diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..fb4390bb88d0d8e2d8555c4adf1ab184a2badd1e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+.gitignore
+.pio
+.vscode
diff --git a/libraries/BlePoll/library.json b/libraries/BlePoll/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..527c6851ecc4967d9c38005a9e6175f17bff48ab
--- /dev/null
+++ b/libraries/BlePoll/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "BlePoll",
+    "version": "0.0.1+20221111"
+  }
\ No newline at end of file
diff --git a/libraries/ComRingBuf/library.json b/libraries/ComRingBuf/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..57784042d87eec4ac24aff6895992bda25c14a39
--- /dev/null
+++ b/libraries/ComRingBuf/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "ComRingBuf",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/EulerAngles/library.json b/libraries/EulerAngles/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..06c82fefc8dfeeed76cf9a118afc7c1884013dbe
--- /dev/null
+++ b/libraries/EulerAngles/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "EulerAngles",
+    "version": "0.0.1+20221111"
+  }
\ No newline at end of file
diff --git a/libraries/GpioCtrl/library.json b/libraries/GpioCtrl/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..175b326846e0682478750036c2d21d8da585a3dd
--- /dev/null
+++ b/libraries/GpioCtrl/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "GpioCtrl",
+    "version": "0.0.1+20221111"
+  }
\ No newline at end of file
diff --git a/libraries/LoopCheck/examplesLinux/testCppArduino.cpp b/libraries/LoopCheck/examplesLinux/testCppArduino.cpp
old mode 100755
new mode 100644
diff --git a/libraries/LoopCheck/examplesWindows/README.md b/libraries/LoopCheck/examplesWindows/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..1951370fc38c00f3b8548bb0d765bdfe39596efe
--- /dev/null
+++ b/libraries/LoopCheck/examplesWindows/README.md
@@ -0,0 +1,2 @@
+Zur Kompatibilität mit platformIO wurde die Datei testLoopCheck umbenannt.
+Wenn die Datei verwendet werden soll, muss die Dateiendung wieder auf .cpp geändert werden.
\ No newline at end of file
diff --git a/libraries/LoopCheck/examplesWindows/testLoopCheck.cpp b/libraries/LoopCheck/examplesWindows/testLoopCheck.txt
old mode 100755
new mode 100644
similarity index 97%
rename from libraries/LoopCheck/examplesWindows/testLoopCheck.cpp
rename to libraries/LoopCheck/examplesWindows/testLoopCheck.txt
index cce3a51c0a5160c513ab8913d8763005647e9cf5..86ed449253fe4eb2f4b5a3207525df16bc057cbd
--- a/libraries/LoopCheck/examplesWindows/testLoopCheck.cpp
+++ b/libraries/LoopCheck/examplesWindows/testLoopCheck.txt
@@ -1,145 +1,145 @@
-//-----------------------------------------------------------------------------
-// Thema:   Social Manufacturing Network / Software Loop Checking and Timing
-// Datei:   testLoopCheck.cpp
-// Editor:  Robert Patzke
-// URI/URL: www.mfp-portal.de
-//-----------------------------------------------------------------------------
-// Lizenz:  CC-BY-SA  (see Wikipedia: Creative Commons)
-//
-// This program was developed and tested with Visual Studio 2010
-// Following configuration has to be done in C/C++ -> Preprocessor Definitions
-//
-// UseGithubPath
-// Visual Studio searches for includes in the environment of the sources.
-// With the switch UseGithubPath the #include directives in source files are
-// relativ to the structure of the tree as it is used on Github repository.
-// So it will work after simple copying the tree from Github.
-//
-// smnDEFBYBUILD
-// With this switch the first part of file environment.h will be used.
-// It is possible to use environment.h for many purposes. 
-// Without defining smnDEFBYBUILD the file has to be edited to fit to your IDE
-// and your microcontroller targets
-//
-// smnWIN32_VS
-// This switch opens a list of definitions in environment.h controlling 
-// conditional compilation in many source files
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-#include <sys/timeb.h>
-
-#include "../LoopCheck.h"
-
-LoopCheck loopCheck;
-
-int main(int argc, char *argv[])
-{
-  time_t          timeSec;
-  struct  tm      *timeStructPtr;
-  struct  timeb   ftimeStruct;
-  lcDateTime      dateTime;
-  int             msecOldPC, msecOldLC, msecOldOP;
-  int             secOldPC, secOldLC, secOldOP;
-  LoopStatistics  statistic;
-
-  // -------------------------------------------------------------------------
-  // setup
-  // -------------------------------------------------------------------------
-  //
-  printf("Testing simulation of Arduino with Windows\n");
-  printf("Check loop behaviour with LoopCheck, demonstrate clocks\n");
-  
-  // Getting PC time with milliseconds resolution
-  //
-  ftime(&ftimeStruct);
-  timeSec = ftimeStruct.time;
-  timeStructPtr = gmtime(&timeSec);
-
-  // Preparing some Variables to calculate and show time difference
-  //
-  msecOldPC = msecOldLC = dateTime.Millisecond = ftimeStruct.millitm;
-  secOldPC = secOldLC = dateTime.Second       = timeStructPtr->tm_sec;
-
-  // Setting the software clock of LoopCheck to PC time
-  //
-  dateTime.Minute       = timeStructPtr->tm_min;
-  dateTime.Hour         = timeStructPtr->tm_hour;
-  dateTime.Day          = timeStructPtr->tm_mday;
-  dateTime.Month        = timeStructPtr->tm_mon + 1;
-  dateTime.Year         = timeStructPtr->tm_year + 1900;
-
-  loopCheck.setDateTime(dateTime);
-
-  // -------------------------------------------------------------------------
-  // loop
-  // -------------------------------------------------------------------------
-  //
-  while(1)
-  {
-    loopCheck.begin();      // this function has to be called first in loop
-    // -----------------------------------------------------------------------
-
-    // Comparing the software clock with the PC clock and showing the difference
-    //
-    if(loopCheck.timerMilli(0,1000,0))
-    {
-      //
-      // This gets true once every second (1000 milliseconds)
-      // The error is that of the PC counter (clock or performance timer)
-
-      // Get the current PC time with milliseconds
-      //
-      ftime(&ftimeStruct);
-      timeSec = ftimeStruct.time;
-      timeStructPtr = gmtime(&timeSec);
-
-      // Get the current time of LoopCheck software clock
-      //
-      loopCheck.getDateTime(&dateTime);
-
-      // Show the PC time and the LoopCheck time and their differences to the last measurement
-      // a second back (do not mind the overflow error with the distance)
-      //
-      printf("PC Time = %02d:%02d:%02d,%03d Diff=%4d     LC Time = %02d:%02d:%02d,%03d Diff=%4d\n",
-        timeStructPtr->tm_hour, timeStructPtr->tm_min, timeStructPtr->tm_sec, ftimeStruct.millitm,
-        ftimeStruct.millitm - msecOldPC + 1000*(timeStructPtr->tm_sec - secOldPC),
-        dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond,
-        dateTime.Millisecond - msecOldLC + 1000*(dateTime.Second - secOldLC));
-      //
-      // You will see, that the timer of LoopCheck is rather accurate. 
-      // The variation of repetition time is less than 1% with some exceptions.
-      // Also the LoopCheck software clock is nearly perfect, because the
-      // underlaying counters are synchronised to the OS clock
-
-      // preperation for the measurement of next cycle
-      //
-      msecOldPC = ftimeStruct.millitm;
-      msecOldLC = dateTime.Millisecond;
-      secOldPC = timeStructPtr->tm_sec;
-      secOldLC = dateTime.Second;
-
-      // to show the difference between microcontrollers and OS based computers
-      // we will look into the statistics of LoopCheck
-      //
-      loopCheck.getStatistics(&statistic);
-
-      // alarmCount is incremented, whenever the time between 2 loops exceeds PeriodMinTime
-      // (adjust PeriodMinTime in LoopCheck.h for your target system)
-      //
-      printf("Loop violations: %4d ", statistic.alarmCount);
-      //
-      // we have also a classification of exceeding the millisecond of loop cycle time
-      // counting the number of exceedings indexed by number of milliseconds.
-      //
-      for(int i = 0; i < LoopScreeningGrades - 1; i++)
-        printf("  %2dms: %4d", i+1 , statistic.rtSreening[i]);
-      printf("  >%2dms: %4d\r\n\n", LoopScreeningGrades - 1, statistic.rtSreening[LoopScreeningGrades - 1]);
-
-    }
-
-    // -----------------------------------------------------------------------
-    loopCheck.end();        // this function has to be called last in the loop
-  }
-}
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Software Loop Checking and Timing
+// Datei:   testLoopCheck.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (see Wikipedia: Creative Commons)
+//
+// This program was developed and tested with Visual Studio 2010
+// Following configuration has to be done in C/C++ -> Preprocessor Definitions
+//
+// UseGithubPath
+// Visual Studio searches for includes in the environment of the sources.
+// With the switch UseGithubPath the #include directives in source files are
+// relativ to the structure of the tree as it is used on Github repository.
+// So it will work after simple copying the tree from Github.
+//
+// smnDEFBYBUILD
+// With this switch the first part of file environment.h will be used.
+// It is possible to use environment.h for many purposes. 
+// Without defining smnDEFBYBUILD the file has to be edited to fit to your IDE
+// and your microcontroller targets
+//
+// smnWIN32_VS
+// This switch opens a list of definitions in environment.h controlling 
+// conditional compilation in many source files
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/timeb.h>
+
+#include "../LoopCheck.h"
+
+LoopCheck loopCheck;
+
+int main(int argc, char *argv[])
+{
+  time_t          timeSec;
+  struct  tm      *timeStructPtr;
+  struct  timeb   ftimeStruct;
+  lcDateTime      dateTime;
+  int             msecOldPC, msecOldLC, msecOldOP;
+  int             secOldPC, secOldLC, secOldOP;
+  LoopStatistics  statistic;
+
+  // -------------------------------------------------------------------------
+  // setup
+  // -------------------------------------------------------------------------
+  //
+  printf("Testing simulation of Arduino with Windows\n");
+  printf("Check loop behaviour with LoopCheck, demonstrate clocks\n");
+  
+  // Getting PC time with milliseconds resolution
+  //
+  ftime(&ftimeStruct);
+  timeSec = ftimeStruct.time;
+  timeStructPtr = gmtime(&timeSec);
+
+  // Preparing some Variables to calculate and show time difference
+  //
+  msecOldPC = msecOldLC = dateTime.Millisecond = ftimeStruct.millitm;
+  secOldPC = secOldLC = dateTime.Second       = timeStructPtr->tm_sec;
+
+  // Setting the software clock of LoopCheck to PC time
+  //
+  dateTime.Minute       = timeStructPtr->tm_min;
+  dateTime.Hour         = timeStructPtr->tm_hour;
+  dateTime.Day          = timeStructPtr->tm_mday;
+  dateTime.Month        = timeStructPtr->tm_mon + 1;
+  dateTime.Year         = timeStructPtr->tm_year + 1900;
+
+  loopCheck.setDateTime(dateTime);
+
+  // -------------------------------------------------------------------------
+  // loop
+  // -------------------------------------------------------------------------
+  //
+  while(1)
+  {
+    loopCheck.begin();      // this function has to be called first in loop
+    // -----------------------------------------------------------------------
+
+    // Comparing the software clock with the PC clock and showing the difference
+    //
+    if(loopCheck.timerMilli(0,1000,0))
+    {
+      //
+      // This gets true once every second (1000 milliseconds)
+      // The error is that of the PC counter (clock or performance timer)
+
+      // Get the current PC time with milliseconds
+      //
+      ftime(&ftimeStruct);
+      timeSec = ftimeStruct.time;
+      timeStructPtr = gmtime(&timeSec);
+
+      // Get the current time of LoopCheck software clock
+      //
+      loopCheck.getDateTime(&dateTime);
+
+      // Show the PC time and the LoopCheck time and their differences to the last measurement
+      // a second back (do not mind the overflow error with the distance)
+      //
+      printf("PC Time = %02d:%02d:%02d,%03d Diff=%4d     LC Time = %02d:%02d:%02d,%03d Diff=%4d\n",
+        timeStructPtr->tm_hour, timeStructPtr->tm_min, timeStructPtr->tm_sec, ftimeStruct.millitm,
+        ftimeStruct.millitm - msecOldPC + 1000*(timeStructPtr->tm_sec - secOldPC),
+        dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond,
+        dateTime.Millisecond - msecOldLC + 1000*(dateTime.Second - secOldLC));
+      //
+      // You will see, that the timer of LoopCheck is rather accurate. 
+      // The variation of repetition time is less than 1% with some exceptions.
+      // Also the LoopCheck software clock is nearly perfect, because the
+      // underlaying counters are synchronised to the OS clock
+
+      // preperation for the measurement of next cycle
+      //
+      msecOldPC = ftimeStruct.millitm;
+      msecOldLC = dateTime.Millisecond;
+      secOldPC = timeStructPtr->tm_sec;
+      secOldLC = dateTime.Second;
+
+      // to show the difference between microcontrollers and OS based computers
+      // we will look into the statistics of LoopCheck
+      //
+      loopCheck.getStatistics(&statistic);
+
+      // alarmCount is incremented, whenever the time between 2 loops exceeds PeriodMinTime
+      // (adjust PeriodMinTime in LoopCheck.h for your target system)
+      //
+      printf("Loop violations: %4d ", statistic.alarmCount);
+      //
+      // we have also a classification of exceeding the millisecond of loop cycle time
+      // counting the number of exceedings indexed by number of milliseconds.
+      //
+      for(int i = 0; i < LoopScreeningGrades - 1; i++)
+        printf("  %2dms: %4d", i+1 , statistic.rtSreening[i]);
+      printf("  >%2dms: %4d\r\n\n", LoopScreeningGrades - 1, statistic.rtSreening[LoopScreeningGrades - 1]);
+
+    }
+
+    // -----------------------------------------------------------------------
+    loopCheck.end();        // this function has to be called last in the loop
+  }
+}
diff --git a/libraries/LoopCheck/library.json b/libraries/LoopCheck/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..56fba8defed884a44260e6f801b9c333fb39beb4
--- /dev/null
+++ b/libraries/LoopCheck/library.json
@@ -0,0 +1,32 @@
+{
+  "name": "LoopCheck",
+  "version": "0.0.1+20221111",
+  "examples": [
+    {
+        "name": "lcBlink",
+        "base": "examples",
+        "files": ["lcBlink.ino"]
+    },
+    {
+        "name": "lcStatistics",
+        "base": "examples",
+        "files": ["lcStatistics.ino"]
+    },
+    {
+        "name": "testCppArduino",
+        "base": "examplesLinux",
+        "files": ["testArduino.cpp"]
+    },
+    {
+        "name": "testLoopCheck",
+        "base": "examplesWindows",
+        "files": ["testLoopCheck.cpp"]
+    }
+],
+"built": {
+    "srcFilter" : ["-<./examples>","-<./examplesLinux>","-<./examplesWindows>"]
+},
+"export":{
+    "exclude" : ["./examples", "./examplesLinux","./examplesWindows"]
+} 
+}
\ No newline at end of file
diff --git a/libraries/MidiNotes/library.json b/libraries/MidiNotes/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..42acf47ed2c1b38686923000d11bd00cb9b2c212
--- /dev/null
+++ b/libraries/MidiNotes/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "MidiNotes",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/Monitor/library.json b/libraries/Monitor/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..0509f4e9768d95b29910c8ca3d55c095650902fc
--- /dev/null
+++ b/libraries/Monitor/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "Monitor",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/ProcMeas/ProcMeas.h b/libraries/ProcMeas/ProcMeas.h
index e0b14eb39e112aee919620b74143b2df9adad6f8..7dd48d389a7708bdecc34a50c04e1e4c73801de0 100644
--- a/libraries/ProcMeas/ProcMeas.h
+++ b/libraries/ProcMeas/ProcMeas.h
@@ -17,6 +17,7 @@
 #include "EulerAngles.h"
 
 //#define ProcMeasDebug
+#define RAD_TO_DEG 57.2957795
 
 typedef enum _PmState
 {
diff --git a/libraries/ProcMeas/library.json b/libraries/ProcMeas/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..b488de4d38daf60b767c23192ce4ccd3be8450c6
--- /dev/null
+++ b/libraries/ProcMeas/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "ProcMeas",
+    "version": "0.0.1+20221111"
+  }
\ No newline at end of file
diff --git a/libraries/SensorLSM9DS1/library.json b/libraries/SensorLSM9DS1/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..4e9466a6450bbe943a0e52aa20b41f7de08a23f9
--- /dev/null
+++ b/libraries/SensorLSM9DS1/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "SensorLSM9DS1",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/SoaapComDue/library.json b/libraries/SoaapComDue/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..d2f55321143f4a081f460f39124d5d13150a1d44
--- /dev/null
+++ b/libraries/SoaapComDue/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "SoaapComDue",
+    "version": "0.0.1+20221111"
+  }
\ No newline at end of file
diff --git a/libraries/SoaapMsg/library.json b/libraries/SoaapMsg/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..7b6bd50a4921c2a714accaec5852e2d737a2b501
--- /dev/null
+++ b/libraries/SoaapMsg/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "SoaapMsg",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/StateMachine/library.json b/libraries/StateMachine/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..2a474a268173ce0290524721d59648c7aab7bf4f
--- /dev/null
+++ b/libraries/StateMachine/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "StateMachine",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/environment/SoaapBleMaster.h b/libraries/environment/SoaapBleMaster.h
new file mode 100644
index 0000000000000000000000000000000000000000..98bd22eb99c0839cf9f5ad554dd116b21c0afd81
--- /dev/null
+++ b/libraries/environment/SoaapBleMaster.h
@@ -0,0 +1,63 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleMaster.h
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                        P o l l i n g - M a s t e r
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. November 2021
+// Letzte Bearbeitung: 15. März 2022
+//
+
+#ifndef SoaapBleMaster_h
+#define SoaapBleMaster_h
+
+// Vordefinitionen, Festlegungen zur Kompilierung
+//
+#define DebugTerminal
+// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden
+// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist
+
+//#define TEST001
+// Ausgaben an serielle schnittstelle zur Prüfung der ap-Zustandsmaschine
+
+#include  "LoopCheck.h"
+#include  "StateMachine.h"
+#include  "nRF52840Radio.h"
+#include  "BlePoll.h"
+#include  "ComRingBuf.h"
+#include  "nRF52840Ser.h"
+#include  "SoaapMsg.h"
+#include  "Monitor.h"
+
+// ----------------------------------------------------------------------------
+// Vorwärtsreferenzen
+// ----------------------------------------------------------------------------
+//
+void ctrlIdle();
+void ctrlInit();
+void sendCtrl();
+void checkCtrl();
+
+void apInit();
+void apWaitDE();
+void apWaitMeas();
+void apProcMeas();
+
+
+#ifdef DebugTerminal
+// ----------------------
+void smInit() ;
+void smCheckJobs() ;
+void smDebDword() ;
+void smCtrlPolling() ;
+void smWaitPolling() ;
+void smReadPollValues() ;
+void smCheckSer();
+// ----------------------
+#endif
+
+#endif /* SoaapBleMaster_h */
diff --git a/libraries/environment/SoaapBleSlave.h b/libraries/environment/SoaapBleSlave.h
new file mode 100644
index 0000000000000000000000000000000000000000..f3ae7f7500126e35f19524b4188a3044d43dfaf4
--- /dev/null
+++ b/libraries/environment/SoaapBleSlave.h
@@ -0,0 +1,43 @@
+#ifndef SoaapBleSlave_h
+#define SoaapBleSlave_h
+
+#include  "LoopCheck.h"
+#include  "StateMachine.h"
+#include  "nRF52840Radio.h"
+#include  "BlePoll.h"
+#include  "ComRingBuf.h"
+#include  "nRF52840Ser.h"
+#include  "SoaapMsg.h"
+#include  "Monitor.h"
+#include "nRF52840Twi.h"
+#include "SensorLSM9DS1.h"
+#include "nRF52840Gpio.h"
+
+//#define SlaveACM1
+bool sendData(PlpType plpType, byte *dest);
+bool getValues(PlpType plpType, byte *dest);
+void smInit();
+void smCheckJobs();
+void smCheckSens();
+
+void smDebDword();
+void smCtrlPolling();
+void smWaitPolling();
+void smSensReset1();
+void smSensReset2();
+
+void smSensGetValues1();
+void smSensGetValues2();
+void smSensGetValues3();
+void smSensGetValues4();
+void smSensGetValues5();
+void smSensGetValues6();
+void smSensGetValues7();
+
+void smSensGetSoaapValues();
+void smSensDebugValues();
+
+void smSensGetErrors();
+void smSensGetTimeOuts();
+void smSensGetRunCounts();
+#endif
\ No newline at end of file
diff --git a/libraries/environment/library.json b/libraries/environment/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..13cd151661d616282166233e4d7f94c730d33ffb
--- /dev/null
+++ b/libraries/environment/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "environment",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/nRF52840Adc/library.json b/libraries/nRF52840Adc/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..34aead1af121d937c5c4f658936056488164ba75
--- /dev/null
+++ b/libraries/nRF52840Adc/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "nRF52840Adc",
+    "version": "0.0.1+20221111"
+  }
\ No newline at end of file
diff --git a/libraries/nRF52840Gpio/library.json b/libraries/nRF52840Gpio/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..1a10197e5509b12cdfbaa8f2525d2e6815f752b5
--- /dev/null
+++ b/libraries/nRF52840Gpio/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Gpio",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/nRF52840Radio/library.json b/libraries/nRF52840Radio/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..8568e9fd5255175d8c97ec82276e1907e92c6510
--- /dev/null
+++ b/libraries/nRF52840Radio/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Radio",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/nRF52840Ser/library.json b/libraries/nRF52840Ser/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..bbed5cb3f23e8e3959de73f22e3a7a53a83ae1f5
--- /dev/null
+++ b/libraries/nRF52840Ser/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Ser",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/libraries/nRF52840Twi/library.json b/libraries/nRF52840Twi/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..80e483a17ee2b4a59e61f9e1fedc40132554e2e1
--- /dev/null
+++ b/libraries/nRF52840Twi/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Twi",
+  "version": "0.0.1+20221111"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/include/README b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/include/README
new file mode 100644
index 0000000000000000000000000000000000000000..194dcd43252dcbeb2044ee38510415041a0e7b47
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/include/README
@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
diff --git a/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/lib/README b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/lib/README
new file mode 100644
index 0000000000000000000000000000000000000000..6debab1e8b4c3faa0d06f4ff44bce343ce2cdcbf
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/lib/README
@@ -0,0 +1,46 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link into executable file.
+
+The source code of each library should be placed in a an own separate directory
+("lib/your_library_name/[here are source files]").
+
+For example, see a structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+|  |
+|  |--Bar
+|  |  |--docs
+|  |  |--examples
+|  |  |--src
+|  |     |- Bar.c
+|  |     |- Bar.h
+|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+|  |
+|  |--Foo
+|  |  |- Foo.c
+|  |  |- Foo.h
+|  |
+|  |- README --> THIS FILE
+|
+|- platformio.ini
+|--src
+   |- main.c
+
+and a contents of `src/main.c`:
+```
+#include <Foo.h>
+#include <Bar.h>
+
+int main (void)
+{
+  ...
+}
+
+```
+
+PlatformIO Library Dependency Finder will find automatically dependent
+libraries scanning project source files.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html
diff --git a/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/platformio.ini b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/platformio.ini
new file mode 100644
index 0000000000000000000000000000000000000000..8aee3f8409f7d237a786c4c5e2ee2a67547dd416
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/platformio.ini
@@ -0,0 +1,38 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG -DDegugTerminal
+;Anstelle der relativen Pfade können auch lokale Syslinks verwendet werden(siehe unten).
+;Diese aber bitte NICHT committen!
+lib_deps = 
+	..\..\..\..\libraries\BlePoll
+	..\..\..\..\libraries\environment
+	..\..\..\..\libraries\ComRingBuf
+	..\..\..\..\libraries\LoopCheck
+	..\..\..\..\libraries\MidiNotes
+	..\..\..\..\libraries\Monitor
+	..\..\..\..\libraries\nRF52840Gpio
+	..\..\..\..\libraries\nRF52840Radio
+	..\..\..\..\libraries\nRF52840Ser
+	..\..\..\..\libraries\nRF52840Twi
+	..\..\..\..\libraries\SensorLSM9DS1
+	..\..\..\..\libraries\SoaapMsg
+	..\..\..\..\libraries\StateMachine
+	..\..\..\..\libraries\nRF52840Adc
+	..\..\..\..\libraries\ProcMeas
+	..\..\..\..\libraries\EulerAngles
+    ..\..\..\..\libraries\GpioCtrl
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/src/SoaapBleMidiMaster.h b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/src/SoaapBleMidiMaster.h
new file mode 100644
index 0000000000000000000000000000000000000000..9bb0445f1db6ca2ab7082d767361e1a084332643
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/src/SoaapBleMidiMaster.h
@@ -0,0 +1,127 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleMidiMaster.h
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                        P o l l i n g - M a s t e r
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   26. April 2022
+// Letzte Bearbeitung: 15. März 2022
+//
+
+#ifndef SoaapBleMidiMaster_h
+#define SoaapBleMidiMaster_h
+
+// Vordefinitionen, Festlegungen zur Kompilierung
+//
+
+//#define DebugTerminal
+// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden
+// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist
+// Diese Definition wird in der Projektumgebung des Entwicklungssystems gesetzt
+// (z.B. Arduino Compile Options bei Eclipse/Sloeber)
+
+//#define TEST001
+// Ausgaben an serielle schnittstelle zur Prüfung der ap-Zustandsmaschine
+#define testOut(x)    smnSerial.print(x)
+
+
+#include  "LoopCheck.h"
+#include  "StateMachine.h"
+#include  "nRF52840Radio.h"
+#include  "MidiNotes.h"
+#include  "BlePoll.h"
+#include  "ComRingBuf.h"
+#include  "nRF52840Ser.h"
+#include  "Monitor.h"
+
+// ----------------------------------------------------------------------------
+// Datentypen
+// ----------------------------------------------------------------------------
+//
+typedef struct _Value2Midi
+{
+  short borderLowAz;
+  short borderHighAz;
+  short borderLowAy;
+  short borderHighAy;
+  short borderLowAx;
+  short borderHighAx;
+
+  byte  lowNote;
+  byte  highNote;
+
+} Value2Midi, *Value2MidiPtr;
+
+enum Meas2Midi
+{
+  NoteType,
+  NoteVal,
+  NoteVel
+};
+
+typedef struct _MidiBorders
+{
+  byte  low;
+  byte  high;
+} MidiBorders, *MiniBordersPtr;
+
+typedef struct _Posture2Midi
+{
+  float       offsetRoll;
+  float       borderLowRoll;
+  float       borderHighRoll;
+  float       koeffRoll;
+  float       offsetPitch;
+  float       borderLowPitch;
+  float       borderHighPitch;
+  float       koeffPitch;
+  float       offsetYaw;
+  float       borderLowYaw;
+  float       borderHighYaw;
+  float       koeffYaw;
+  Meas2Midi   aimRoll;
+  Meas2Midi   aimPitch;
+  Meas2Midi   aimYaw;
+  byte        signAreaValue[4];
+  byte        signAreaCtrl[4];
+  MidiBorders midiBords[3];
+} Posture2Midi, *Posture2MidiPtr;
+
+// ----------------------------------------------------------------------------
+// Vorwärtsreferenzen
+// ----------------------------------------------------------------------------
+//
+void apInit();
+void apWaitDE();
+void apWaitMeas();
+void apProcMeas();
+void apCheckValues();
+void apCalcResult();
+void apSetResult();
+void apTestController();
+
+void setParM1();
+void setParM2();
+void setParP1();
+void setParP2();
+
+
+#ifdef DebugTerminal
+// ----------------------
+void smInit() ;
+void smCheckJobs() ;
+void smDebDword() ;
+void smCtrlPolling() ;
+void smWaitPolling() ;
+void smReadPollValues() ;
+void smCheckApp();
+void smMode4Slave();
+void smMode4SlaveIn();
+// ----------------------
+#endif
+
+#endif SoaapBleMidiMaster_h
diff --git a/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/src/main.cpp b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b2577ce24c6307e36242ce5ce34e0b78f618d7e9
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/src/main.cpp
@@ -0,0 +1,1184 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleMidiMaster.ino
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                        P o l l i n g - M a s t e r
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   26. April 2022
+// Letzte Bearbeitung:
+//
+
+#include  "Arduino.h"
+#include  "SoaapBleMidiMaster.h"
+
+// ----------------------------------------------------------------------------
+LoopCheck     lc;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse LoopCheck
+// Darüber wird das Zeitverhalten gesteuert (Software-Timer) und geprüft
+
+// ----------------------------------------------------------------------------
+nRF52840Radio bleCom;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse nRF52840Radio
+// Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und
+// Empfangen von BLE-Beacons angesprochen.
+
+
+#define bleCycleTime 250
+// ----------------------------------------------------------------------------
+BlePoll       blePoll((IntrfRadio *) &bleCom, micros);
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse BlePoll
+// Darüber werden das Polling des Masters als auch die Antworten der Slaves
+// gesteuert. Es können Geräte entwickelt werden, die nur Master oder Slave
+// sind und solche mit Doppelfunktion, wenn kein expliziter Master
+// eingesetzt und das Netzwerk über Spontan-Master quasi dezentral
+// betrieben werden soll.
+// ----- Parameter ------------------------------------------------------------
+// <&bleCom>    Die Klasse (vom angenommenen Typ IntrfRadio), die die Daten-
+//              übertragung abwickelt. Hier wird eine Instanz von nRF52840Radio
+//              angebunden. Für andere Hardware kann eine entsprechende Klasse
+//              verwendet werden, die von IntrfRadio abgeleitet wurde.
+// <micros>     Eine Funktion, die die verstrichene Zeit in Mikrosekunden gibt.
+//              Damit werden Zeiten (z.B. Time-Out) berechnet.
+//              Wird hier der Wert NULL übergeben, dann werden die Zeiten aus
+//              dem Aufrufzyklus (bleCycleTime) in Mikrosekunden berechnet,
+//              was hier einer Auflösung von 250 Mikrosekunden entspricht.
+
+#define NrOfSlavesToPoll  5
+// Die Anzahl der Slaves, die der Master aufrufen soll (Polling).
+// Es wird grundsätzlich mit der Adresse 1 begonnen und nach dem Aufruf die
+// Adresse inkrementiert, also immer die Slaves Adr = 1 bis
+// Adr = NrOfSlavesToPoll+1 aufgerufen.
+// ACHTUNG!
+// Diese Zahl muss kleiner/gleich der in BlePoll.h definierten maximalen
+// Anzahl der Slaves (MAXSLAVE) sein, weil die Ressourcen darüber statisch
+// festgelegt werden.
+
+Value2Midi    val2midArr[NrOfSlavesToPoll + 1];
+Posture2Midi  post2midArr[NrOfSlavesToPoll + 1];
+// Jeder Slave bekommt spezifische Value->Midi-Parameter.
+// Index 0 steht für eventuelle Parameter des Masters
+
+SerParams     ttyParams;
+// ----------------------------------------------------------------------------
+nRF52840Ser   tty;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse nRF52840Ser (UART)
+// Darüber werden die seriellen Schnittstellen (UARTE0 und UARTE1) des
+// nRF52840 bedient.
+// Die Parameter werden in einer Struktur <SerParams> über die Funktion
+// <begin(...)> gesetzt.
+
+#define       sndBufSize  256
+byte          sndBuffer[sndBufSize];
+// ----------------------------------------------------------------------------
+ComRingBuf    crb;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse <ComRingBuf>
+// Damit wird ein Ringpuffer aufgebaut, der eine serielle Schnittstelle bedient.
+// Der Speicher muss extra eingerichtet und mit der Funktion
+//  <setWriteBuffer(sndBufSize, sndBuffer)> übergeben werden.
+// Die Klasse für die serielle Schnittstelle muss von <IntrfSerial> abgeleitet
+// sein, die Instanz wird mit der Funktion <begin(...)> übergeben.
+
+#define MidiCycle     1000
+MidiNotes  midi1,midi2;
+
+#define appCycleTime 1000
+StateMachine  ap(apInit, NULL, appCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für die
+// Anwendung (App) von SOAAP eingesetzt wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Mikrosekunden
+
+
+#ifdef DebugTerminal
+// ----------------------------------------------------------------------------
+// Zum Debuggen und weitere Analysen der Programmumgebung und Funktionstests
+// Es ist ein (richtiges) Terminal erforderlich, mit dem einzelnen Zeichen
+// direkt abgeschickt und die eintreffenden direkt angezeigt werden.
+// ----------------------------------------------------------------------------
+#define smCycleTime 5
+StateMachine  sm(smInit, NULL, smCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für allgemeine
+// Steuerungen, Überwachungen und zum Debugging verwendet wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Millisekunden
+
+char *infoThis =
+{
+"SOAAP BLE Master Midi Version 22.09.24-1\r\n"
+"c0  Abschalten der periodischen Meldung\r\n"
+"c1  Auslesen BlePoll-Debug-Register\r\n"
+"c2  Steuern/Analysieren des Polling\r\n"
+"c3  Werte auslesen\r\n"
+"c4  Anwendung analysieren\r\n"
+"c5  Meldung an Slave senden\r\n"
+};
+
+
+Monitor       mon(modeEcho | modeNl,0,&lc);
+// Eine statische Instanz (mit Konstruktordaten) der Klasse Monitor
+// Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert
+// Unter Linux werden hier GtkTerm (siehe Internet) und
+// ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt.
+// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeigent,
+// weil damit keine direkte Kommunikation (getipptes Zeichen sofort gesendet)
+// möglich ist.
+// ----- Parameter ------------------------------------------------------------
+// <mode Echo>  Alle eintreffenden Zeichen werden sofort zurückgesendet
+// <mode NL>    Vor der Ausgabe des Prompt (M>) erfolgt CR/LF
+// <0>          Für Speicherzugriffe wird von 32 Bit ARM ausgegangen
+// <&lc>        Für Zeitüberwachungen und entsprechende statisctische Daten
+//              greift die Monitor-Klasse auf die LoopCheck-Klasse zu
+// ----------------------------------------------------------------------------
+#endif
+
+
+BlePoll::AppType  appType;
+
+// ============================================================================
+void setup()
+// ============================================================================
+{
+  bleCom.begin();           // Initialisierung der Datenübertragung
+  //bleCom.setPower(0x08);     // Maximale Sendeleistung bei nRF52840
+  // TEST
+  bleCom.setPower(0x0FC);   // Reduzierte Sendeleistung beim Schreibtisch-Test
+
+  //appType = BlePoll::atDevSOAAP;
+  appType = BlePoll::atSOAAP2;
+
+  blePoll.begin(BlePoll::ctMASTER, NrOfSlavesToPoll, appType, 10000);
+  // Initialisierung des Polling mit folgenden Parametern:
+  // <BlePoll::ctMASTER>    Es wird ein Master eingerichtet
+  // <NrOfSlavesToPoll>     Anzahl gepollter Slaves (s.o.)
+  // <BlePoll::atSOAAP>     Spezielle Anwendung SOAAP
+  // <10000>                INT-Watchdog-Timeout beim Lesen in Mikrosekunden
+
+  blePoll.setEmptyPollParams(2000, 500, 2000);
+  // Setzen der Parameter für das leere Polling zur Feststellung der
+  // vorhandenen Slaves und Aufbau einer Poll-Liste für den Datenaustausch
+  // ----- Parameter ----------------------------------------------------------
+  // <2000>   Anzahl der Poll-Durchläufe, solange kein Slave gefunden wird
+  // <500>    Anzahl weiterer Durchläufe, nachdem wenigstens ein Slave gefunden ist
+  // <2000>   Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden
+
+  for(int i = 1; i <= NrOfSlavesToPoll; i++)
+    blePoll.setDataPollParams(i, 1, 10, 1000);
+  // Setzen der Parameter beim Datenpolling, für Slaves individuell
+  // ----- Parameter ----------------------------------------------------------
+  // <i>      Adresse des Slave (1-..)
+  // <1>      Priorität beim Aufruf, 0 = immer bis max 65535 = sehr selten
+  // <10>     minimale Priorität bei automatischer Prioritätsreduzierung
+  //          im Fall von Störungen (Time-Out)
+  // <1000>   Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden
+
+#ifdef DebugTerminal
+  blePoll.stopEP();       // Das Polling muss extra gestartet werden
+  mon.setInfo(infoThis);  // Info-Meldung für Monitor
+#endif
+
+  // Initialisierung von serieller Schnittstelle und Ringpuffer
+  // --------------------------------------------------------------------------
+  ttyParams.inst    = 0;    // Instanzindex der Schnittstelle (0,1)
+  ttyParams.rxdPort = 1;    // Nummer des IO-Port mit RxD-Pin
+  ttyParams.rxdPin  = 10;   // Nummer des RxD-Pin am Port
+  ttyParams.txdPort = 1;    // Nummer des IO-Port mit TxD-Pin
+  ttyParams.txdPin  = 3;    // Nummer des TxD-Pin am Port
+  ttyParams.speed   = Baud31250;    // Enumerator für Bitrate
+  ttyParams.type    = stCur;        // Stromschleife
+
+  tty.begin(&ttyParams, (IntrfBuf *) &crb);
+  // Übergeben von Parametern und Referenz auf Ringpufferverwaltung
+  // für die Übergabe empfangener Zeichen
+
+  tty.startSend();    // Sendebetrieb aktivieren
+
+  crb.setWriteBuffer(sndBufSize, sndBuffer);
+  // Speicher an Ringpufferverwaltung übergeben
+
+  crb.begin((IntrfSerial *) &tty);
+  // Referenz auf Schnittstelle an Ringpufferverwaltung
+  // für die Übergabe zu sendender Zeichen
+
+  setParM1();
+  setParP1();
+  midi1.begin(120, nd32, MidiCycle, (IntrfBuf *) &crb);
+  midi1.setChannel(1);
+
+  setParM2();
+  setParP2();
+  midi2.begin(120, nd32, MidiCycle, (IntrfBuf *) &crb);
+  midi2.setChannel(2);
+  //midi2.stop();
+}
+
+// ============================================================================
+void loop()
+// ============================================================================
+{
+  lc.begin();     // Muss am Anfang von LOOP aufgerufen werden
+  // --------------------------------------------------------------------------
+
+#ifdef DebugTerminal
+  mon.run();      // Der Monitor bekommt bei jedem Durchlauf die CPU
+#endif
+
+  // Alle 250 Mikrosekunden erfolgt der Aufruf des Ble-Polling
+  //
+  if(lc.timerMicro(lcTimer0, bleCycleTime, 0))
+    blePoll.run();
+  // ----- Parameter der Software-Timer ---------------------------------------
+  // <lcTimer0>   Id/Nummer des Timer, zur Zeit werden bis 10 Timer unterstützt
+  //              lcTimer0 bis lcTimer9 (einstellbar in LoopCheck.h)
+  // <bleCycleTime>   Ablaufzeit in Einheit des Timer-Typ (Micro/Milli)
+  //                  hier in Mikrosekunden (timerMicro)
+  // <0>          Anzahl der Wiederholungen, 0 = unbegrenzt
+
+  // Alle <appCycleTime> Mikrosekunden erfolgt der Aufruf der Anwendung
+  //
+  if(lc.timerMicro(lcTimer1, appCycleTime, 0, 10000))
+    ap.run();
+
+  // Alle <MidiCycle> Mikrosekunden erfolgt der Aufruf des Midi-Controller
+  //
+  if(lc.timerMicro(lcTimer2, MidiCycle, 0, 1000))
+  {
+    midi1.run();
+    midi2.run();
+  }
+
+#ifdef DebugTerminal
+  // Jede Sekunde erfolgt die Ausgabe einer Versionsmeldung
+  // das kann über c0 am Terminal abgeschaltet werden
+  //
+  if(lc.timerMilli(lcTimer3, 1000, 0))
+  {
+    if(!mon.cFlag[0])
+      mon.printcr((char *)"%@TestBleMidiMaster, Version 20221018");
+  }
+  // Die Zeichen %@ am Anfang steuern die Ausgabe bei AndroidMonTerm in ein
+  // Textfeld (Label) statt auf das Terminal-Display
+
+  // Jede Millisekunde erfolgt der Aufruf der Zustandsmaschine
+  //
+  if(lc.timerMilli(lcTimer4, smCycleTime, 0))
+  {
+    sm.run();
+  }
+#endif
+
+  // --------------------------------------------------------------------------
+  lc.end();       // Muss vor dem Ende von LOOP aufgerufen werden
+}
+
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e   S O A A P - A n w e n d u n g  (ap)
+// ****************************************************************************
+//
+byte  apTmpByteArray[256];              // Zwischenspeicher für Zeichenfolgen
+int   apNrOfMeasBytes;                  // Anzahl der empfangenen Messwertbytes
+byte  apMeasByteArray[32];              // Zwischenspeicher für Messwerte
+byte  apSlaveList[NrOfSlavesToPoll];    // Merker für gepollte Slaves
+int   apNrOfSlaves;                     // Aktuelle Anzahl von Slaves
+int   curListIdx;                       // Aktueller Index für Slaveliste
+int   area;                             // Area des aktuellen Slave
+int   sMsgLen;                          // Länge einer SOAAP-Meldung
+int   slNr;                             // Slave-Nummer (Adresse)
+int   txNr;                             // Anzahl versendeter Zeichen
+
+PlpType   pAppId;                       // Anwendungs-Id aus Polling-Sicht
+
+int   lastNoteIdxM1 = 0;
+int   lastNoteIdxM2 = 0;
+
+#ifdef TEST001
+char testMsgBuf[256];
+#endif
+// ----------------------------------------------------------------------------
+// Initialisierungen
+//
+dword apInitCnt;
+void apInit()
+{
+  apInitCnt++;
+
+  midi1.setNoteType(MidiNotes::nti8);
+  lastNoteIdxM1 = midi1.addChordNote(MidiNotes::nti8, SchlossC, 10);
+  midi1.setOpMode(momSequence);
+  midi2.setNoteType(MidiNotes::nti8);
+  lastNoteIdxM2 = midi2.addChordNote(MidiNotes::nti8, Kammerton, 10);
+  midi2.setOpMode(momSequence);
+  ap.enter(apWaitDE);
+}
+
+// ----------------------------------------------------------------------------
+// Warten, bis Datenaustausch Master/Slave erfolgt
+//
+dword apWaitDECnt;
+void apWaitDE()
+{
+  apWaitDECnt++;
+
+  if(!blePoll.DataExchange)
+    return;   // Verbleiben in diesem Zustand bis Leerpolling beendet
+
+  apNrOfSlaves = blePoll.getSlaveList(apSlaveList, NrOfSlavesToPoll);
+  // Ermitteln der angeschlossenen Slaves
+
+  ap.enter(apWaitMeas);
+}
+
+// ----------------------------------------------------------------------------
+// Warten auf neuen Messwert von einem Slave
+//
+dword apWaitMeasCnt;
+void apWaitMeas()
+{
+  apWaitMeasCnt++;
+
+  // Ermitteln, ob einer der Slaves einen Messwert hat
+  //
+  for(curListIdx = 0; curListIdx < apNrOfSlaves; curListIdx++)
+  {
+    slNr = apSlaveList[curListIdx];
+    if(blePoll.measAvail(slNr)) break;
+  }
+  if(curListIdx == apNrOfSlaves) return;
+  // Wenn kein Slave neue Messwerte hat,
+  // dann im nächsten Zustandstakt Abfrage wiederholen
+
+  // Slave (curListIdx) hat Messwerte übermittelt
+  // diese werden mit dem nächsten Takt verarbeitet
+  ap.enter(apProcMeas);
+}
+
+// ----------------------------------------------------------------------------
+// Verarbeiten der Daten vom Slave
+//
+dword apProcMeasCnt;
+void apProcMeas()
+{
+  apProcMeasCnt++;
+
+  // Parameter und Daten für die SOAAP-Ausgabe holen
+  //
+  slNr = apSlaveList[curListIdx];
+  area = blePoll.getArea(slNr);
+  pAppId = blePoll.getAppId(slNr);
+  apNrOfMeasBytes = blePoll.getMeas(slNr, apMeasByteArray);
+
+  // Spezifisch je Slave auswerten
+  //
+  if(slNr == 1 || slNr == 2)
+  {
+    ap.enter(apCheckValues);
+    return;
+  }
+
+  // Auf nächsten Messwert von einem Slave warten
+  //
+  ap.enter(apWaitMeas);
+}
+
+// ----------------------------------------------------------------------------
+// Daten überprüfen (auswerten)
+//
+short accXold, accYold, accZold;
+float rollOld, pitchOld, yawOld;
+dword apCheckValuesCnt;
+void apCheckValues()
+{
+  apCheckValuesCnt++;
+
+  switch (appType)
+  {
+   case BlePoll::atSOAAP1:
+     //bool newData = false;
+
+     accXold = * (short *) &apMeasByteArray[6];
+     accYold = * (short *) &apMeasByteArray[8];
+     accZold = * (short *) &apMeasByteArray[10];
+
+     break;
+
+   case BlePoll::atSOAAP2:
+     rollOld  = * (float *) &apMeasByteArray[0];
+     pitchOld = * (float *) &apMeasByteArray[4];
+     yawOld   = * (float *) &apMeasByteArray[8];
+
+     break;
+  }
+
+  ap.enter(apCalcResult);
+}
+
+// ----------------------------------------------------------------------------
+// Daten auf Midi-Noten abbilden
+//
+//short borderLowAz = 100;
+//short borderHighAz = 8000;
+//short borderLowAy = 100;
+//short borderHighAy = 8300;
+//short borderLowAx = 100;
+//short borderHighAx = 4000;
+
+//byte  lowNote = 23;
+//byte  highNote = 72;
+//byte highNote = 96;
+
+void setParM1()
+{
+  val2midArr[1].borderLowAz = 100;
+  val2midArr[1].borderHighAz = 8000;
+  val2midArr[1].borderLowAy = 100;
+  val2midArr[1].borderHighAy = 8300;
+  val2midArr[1].borderLowAx = 100;
+  val2midArr[1].borderHighAx = 4000;
+  val2midArr[1].lowNote = 23;
+  val2midArr[1].highNote = 96;
+}
+
+void setParM2()
+{
+  val2midArr[2].borderLowAz = 100;
+  val2midArr[2].borderHighAz = 8000;
+  val2midArr[2].borderLowAy = 100;
+  val2midArr[2].borderHighAy = 8300;
+  val2midArr[2].borderLowAx = 100;
+  val2midArr[2].borderHighAx = 4000;
+  val2midArr[2].lowNote = 23;
+  val2midArr[2].highNote = 96;
+}
+
+void setParP1()
+{
+  Posture2MidiPtr pmp = &post2midArr[1];
+
+  pmp->offsetRoll               = 90;
+  pmp->borderLowRoll            = 45;
+  pmp->borderHighRoll           = 170;
+  pmp->aimRoll                  = NoteType;
+
+  pmp->offsetPitch              = 90;
+  pmp->borderLowPitch           = 45;
+  pmp->borderHighPitch          = 170;
+  pmp->aimPitch                 = NoteVal;
+
+  pmp->midiBords[NoteVal].low   = 23;
+  pmp->midiBords[NoteVal].high  = 96;
+  pmp->midiBords[NoteType].low  = 2;
+  pmp->midiBords[NoteType].high = 12;
+
+  pmp->koeffRoll =
+      (pmp->midiBords[pmp->aimRoll].high - pmp->midiBords[pmp->aimRoll].low) /
+      (pmp->borderHighRoll - pmp->borderLowRoll);
+
+  pmp->koeffPitch =
+      (pmp->midiBords[pmp->aimPitch].high - pmp->midiBords[pmp->aimPitch].low) /
+      (pmp->borderHighPitch - pmp->borderLowPitch);
+}
+
+void setParP2()
+{
+  Posture2MidiPtr pmp = &post2midArr[2];
+
+  pmp->offsetRoll               = 90;
+  pmp->borderLowRoll            = 45;
+  pmp->borderHighRoll           = 170;
+  pmp->aimRoll                  = NoteType;
+
+  pmp->offsetPitch              = 90;
+  pmp->borderLowPitch           = 45;
+  pmp->borderHighPitch          = 170;
+  pmp->aimPitch                 = NoteVal;
+
+  pmp->midiBords[NoteVal].low   = 23;
+  pmp->midiBords[NoteVal].high  = 96;
+  pmp->midiBords[NoteType].low  = 2;
+  pmp->midiBords[NoteType].high = 12;
+
+  pmp->koeffRoll =
+      (pmp->midiBords[pmp->aimRoll].high - pmp->midiBords[pmp->aimRoll].low) /
+      (pmp->borderHighRoll - pmp->borderLowRoll);
+
+  pmp->koeffPitch =
+      (pmp->midiBords[pmp->aimPitch].high - pmp->midiBords[pmp->aimPitch].low) /
+      (pmp->borderHighPitch - pmp->borderLowPitch);
+}
+
+
+byte  resultAz;
+byte  resultAy;
+byte  resultAx;
+
+byte  resultNote[3];
+
+dword apCalcResultCnt;
+void apCalcResult()
+{
+  short     testY;
+  int       result;
+  float     rollVal, pitchVal, yawVal;
+  Meas2Midi meas2midi;
+
+  apCalcResultCnt++;
+
+  switch (appType)
+  {
+    case BlePoll::atSOAAP1:
+      if((accZold < val2midArr[slNr].borderLowAz) && (accXold < val2midArr[slNr].borderLowAx))
+      {
+        ap.enter(apWaitMeas);
+        return;
+      }
+
+      testY = accZold + accYold / 4;
+      result = val2midArr[slNr].lowNote
+          + (val2midArr[slNr].highNote * testY) / val2midArr[slNr].borderHighAz;
+      if(result > val2midArr[slNr].highNote)
+        resultAz = val2midArr[slNr].highNote;
+      else if (result < val2midArr[slNr].lowNote)
+        resultAz = val2midArr[slNr].lowNote;
+      else
+        resultAz = result;
+
+      testY = accXold + accYold / 4;
+      result = (MidiNotes::nti32 * testY) / val2midArr[slNr].borderHighAz;
+      if(result < MidiNotes::nti2) result = MidiNotes::nti2;
+      if(result > MidiNotes::nti32) result = MidiNotes::nti32;
+      resultAx = result;
+      break;
+
+    case BlePoll::atSOAAP2:
+      rollVal = rollOld + post2midArr[slNr].offsetRoll; // Rollwinkel in positiven Bereich verschieben
+      if(rollVal < post2midArr[slNr].borderLowRoll)
+      {
+        rollVal = post2midArr[slNr].borderLowRoll;      // Inhalt ggf. auf Minimalwert begrenzen
+      }
+      else if(rollVal > post2midArr[slNr].borderHighRoll)
+      {
+        rollVal = post2midArr[slNr].borderHighRoll;     // Inhalt ggf. auf Maximalwert begrenzen
+      }
+      meas2midi = post2midArr[slNr].aimRoll;
+      resultNote[meas2midi] =
+          post2midArr[slNr].midiBords[meas2midi].low +
+          (byte) ((rollVal - post2midArr[slNr].borderLowRoll) * post2midArr[slNr].koeffRoll);
+
+      pitchVal = pitchOld + post2midArr[slNr].offsetPitch; // Pitchwinkel in positiven Bereich verschieben
+      if(pitchVal < post2midArr[slNr].borderLowPitch)
+      {
+        pitchVal = post2midArr[slNr].borderLowPitch;    // Inhalt ggf. auf Minimalwert begrenzen
+      }
+      else if(pitchVal > post2midArr[slNr].borderHighPitch)
+      {
+        pitchVal = post2midArr[slNr].borderHighPitch;   // Inhalt ggf. auf Maximalwert begrenzen
+      }
+      meas2midi = post2midArr[slNr].aimPitch;
+      resultNote[meas2midi] =
+          post2midArr[slNr].midiBords[meas2midi].low +
+          (byte) ((pitchVal - post2midArr[slNr].borderLowPitch) * post2midArr[slNr].koeffPitch);
+      resultNote[NoteVel] = 100;
+      break;
+  }
+
+  ap.enter(apSetResult);
+}
+
+// ----------------------------------------------------------------------------
+// Bedienen des Midi-Controller
+//
+dword apSetResultCnt;
+void apSetResult()
+{
+  apSetResultCnt++;
+
+  switch (appType)
+  {
+    case BlePoll::atSOAAP1:
+      if(slNr == 1)
+        midi1.setChordNote(lastNoteIdxM1, (MidiNotes::NoteTypeIdx) resultAx, resultAz, 100);
+      else if(slNr == 2)
+        midi2.setChordNote(lastNoteIdxM2, (MidiNotes::NoteTypeIdx) resultAx, resultAz, 100);
+      break;
+
+    case BlePoll::atSOAAP2:
+      if(slNr == 1)
+        midi1.setChordNote
+        (
+          lastNoteIdxM1,
+          (MidiNotes::NoteTypeIdx) resultNote[NoteType],
+          resultNote[NoteVal],
+          resultNote[NoteVel]
+        );
+      else if(slNr == 2)
+        midi2.setChordNote
+        (
+          lastNoteIdxM1,
+          (MidiNotes::NoteTypeIdx) resultNote[NoteType],
+          resultNote[NoteVal],
+          resultNote[NoteVel]
+        );
+      break;
+  }
+
+  ap.enter(apWaitMeas);
+}
+
+byte  testValue = 22;
+
+void apTestController()
+{
+  midi1.setChordNote(lastNoteIdxM1, MidiNotes::nti4, testValue, 60);
+  testValue++;
+  if(testValue > 96)
+    testValue = 22;
+  ap.setDelay(100);
+}
+
+
+
+#ifdef DebugTerminal
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e   z u m   D e b u g g e n   (sm)
+// ****************************************************************************
+//
+dword   debDword;
+byte    tmpByteArray[256];
+
+
+void smInit()
+{
+  sm.enter(smCheckJobs);
+}
+
+// ----------------------------------------------------------------------------
+// Abfrage der Monitorschalter
+// ----------------------------------------------------------------------------
+//
+
+void smCheckJobs()
+{
+  if(mon.cFlag[1] && !mon.busy)
+    sm.enter(smDebDword);
+  else if(mon.cFlag[2] && !mon.busy)
+    sm.enter(smCtrlPolling);
+  else if(mon.cFlag[3] && !mon.busy)
+    sm.enter(smReadPollValues);
+  else if(mon.cFlag[4] && !mon.busy)
+    sm.enter(smCheckApp);
+  else if(mon.cFlag[5] && !mon.busy)
+    sm.enter(smMode4Slave);
+}
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+void smDebDword()
+{
+  int idx;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "DebDword[");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn >= 0x30 && mon.lastKeyIn <= 0x39)
+  {
+    idx = mon.lastKeyIn & 0x0F;
+    mon.print(idx);
+    mon.print((char *) "]=");
+    debDword = blePoll.debGetDword(idx);
+    mon.println(debDword);
+    sm.resetEnter();
+  }
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[1] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Steuern des Polling-Prozesses
+// ----------------------------------------------------------------------------
+//
+
+char *smPollHelp =
+{
+    "C   Pollzähler zurücksetzen\r\n"
+    "L   Liste der Slaves anzeigen\r\n"
+    "P   Polling starten/stoppen/fortsetzen\r\n"
+    "R   Radiopuffer auslesen (16 Zeichen)\r\n"
+    "S   Sendepuffer auslesen (16 Zeichen)\r\n"
+    "T   Übertragungsstatistik und Daten anzeigen\r\n"
+    "0...9  Slave-Umgebung\r\n"
+};
+
+TxStatistics txStatistics;
+
+void smCtrlPolling()
+{
+  dword   tmpDw;
+  short   tmpShort;
+  int     i;
+
+  PlpMeas6Ptr resPtr;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "polling ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn == 'H' || mon.lastKeyIn == 'h')
+  {
+    mon.println();
+    mon.print(smPollHelp);
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'P' || mon.lastKeyIn == 'p')
+  {
+    if(blePoll.stoppedEP())
+    {
+      blePoll.resumeEP();
+      mon.println((char *) "fortgesetzt");
+      sm.resetEnter();
+    }
+    else
+    {
+    blePoll.stopEP();
+    sm.enter(smWaitPolling);
+    }
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'C' || mon.lastKeyIn == 'c')
+  {
+    blePoll.resetPollCounters();
+    mon.println((char *) "Zähler zurückgesetzt");
+    sm.resetEnter();
+  }
+
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'R' || mon.lastKeyIn == 'r')
+  {
+    mon.print((char *) "Radiopuffer = ");
+    bleCom.getPduMem(tmpByteArray, 0, 16);
+    mon.println(tmpByteArray, 16, ' ');
+    sm.resetEnter();
+  }
+
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'S' || mon.lastKeyIn == 's')
+  {
+    mon.print((char *) "Sendepuffer = ");
+    bleCom.getPduSentS(tmpByteArray, 0, 16);
+    mon.println(tmpByteArray, 16, ' ');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'L' || mon.lastKeyIn == 'l')
+  {
+    mon.print((char *) "Slave-Liste: ");
+    int nrOfSlaves = blePoll.getSlaveList(tmpByteArray, 255);
+    mon.println(tmpByteArray, nrOfSlaves, ',');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'T' || mon.lastKeyIn == 't')
+  {
+    mon.print((char *) "TxStat [");
+    dword bleStat = blePoll.getStatistics(&txStatistics);
+    mon.print(bleStat);
+    mon.print((char *) "] ");
+    mon.print(txStatistics.mode); mon.cprint(' ');
+    mon.print(txStatistics.interrupts); mon.cprint(' ');
+    mon.print(txStatistics.recs); mon.cprint(' ');
+    mon.print(txStatistics.sendings); mon.cprint(' ');
+    mon.print(txStatistics.aliens); mon.cprint(' ');
+    mon.print(txStatistics.wrongs); mon.cprint(' ');
+    mon.print(txStatistics.pollAcks); mon.cprint(' ');
+    mon.print(txStatistics.pollNaks); mon.cprint(' ');
+    mon.print(txStatistics.crcErrors); mon.print("  s[ ");
+    mon.print(txStatistics.memDumpSnd,8,' '); mon.print("]  r[ ");
+    mon.print(txStatistics.memDumpRec,16,' '); mon.cprintln(']');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn >= '0' && mon.lastKeyIn <= '9')
+  {
+    int idx = mon.lastKeyIn & 0x0F;
+    SlavePtr slPtr = blePoll.getSlavePtr(idx);
+    PollStatePtr pPtr = blePoll.getPollPtr(slPtr->pIdx);
+
+    mon.print((char *) "Slave[");
+    mon.print(idx);
+    mon.print((char *) "] ");
+    mon.print(slPtr->cntTo); mon.cprint(' ');
+    mon.print(slPtr->cntNakEP); mon.cprint(' ');
+    mon.print(slPtr->cntAckDP); mon.cprint(' ');
+
+    if(slPtr->cntAckDP == 0)
+    {
+      if(slPtr->cntTo == 0)
+        tmpDw = slPtr->cntNakEP;
+      else
+        tmpDw = slPtr->cntNakEP / slPtr->cntTo;
+    }
+    else
+    {
+      if(slPtr->cntTo == 0)
+        tmpDw = slPtr->cntAckDP;
+      else
+        tmpDw = slPtr->cntAckDP / slPtr->cntTo;
+    }
+    mon.print(tmpDw); mon.cprint(' ');
+
+    resPtr = (PlpMeas6Ptr) &slPtr->result;
+
+    mon.print(slPtr->cntLostPdu); mon.cprint('|');
+    mon.print(slPtr->cntErrCrc); mon.cprint('|');
+    //mon.print(slPtr->result.measCnt); mon.cprint('|');
+    mon.print(resPtr->measCnt); mon.cprint('|');
+    mon.print(slPtr->cntLostMeas); mon.cprint(' ');
+
+    for(i = 0; i < 6; i++)
+    {
+      //tmpShort = (short) slPtr->result.meas[i];
+      tmpShort = (short) resPtr->meas[i];
+            mon.prints(tmpShort); mon.cprint(' ');
+    }
+    mon.print((char *) "  Poll[");
+    mon.print(slPtr->pIdx);
+    mon.print((char *) "] ");
+    mon.print(pPtr->status); mon.cprint(' ');
+    mon.println(pPtr->slIdx);
+    sm.resetEnter();
+  }
+
+
+
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[2] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+void smWaitPolling()
+{
+  if(!blePoll.stoppedEP()) return;
+
+  mon.println((char *) "angehalten");
+  sm.enter(smCtrlPolling);
+}
+
+// ----------------------------------------------------------------------------
+// Zugriff auf die Sensordaten
+// ----------------------------------------------------------------------------
+//
+
+char *rpValHelp =
+{
+"0-9  Sensordaten\r\n"
+"Leerzeichen für Abbruch\r\n"
+};
+
+void smReadPollValues()
+{
+  PlPduMeasPtr  resultPtr;
+  PlPduMeasPtr  ctrlPtr;
+  byte          appId;
+  float         tmpFloat;
+  char          conv[32];
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "Werte vom Sensor ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn == 'H' || mon.lastKeyIn == 'h')
+  {
+    mon.println();
+    mon.println(rpValHelp);
+    sm.resetEnter();
+  }
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn >= '0' && mon.lastKeyIn <= '9')
+  {
+    int idx = mon.lastKeyIn & 0x0F;
+    SlavePtr slPtr = blePoll.getSlavePtr(idx);
+    PollStatePtr pPtr = blePoll.getPollPtr(slPtr->pIdx);
+    resultPtr = (PlPduMeasPtr) &slPtr->result;
+    ctrlPtr = (PlPduMeasPtr) &slPtr->control;
+    appId = resultPtr->appId;
+
+    mon.print((char *) "Slave[");
+    mon.print(idx);
+    mon.print((char *) "] pduCnt=");
+    mon.print(resultPtr->counter);
+    mon.print((char *) " pduType=");
+    mon.print(resultPtr->type);
+    mon.print((char *) " appId=");
+    mon.print(resultPtr->appId);
+    mon.print((char *) " measCnt=");
+    mon.println(resultPtr->measCnt);
+
+    mon.println(resultPtr->plData,27,' ');
+
+    switch (appId)
+    {
+      case plptIMU3F4Ctrl4:
+        mon.print("AppId: plptIMU3F4Ctrl4");
+        mon.print(" Roll=");
+        tmpFloat = ((PlpI3S4C4Ptr) resultPtr)->meas[0];
+        sprintf(conv,"%f",tmpFloat);
+        mon.print(conv);
+        mon.print(" Pitch=");
+        tmpFloat = ((PlpI3S4C4Ptr) resultPtr)->meas[1];
+        sprintf(conv,"%f",tmpFloat);
+        mon.print(conv);
+        break;
+
+      default:
+        mon.print(" Unbekannte AppId");
+        break;
+    }
+    mon.println();
+    sm.resetEnter();
+  }
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[3] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+
+}
+
+// ----------------------------------------------------------------------------
+// Analysieren der Anwendung
+// ----------------------------------------------------------------------------
+//
+char *caHelp =
+{
+"c Zyklen der Zustandsmaschine\r\n"
+"m Ausgabe Midiwerte\r\n"
+"Leerzeichen für Abbruch\r\n"
+};
+
+void smCheckApp()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "Check App ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn == 'H' || mon.lastKeyIn == 'h')
+  {
+    mon.println();
+    mon.println(caHelp);
+    sm.resetEnter();
+  }
+  else if(mon.lastKeyIn == 'C' || mon.lastKeyIn == 'c')
+  {
+    mon.cprintln('c');
+    mon.print(apInitCnt); mon.cprint(' ');
+    mon.print(apWaitDECnt); mon.cprint(' ');
+    mon.print(apWaitMeasCnt); mon.cprint(' ');
+    mon.print(apProcMeasCnt); mon.cprint(' ');
+    mon.print(apCheckValuesCnt); mon.cprint(' ');
+    mon.print(apCalcResultCnt); mon.cprint(' ');
+    mon.println(apSetResultCnt);
+    sm.resetEnter();
+  }
+  else if(mon.lastKeyIn == 'M' || mon.lastKeyIn == 'm')
+  {
+    mon.cprintln('m');
+    mon.print(slNr); mon.cprint(' ');
+    mon.print(resultNote[NoteType]); mon.cprint(' ');
+    mon.print(resultNote[NoteVal]); mon.cprint(' ');
+    mon.println(resultNote[NoteVel]);
+    sm.resetEnter();
+  }
+
+  else if(mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[4] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Modus (Polling-Info, Steuerung) an einen Slave
+// ----------------------------------------------------------------------------
+// ACHTUNG!
+// Diese Testfunktion ist allgemein gehalten. Tatsächlich wird zur Zeit noch
+// nicht der Datentyp ausgewertet und immer die ersten zwei Zeichen Inhalt
+// zum Slave übertragen
+//
+char *msHelp =
+{
+"1. 1..5 Slaveadresse\r\n"
+"2. 0..9 Modustyp oder A für Antwort\r\n"
+"   xyz  Modus, Senden mit TAB\r\n"
+"Leerzeichen für Abbruch\r\n"
+};
+
+int   inIdx = 0;
+int   msSlaveNr = 0;
+int   msModeType = 0;
+
+CtrlResp2 ctrlResp;
+byte      oldProcCnt = 0;
+
+void smMode4Slave()
+{
+  //CtrlData2Ptr ctrlDataPtr;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "Meldung an Slave[");
+    mon.lastKeyIn = ':';
+    inIdx = 0;
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn == 'H' || mon.lastKeyIn == 'h')
+  {
+    mon.println();
+    mon.println(msHelp);
+    sm.resetEnter();
+  }
+  else if(mon.lastKeyIn >= '1' && mon.lastKeyIn <= '5' && inIdx == 0)
+  {
+    mon.cprint(mon.lastKeyIn);
+    msSlaveNr = mon.lastKeyIn & 0x0F;
+    mon.print("] Typ = ");
+    inIdx = 1;
+    mon.lastKeyIn = ':';
+  }
+  else if(mon.lastKeyIn >= '0' && mon.lastKeyIn <= '9' && inIdx == 1)
+  {
+    mon.cprint(mon.lastKeyIn);
+    msModeType = mon.lastKeyIn & 0x0F;
+    sm.enter(smMode4SlaveIn);
+  }
+  else if((mon.lastKeyIn == 'A' || mon.lastKeyIn == 'a') && inIdx == 1)
+  {
+    mon.print("Antwort: {");
+    blePoll.getCtrlResp(msSlaveNr, &ctrlResp);
+
+    if(ctrlResp.procCnt != oldProcCnt)
+    {
+      oldProcCnt = ctrlResp.procCnt;
+      mon.cprint(ctrlResp.ctrl[0]);
+      mon.cprint(ctrlResp.ctrl[1]);
+    }
+    mon.cprintln('}');
+    sm.resetEnter();
+  }
+
+  else if(mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[5] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+}
+
+char mode2Snd[8];
+
+void smMode4SlaveIn()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) " {");
+    mon.lastKeyIn = ':';
+    inIdx = 0;
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[5] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+
+  else if(mon.lastKeyIn == '\t' || inIdx > 5)
+  {
+    blePoll.updControl(msSlaveNr, (byte *) mode2Snd, 2);
+    mon.println("} gesendet");
+    sm.enter(smMode4Slave);
+  }
+
+  else
+  {
+    mode2Snd[inIdx] = mon.lastKeyIn;
+    mon.cprint(mon.lastKeyIn);
+    mon.lastKeyIn = ':';
+    inIdx++;
+  }
+
+}
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+#endif // DebugTerminal
+
diff --git a/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/test/README b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/test/README
new file mode 100644
index 0000000000000000000000000000000000000000..9b1e87bc67c90e7f09a92a3e855444b085c655a6
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/22_11_11_1_BLE_Master_Soaap/test/README
@@ -0,0 +1,11 @@
+
+This directory is intended for PlatformIO Test Runner and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PlatformIO Unit Testing:
+- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.gitignore b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..d7c90c91edbd8584ab713f39dcdbbaa149059e5d
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.gitignore
@@ -0,0 +1,7 @@
+.pio
+.vscode/.browse.c_cpp.db*
+.vscode/c_cpp_properties.json
+.vscode/launch.json
+.vscode/ipch
+*.log
+*.ini
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/build/nano33ble/idedata.json b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/build/nano33ble/idedata.json
new file mode 100644
index 0000000000000000000000000000000000000000..df0afb763a300d300f146a268654bce90035aa03
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/build/nano33ble/idedata.json
@@ -0,0 +1 @@
+{"env_name": "nano33ble", "libsource_dirs": ["c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1\\lib", "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1\\.pio\\libdeps\\nano33ble", "C:\\Users\\lenna\\.platformio\\lib", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries"], "defines": ["PLATFORMIO=60104", "ARDUINO_ARDUINO_NANO33BLE", "ARDUINO_ARCH_NRF52840", "smnDEFBYBUILD", "smnNANOBLE33", "smnDEBUG", "ARM_MATH_CM4", "BOARD_PCA10056", "__CMSIS_RTOS", "CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"", "COMPONENT_FLASHIAP=1", "CONFIG_GPIO_AS_PINRESET", "__CORTEX_M4", "DEVICE_ANALOGIN=1", "DEVICE_FLASH=1", "DEVICE_I2C=1", "DEVICE_I2C_ASYNCH=1", "DEVICE_I2CSLAVE=1", "DEVICE_INTERRUPTIN=1", "DEVICE_LPTICKER=1", "DEVICE_PORTIN=1", "DEVICE_PORTINOUT=1", "DEVICE_PORTOUT=1", "DEVICE_PWMOUT=1", "DEVICE_SERIAL=1", "DEVICE_SERIAL_ASYNCH=1", "DEVICE_SERIAL_FC=1", "DEVICE_SLEEP=1", "DEVICE_SPI=1", "DEVICE_SPI_ASYNCH=1", "DEVICE_SYSTICK_CLK_OFF_DURING_SLEEP=1", "DEVICE_TRNG=1", "DEVICE_USBDEVICE=1", "DEVICE_USTICKER=1", "DEVICE_WATCHDOG=1", "FEATURE_BLE=1", "FEATURE_CRYPTOCELL310=1", "FEATURE_STORAGE=1", "__FPU_PRESENT=1", "__MBED__=1", "MBED_BUILD_TIMESTAMP=1652255892.88627", "__MBED_CMSIS_RTOS_CM", "MBED_MPU_CUSTOM", "MBED_TICKLESS", "MBEDTLS_CONFIG_HW_SUPPORT", "NRF52840_XXAA", "NRF52_PAN_20", "SWI_DISABLE0", "TARGET_ARDUINO_NANO33BLE", "TARGET_CORDIO", "TARGET_CORDIO_LL", "TARGET_CORTEX", "TARGET_CORTEX_M", "TARGET_LIKE_CORTEX_M4", "TARGET_LIKE_MBED", "TARGET_M4", "TARGET_MCU_NRF52840", "TARGET_NAME=ARDUINO_NANO33BLE", "TARGET_NORDIC", "TARGET_NORDIC_CORDIO", "TARGET_NRF52", "TARGET_NRF52840", "TARGET_NRF5x", "TARGET_RELEASE", "TARGET_RTOS_M4_M7", "TARGET_SDK_15_0", "TARGET_SOFTDEVICE_NONE", "TOOLCHAIN_GCC", "TOOLCHAIN_GCC_ARM", "WSF_MAX_HANDLERS=10", "MBED_NO_GLOBAL_USING_DIRECTIVE=1", "CORE_MAJOR=3", "CORE_MINOR=1", "CORE_PATCH=1", "USE_ARDUINO_PINOUT", "ARDUINO=10810", "ARDUINO_ARCH_MBED"], "includes": {"build": ["c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1\\include", "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1\\src", "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1\\include", "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1\\src", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SensorLSM9DS1", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Twi", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Gpio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\MidiNotes", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino\\api\\deprecated", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino\\api\\deprecated-avr-comp", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\variants\\ARDUINO_NANO33BLE"], "compatlib": ["C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\MidiNotes", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\MidiNotes", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SensorLSM9DS1", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SensorLSM9DS1", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Gpio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Gpio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Twi", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Twi", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Camera\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Ethernet\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\GC2145", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\GPS\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\GSM\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Himax_HM01B0", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\KernelDebug\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\MCUboot\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\MLC\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\MRI\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Nano33BLE_System\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Nicla_System\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\PDM\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_Audio\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_SDCARD\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_SDRAM\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_Video\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_lvgl\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\RPC\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\SE05X\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\SFU\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\SPI", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\STM32H747_System\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Scheduler\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\SocketWrapper\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\ThreadDebug\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\USBAudio", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\USBHID\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\USBHOST\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\USBMSD\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\WiFi\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Wire", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\doom\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\ea_malloc", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\mbed-memory-status", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\openamp_arduino\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\rpclib\\src"], "toolchain": ["C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\arm-none-eabi\\include\\c++\\8.2.1", "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\arm-none-eabi\\include\\c++\\8.2.1\\arm-none-eabi", "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\lib\\gcc\\arm-none-eabi\\8.2.1\\include", "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\lib\\gcc\\arm-none-eabi\\8.2.1\\include-fixed", "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\arm-none-eabi\\include"]}, "cc_flags": "-std=gnu11 -DAPPLICATION_ADDR=0x10000 -DAPPLICATION_SIZE=0xf0000 -DMBED_RAM_SIZE=0x40000 -DMBED_RAM_START=0x20000000 -DMBED_ROM_SIZE=0x100000 -DMBED_ROM_START=0x0 -DMBED_TRAP_ERRORS_ENABLED=1 -Os -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -c -fdata-sections -ffunction-sections -fmessage-length=0 -fno-exceptions -fomit-frame-pointer -funsigned-char -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -mthumb -iprefixC:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino @C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\variants\\ARDUINO_NANO33BLE\\includes.txt -nostdlib", "cxx_flags": "-Wvla -fno-rtti -std=gnu++14 -DAPPLICATION_ADDR=0x10000 -DAPPLICATION_SIZE=0xf0000 -DMBED_RAM_SIZE=0x40000 -DMBED_RAM_START=0x20000000 -DMBED_ROM_SIZE=0x100000 -DMBED_ROM_START=0x0 -DMBED_TRAP_ERRORS_ENABLED=1 -Os -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -c -fdata-sections -ffunction-sections -fmessage-length=0 -fno-exceptions -fomit-frame-pointer -funsigned-char -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -mthumb -iprefixC:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino @C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\variants\\ARDUINO_NANO33BLE\\includes.txt -nostdlib", "cc_path": "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\bin\\arm-none-eabi-gcc.exe", "cxx_path": "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\bin\\arm-none-eabi-g++.exe", "gdb_path": "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\bin\\arm-none-eabi-gdb.exe", "prog_path": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1\\.pio\\build\\nano33ble\\firmware.elf", "svd_path": "C:\\Users\\lenna\\.platformio\\platforms\\nordicnrf52\\misc\\svd\\nrf52840.svd", "compiler_type": "gcc", "targets": [{"name": "size", "title": "Program Size", "description": "Calculate program size", "group": "Platform"}, {"name": "upload", "title": "Upload", "description": null, "group": "Platform"}, {"name": "erase", "title": "Erase Flash", "description": null, "group": "Platform"}], "extra": {"flash_images": []}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/build/project.checksum b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/build/project.checksum
new file mode 100644
index 0000000000000000000000000000000000000000..3c2961d85e9ba1031c76f84d3102bcb4f64b73cc
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/build/project.checksum
@@ -0,0 +1 @@
+6107bbcff6a5f2b9e99a6c32ff252bb709c950ae
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/BlePoll.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/BlePoll.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..28e17bc7ae86c00b35723fe8330bad0ca9a97a93
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/BlePoll.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "BlePoll", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/ComRingBuf.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/ComRingBuf.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..56126438430e9280d1ac92cda5e3c9e43fd2d2c5
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/ComRingBuf.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "ComRingBuf", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/LoopCheck.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/LoopCheck.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..e32a4fb766d160e6337a3565c9bd6ea0029deae7
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/LoopCheck.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "LoopCheck", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/MidiNotes.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/MidiNotes.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..41e3a9906f26be2ff46316bba3179b1d0bd4be05
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/MidiNotes.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "MidiNotes", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\MidiNotes"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/Monitor.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/Monitor.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..4c502e2a44fc82ee0fbcbd201665542e2f1d6b1c
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/Monitor.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "Monitor", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/SensorLSM9DS1.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/SensorLSM9DS1.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..bdec87c63a7998807f54ebc393fa2b8e18c424b3
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/SensorLSM9DS1.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "SensorLSM9DS1", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SensorLSM9DS1"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/SoaapMsg.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/SoaapMsg.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..fc05abe269f0169f2afbcf2759de824f5b893f88
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/SoaapMsg.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "SoaapMsg", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/StateMachine.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/StateMachine.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..e0ce3a058ae2760279eb131fe5f7a428a8f01e1c
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/StateMachine.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "StateMachine", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/environment.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/environment.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..58b10673feffeae43ce8bc157878aa3287bc7f56
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/environment.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "environment", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/integrity.dat b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/integrity.dat
new file mode 100644
index 0000000000000000000000000000000000000000..eb48d1334c2ebd5faafe31fd0022200f84692be8
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/integrity.dat
@@ -0,0 +1,13 @@
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Gpio.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Gpio.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..3073b4f1bc60606bb097a21dc7cf3986074598e0
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Gpio.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "nRF52840Gpio", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Gpio"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Radio.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Radio.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..fd40a8f98d13dcda2abe778b810adc2a1ac35fca
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Radio.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "nRF52840Radio", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Ser.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Ser.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..e57534b75b96899080d89827a24e57eb7c5f224f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Ser.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "nRF52840Ser", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Twi.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Twi.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..3eb0cf1371ad6143871c0af57bb2bf1f1ca41cc5
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.pio/libdeps/nano33ble/nRF52840Twi.pio-link
@@ -0,0 +1 @@
+{"cwd": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Master_Test_1", "spec": {"owner": null, "id": null, "name": "nRF52840Twi", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Twi"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.vscode/extensions.json b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.vscode/extensions.json
new file mode 100644
index 0000000000000000000000000000000000000000..080e70d08b9811fa743afe5094658dba0ed6b7c2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/.vscode/extensions.json
@@ -0,0 +1,10 @@
+{
+    // See http://go.microsoft.com/fwlink/?LinkId=827846
+    // for the documentation about the extensions.json format
+    "recommendations": [
+        "platformio.platformio-ide"
+    ],
+    "unwantedRecommendations": [
+        "ms-vscode.cpptools-extension-pack"
+    ]
+}
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/include/README b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/include/README
new file mode 100644
index 0000000000000000000000000000000000000000..194dcd43252dcbeb2044ee38510415041a0e7b47
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/include/README
@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/lib/README b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/lib/README
new file mode 100644
index 0000000000000000000000000000000000000000..6debab1e8b4c3faa0d06f4ff44bce343ce2cdcbf
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/lib/README
@@ -0,0 +1,46 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link into executable file.
+
+The source code of each library should be placed in a an own separate directory
+("lib/your_library_name/[here are source files]").
+
+For example, see a structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+|  |
+|  |--Bar
+|  |  |--docs
+|  |  |--examples
+|  |  |--src
+|  |     |- Bar.c
+|  |     |- Bar.h
+|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+|  |
+|  |--Foo
+|  |  |- Foo.c
+|  |  |- Foo.h
+|  |
+|  |- README --> THIS FILE
+|
+|- platformio.ini
+|--src
+   |- main.c
+
+and a contents of `src/main.c`:
+```
+#include <Foo.h>
+#include <Bar.h>
+
+int main (void)
+{
+  ...
+}
+
+```
+
+PlatformIO Library Dependency Finder will find automatically dependent
+libraries scanning project source files.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/platformio.ini b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/platformio.ini
new file mode 100644
index 0000000000000000000000000000000000000000..ccfbefb1b29fcf9743c184f15a2115cd9a82015d
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/platformio.ini
@@ -0,0 +1,60 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+	
+[env:Logging]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+monitor_filters =
+  default   ; Remove typical terminal control codes from input
+  time      ; Add timestamp with milliseconds for each new line
+  log2file  ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
+
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/src/main.cpp b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7669201242f9aee1636d388890138095ae1d6aa2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/src/main.cpp
@@ -0,0 +1,438 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleMaster.ino
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                        P o l l i n g - M a s t e r
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. November 2021
+// Letzte Bearbeitung: 1. November 2021
+//
+#include "Arduino.h"
+
+#include "LoopCheck.h"
+#include "StateMachine.h"
+#include "nRF52840Radio.h"
+#include "BlePoll.h"
+#include "Monitor.h"
+#include "SoaapBleMaster.h"  //Eingefügt
+
+#define DebugTerminal
+// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden
+// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist
+
+LoopCheck     lc;
+// Eine statische Instanz der Klasse LoopCheck
+// Darüber wird das Zeitverhalten gesteuert (Software-Timer) und geprüft
+
+#ifdef DebugTerminal
+Monitor       mon(modeEcho | modeNl,0,&lc);
+byte    tmpByteArray[256];
+// Eine statische Instanz (mit Konstruktordaten) der Klasse Monitor
+// Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert
+// Unter Linux werden hier GtkTerm (siehe Internet) und
+// ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt.
+// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeigent,
+// weil damit keine direkte Kommunikation (getipptes Zeichen sofort gesendet)
+// möglich ist.
+// ----- Parameter ------------------------------------------------------------
+// <mode Echo>  Alle eintreffenden Zeichen werden sofort zurückgesendet
+// <mode NL>    Vor der Ausgabe des Prompt (M>) erfolgt CR/LF
+// <0>          Für Speicherzugriffe wird von 32 Bit ARM ausgegangen
+// <&lc>        Für Zeitüberwachungen und entsprechende statisctische Daten
+//              greift die Monitor-Klasse auf die LoopCheck-Klasse zu
+#endif
+
+nRF52840Radio bleCom;
+// Eine statische Instanz der Klasse nRF52840Radio
+// Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und
+// Empfangen von BLE-Beacons angesprochen.
+
+
+#define bleCycleTime 150
+BlePoll       blePoll((IntrfRadio *) &bleCom, micros);
+// Eine statische Instanz der Klasse BlePoll
+// Darüber werden das Polling des Masters als auch die Antworten der Slaves
+// gesteuert. Es können Geräte entwickelt werden, die nur Master oder Slave
+// sind und solche mit Doppelfunktion, wenn kein expliziter Master
+// eingesetzt und das Netzwerk über Spontan-Master quasi dezentral
+// betrieben werden soll.
+// ----- Parameter ------------------------------------------------------------
+// <&bleCom>    Die Klasse (vom angenommenen Typ IntrfRadio), die die Daten-
+//              übertragung abwickelt. Hier wird eine Instanz von nRF52840Radio
+//              angebunden. Für andere Hardware kann eine entsprechende Klasse
+//              verwendet werden, die von IntrfRadio abgeleitet wurde.
+// <micros>     Eine Funktion, die die verstrichene Zeit in Mikrosekunden gibt.
+//              Damit werden Zeiten (z.B. Time-Out) berechnet.
+//              Wird hier der Wert NULL übergeben, dann werden die Zeiten aus
+//              dem Aufrufzyklus (bleCycleTime) in Mikrosekunden berechnet,
+//              was hier einer Auflösung von 500 Mikrosekunden entspricht.
+
+#ifdef DebugTerminal
+#define smCycleTime 5
+void smInit();  // Vorwärtsreferenz auf die weiter unten definierte Funktion
+StateMachine  sm(smInit, NULL, smCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für allgemeine
+// Steuerungen, Überwachungen und zum Debugging verwendet wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Millisekunden
+#endif
+
+#define NrOfSlavesToPoll  5
+// Die Anzahl der Slaves, die der Master aufrufen soll (Polling).
+// Es wird grundsätzlich mit der Adresse 1 begonnen und nach dem Aufruf die
+// Adresse inkrementiert, also immer die Slaves Adr = 1 bis
+// Adr = NrOfSlavesToPoll+1 aufgerufen.
+// ACHTUNG!
+// Diese Zahl muss kleiner/gleich der in BlePoll.h definierten maximalen
+// Anzahl der Slaves (MAXSLAVE) sein, weil die Ressourcen darüber statisch
+// festgelegt werden.
+
+// ============================================================================
+int durchlaufe=0; //hinzugefügt
+void setup()
+{
+  
+  pinMode(LED_BUILTIN,OUTPUT);
+  bleCom.begin();           // Initialisierung der Datenübertragung
+  //bleCom.setPower(0x08);     // Maximale Sendeleistung bei nRF52840
+  // TEST
+  bleCom.setPower(0x0FC);   // Reduzierte Sendeleistung beim Schreibtisch-Test
+
+  blePoll.begin(BlePoll::ctMASTER, NrOfSlavesToPoll, BlePoll::atSOAAP, 1000000);
+  // Initialisierung des Polling mit folgenden Parametern:
+  // <BlePoll::ctMASTER>    Es wird ein Master eingerichtet
+  // <NrOfSlavesToPoll>     Anzahl gepollter Slaves (s.o.)
+  // <BlePoll::atSOAAP>     Spezielle Anwendung SOAAP
+  // <10000>                INT-Watchdog-Timeout beim Lesen in Mikrosekunden
+
+  blePoll.setEmptyPollParams(2000, 500, 2000);
+  // Setzen der Parameter für das leere Polling zur Feststellung der
+  // vorhandenen Slaves und Aufbau einer Poll-Liste für den Datenaustausch
+  // ----- Parameter ----------------------------------------------------------
+  // <2000>   Anzahl der Poll-Durchläufe, solange kein Slave gefunden wird
+  // <500>    Anzahl weiterer Durchläufe, nachdem wenigstens ein Slave gefunden ist
+  // <2000>   Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden
+
+  for(int i = 1; i <= NrOfSlavesToPoll; i++)
+    blePoll.setDataPollParams(i, 1, 10, 1000);
+  // Setzen der Parameter beim Datenpolling, für Slaves individuell
+  // ----- Parameter ----------------------------------------------------------
+  // <i>      Adresse des Slave (1-..)
+  // <1>      Priorität beim Aufruf, 0 = immer bis max 65535 = sehr selten
+  // <10>     minimale Priorität bei automatischer Prioritätsreduzierung
+  //          im Fall von Störungen (Time-Out)
+  // <1500>   Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden
+
+  // TEST
+  blePoll.stopEP();   // Das Polling muss extra gestartet werden
+}
+
+// ============================================================================
+void loop()
+{
+  lc.begin();     // Muss am Anfang von LOOP aufgerufen werden
+  // --------------------------------------------------------------------------
+
+#ifdef DebugTerminal
+  mon.run();      // Der Monitor bekommt bei jedem Durchlauf die CPU
+
+#endif
+
+  // Alle 500 Mikrosekunden erfolgt der Aufruf des Ble-Polling
+  //
+  if(lc.timerMicro(lcTimer0, bleCycleTime, 0)){
+       blePoll.run();      
+  }
+ 
+  // ----- Parameter der Software-Timer ---------------------------------------
+  // <lcTimer0>   Id/Nummer des Timer, zur Zeit werden bis 10 Timer unterstützt
+  //              lcTimer0 bis lcTimer9 (einstellbar in LoopCheck.h)
+  // <bleCycleTime>   Ablaufzeit in Einheit des Timer-Typ (Micro/Milli)
+  //                  hier in Mikrosekunden (timerMicro)
+  // <0>          Anzahl der Wiederholungen, 0 = unbegrenzt
+
+#ifdef DebugTerminal
+  // Jede Sekunde erfolgt die Ausgabe einer Versionsmeldung
+  // das kann über c0 am Terminal abgeschaltet werden
+  //
+  if(lc.timerMilli(lcTimer1, 1000, 0))
+  {
+    if(!mon.cFlag[0]){
+       durchlaufe++; //hinzugefügt
+       //mon.printcr((char *)"%@TestBleMaster (ttyACM0), Version 20211104\n");
+       //mon.println(durchlaufe); //hinzugefügt
+       smWaitPolling();
+    }
+     
+  }
+  // Die Zeichen %@ am Anfang steuern die Ausgabe bei AndroidMonTerm in ein
+  // Textfeld (Label) statt auf das Terminal-Display
+
+  // Alle 5 Millisekunden erfolgt der Aufruf der Zustandsmaschine
+  //
+  if(lc.timerMilli(lcTimer2, smCycleTime, 0))
+  {
+    sm.run();
+  }
+#endif
+
+
+  // --------------------------------------------------------------------------
+  lc.end();       // Muss vor dem Ende von LOOP aufgerufen werden
+}
+
+#ifdef DebugTerminal
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e
+// ****************************************************************************
+//
+dword   debDword;
+
+
+
+void smInit()
+{
+  sm.enter(smCheckJobs);
+}
+
+// ----------------------------------------------------------------------------
+// Abfrage der Monitorschalter
+// ----------------------------------------------------------------------------
+//
+
+void smCheckJobs()
+{
+  if(mon.cFlag[1] && !mon.busy)
+    sm.enter(smDebDword);
+  else if(mon.cFlag[2] && !mon.busy)
+    sm.enter(smCtrlPolling);
+  else if(mon.cFlag[3] && !mon.busy)
+    sm.enter(smReadPollValues);
+  /*
+  else if(mon.cFlag[4] && !mon.busy)
+    sm.enter(smCheckSens);
+  */
+}
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+void smDebDword()
+{
+  int idx;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "DebDword[");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn >= 0x30 && mon.lastKeyIn <= 0x39)
+  {
+    idx = mon.lastKeyIn & 0x0F;
+    mon.print(idx);
+    mon.print((char *) "]=");
+    debDword = blePoll.debGetDword(idx);
+    mon.println(debDword);
+    sm.resetEnter();
+  }
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[1] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Steuern des Polling-Prozesses
+// ----------------------------------------------------------------------------
+//
+
+TxStatistics txStatistics;
+
+void smCtrlPolling()
+{
+  dword   tmpDw;
+  short   tmpShort;
+  int     i;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "polling ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  // --------------------------------------------------------------------------
+  if(mon.lastKeyIn == 'P' || mon.lastKeyIn == 'p')
+  {
+    if(blePoll.stoppedEP())
+    {
+      blePoll.resumeEP();
+      mon.println((char *) "fortgesetzt");
+      sm.resetEnter();
+    }
+    else
+    {
+    blePoll.stopEP();
+    sm.enter(smWaitPolling);
+    }
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'C' || mon.lastKeyIn == 'c')
+  {
+    blePoll.resetPollCounters();
+    mon.println((char *) "Zähler zurückgesetzt");
+    sm.resetEnter();
+  }
+
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'R' || mon.lastKeyIn == 'r')
+  {
+    mon.print((char *) "Radiopuffer = ");
+    bleCom.getPduMem(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'S' || mon.lastKeyIn == 's')
+  {
+    mon.print((char *) "Sendepuffer = ");
+    bleCom.getPduSent(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'L' || mon.lastKeyIn == 'l')
+  {
+    mon.print((char *) "Slave-Liste: ");
+    int nrOfSlaves = blePoll.getSlaveList(tmpByteArray, 255);
+    mon.println(tmpByteArray, nrOfSlaves, ',');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'T' || mon.lastKeyIn == 't')
+  {
+    mon.print((char *) "TxStat [");
+    dword bleStat = blePoll.getStatistics(&txStatistics);
+    mon.print(bleStat);
+    mon.print((char *) "] ");
+    mon.print(txStatistics.mode); mon.cprint(' ');
+    mon.print(txStatistics.interrupts); mon.cprint(' ');
+    mon.print(txStatistics.recs); mon.cprint(' ');
+    mon.print(txStatistics.sendings); mon.cprint(' ');
+    mon.print(txStatistics.aliens); mon.cprint(' ');
+    mon.print(txStatistics.wrongs); mon.cprint(' ');
+    mon.print(txStatistics.pollAcks); mon.cprint(' ');
+    mon.print(txStatistics.pollNaks); mon.cprint(' ');
+    mon.print(txStatistics.crcErrors); mon.print("  s[ ");
+    mon.print(txStatistics.memDumpSnd,8,' '); mon.print("]  r[ ");
+    mon.print(txStatistics.memDumpRec,16,' '); mon.cprintln(']');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn >= '0' && mon.lastKeyIn <= '9')
+  {
+    int idx = mon.lastKeyIn & 0x0F;
+    SlavePtr slPtr = blePoll.getSlavePtr(idx);
+    PollStatePtr pPtr = blePoll.getPollPtr(slPtr->pIdx);
+
+    mon.print((char *) "Slave[");
+    mon.print(idx);
+    mon.print((char *) "] ");
+    mon.print(slPtr->cntTo); mon.cprint(' ');
+    mon.print(slPtr->cntNakEP); mon.cprint(' ');
+    mon.print(slPtr->cntAckDP); mon.cprint(' ');
+
+    if(slPtr->cntAckDP == 0)
+    {
+      if(slPtr->cntTo == 0)
+        tmpDw = slPtr->cntNakEP;
+      else
+        tmpDw = slPtr->cntNakEP / slPtr->cntTo;
+    }
+    else
+    {
+      if(slPtr->cntTo == 0)
+        tmpDw = slPtr->cntAckDP;
+      else
+        tmpDw = slPtr->cntAckDP / slPtr->cntTo;
+    }
+    mon.print(tmpDw); mon.cprint(' ');
+
+    mon.print(slPtr->cntLostPdu); mon.cprint('|');
+    mon.print(slPtr->cntErrCrc); mon.cprint('|');
+    mon.print(slPtr->result.measCnt); mon.cprint('|');
+    mon.print(slPtr->cntLostMeas); mon.cprint(' ');
+
+    for(i = 0; i < 6; i++)
+    {
+      tmpShort = (short) slPtr->result.meas[i];
+      mon.prints(tmpShort); mon.cprint(' ');
+    }
+    mon.print((char *) "  Poll[");
+    mon.print(slPtr->pIdx);
+    mon.print((char *) "] ");
+    mon.print(pPtr->status); mon.cprint(' ');
+    mon.println(pPtr->slIdx);
+    sm.resetEnter();
+  }
+
+
+
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[2] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+void smWaitPolling()
+{
+  if(!blePoll.stoppedEP()) return;
+
+  mon.println((char *) "angehalten");
+  sm.enter(smCtrlPolling);
+}
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+void smReadPollValues()
+{
+
+}
+
+#endif // DebugTerminal
+
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/template_platformio.txt b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/template_platformio.txt
new file mode 100644
index 0000000000000000000000000000000000000000..00fcc504ed42a1ed10054916dbc0a611c5bc2c2c
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/template_platformio.txt
@@ -0,0 +1,60 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://[Pfad_Repository]\libraries\BlePoll
+	symlink://[Pfad_Repository]\libraries\environment
+	symlink://[Pfad_Repository]\libraries\ComRingBuf
+	symlink://[Pfad_Repository]\libraries\LoopCheck
+	symlink://[Pfad_Repository]\libraries\MidiNotes
+	symlink://[Pfad_Repository]\libraries\Monitor
+	symlink://[Pfad_Repository]\libraries\nRF52840Gpio
+	symlink://[Pfad_Repository]\libraries\nRF52840Radio
+	symlink://[Pfad_Repository]\libraries\nRF52840Ser
+	symlink://[Pfad_Repository]\libraries\nRF52840Twi
+	symlink://[Pfad_Repository]\libraries\SensorLSM9DS1
+	symlink://[Pfad_Repository]\libraries\SoaapMsg
+	symlink://[Pfad_Repository]\libraries\StateMachine
+	;symlink://[Pfad_Repository]\libraries\SoaapComDue
+
+[env:Logging]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://[Pfad_Repository]\libraries\BlePoll
+	symlink://[Pfad_Repository]\libraries\environment
+	symlink://[Pfad_Repository]\libraries\ComRingBuf
+	symlink://[Pfad_Repository]\libraries\LoopCheck
+	symlink://[Pfad_Repository]\libraries\MidiNotes
+	symlink://[Pfad_Repository]\libraries\Monitor
+	symlink://[Pfad_Repository]\libraries\nRF52840Gpio
+	symlink://[Pfad_Repository]\libraries\nRF52840Radio
+	symlink://[Pfad_Repository]\libraries\nRF52840Ser
+	symlink://[Pfad_Repository]\libraries\nRF52840Twi
+	symlink://[Pfad_Repository]\libraries\SensorLSM9DS1
+	symlink://[Pfad_Repository]\libraries\SoaapMsg
+	symlink://[Pfad_Repository]\libraries\StateMachine
+	;symlink://[Pfad_Repository]\libraries\SoaapComDue
+monitor_filters =
+  default   ; Remove typical terminal control codes from input
+  time      ; Add timestamp with milliseconds for each new line
+  log2file  ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
+
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/test/README b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/test/README
new file mode 100644
index 0000000000000000000000000000000000000000..9b1e87bc67c90e7f09a92a3e855444b085c655a6
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Master_Test_1/test/README
@@ -0,0 +1,11 @@
+
+This directory is intended for PlatformIO Test Runner and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PlatformIO Unit Testing:
+- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.gitignore b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..672308dcd458c0250233374dcfe709c33b67c2ed
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.gitignore
@@ -0,0 +1,6 @@
+.pio
+.vscode/.browse.c_cpp.db*
+.vscode/c_cpp_properties.json
+.vscode/launch.json
+.vscode/ipch
+*.ini
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/.sconsign39.dblite b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/.sconsign39.dblite
new file mode 100644
index 0000000000000000000000000000000000000000..63be4bed358c427195e49cbc722e90e30b853826
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/.sconsign39.dblite differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/Interrupts.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/Interrupts.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..6c9841f8b79d3c0544c1fa7f0782759e1af2a51a
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/Interrupts.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/Serial.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/Serial.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..295926d8825b590173829774b4a40d9ff4adc8f2
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/Serial.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/Tone.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/Tone.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..825be7302b203c09976878f2d5cb1ea2a99a811f
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/Tone.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/USB/PluggableUSBDevice.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/USB/PluggableUSBDevice.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..9c886ba269a45e35f34d0be3a619b9968b716ebe
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/USB/PluggableUSBDevice.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/USB/USBCDC.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/USB/USBCDC.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..dcf1160ab607cd05205e3c07a0fd61328b46547a
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/USB/USBCDC.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/USB/USBSerial.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/USB/USBSerial.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..d534c1fb5f0eaa501367e8bb3e1662dec1048b8c
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/USB/USBSerial.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/WMath.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/WMath.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..f5fe8e0142d91ebbda5fd43bbe00d139bf127965
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/WMath.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/abi.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/abi.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..049d127a2b6877f29effc011deaa6de622879609
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/abi.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/Common.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/Common.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..f21ab7233894b4513fb2f0668c037bfa8bf66c02
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/Common.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/IPAddress.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/IPAddress.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..dc96c7f7bccf38b66142457b0acb07d37be84da5
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/IPAddress.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/PluggableUSB.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/PluggableUSB.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..f628d930d9813b86b018b3bc22e85baf8e66a221
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/PluggableUSB.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/Print.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/Print.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..5bd90a4ee9b90ac62540faf8d3521665638734bd
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/Print.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/Stream.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/Stream.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..5c8d3573fcd97236448846b55d6b9d0ed84f8345
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/Stream.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/String.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/String.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..0cdddeaba9f1703c59d385e5b676691e25935f8a
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/api/String.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/arm_hal_random.c.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/arm_hal_random.c.o
new file mode 100644
index 0000000000000000000000000000000000000000..5c07ffc730e4924f3bb8d7cdd06145c8c458258b
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/arm_hal_random.c.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/as_mbed_library/variant.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/as_mbed_library/variant.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..6dc884556ee35c888abba3919c31ca6cad8f3658
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/as_mbed_library/variant.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/itoa.c.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/itoa.c.o
new file mode 100644
index 0000000000000000000000000000000000000000..b5450562e4d2e10fc21017817830502019ef2c1b
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/itoa.c.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/main.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/main.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..b7bfb5e9fcba4b2e72fa0ecf2ddfc6ace9fa8065
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/main.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/mbed/platform/cxxsupport/mstd_mutex.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/mbed/platform/cxxsupport/mstd_mutex.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..48e49b2cdd0621c400b5f36049fe85671435ca24
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/mbed/platform/cxxsupport/mstd_mutex.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/pinToIndex.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/pinToIndex.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..525e981af7ea3239cdd358e2a6486b9eeb225144
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/pinToIndex.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/random_seed.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/random_seed.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..8e99f7b1103595b3159ff904a315fe4db6ed81b7
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/random_seed.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/timer.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/timer.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..e460418560d0eb3a7980b20a5e957aea1aecb9d7
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/timer.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..ae2e00bf06b2fa683f79d8be394f9b72b435d270
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_analog.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_analog.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..d2b5bdf05cb72760f512a40ee7f4182752d93bb7
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_analog.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_digital.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_digital.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..8c3db1e4556a973001c1e21daa19bd0065fbff5e
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_digital.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_pulse.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_pulse.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..8b83c5a8e757f2b0cac1f54ce315e988332709ac
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_pulse.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_shift.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_shift.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..673fcf8f7cd8073cf7d745e87e2a830e4335863b
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduino/wiring_shift.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduinoVariant/variant.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduinoVariant/variant.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..86cce2e8a92084743f3356451fc72df9865bd794
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/FrameworkArduinoVariant/variant.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/cpp.linker_script.ld b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/cpp.linker_script.ld
new file mode 100644
index 0000000000000000000000000000000000000000..270da6c4371ee1182fb0253c37c7c543b92ccc48
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/cpp.linker_script.ld
@@ -0,0 +1,154 @@
+MEMORY
+{
+  FLASH (rx) : ORIGIN = 0x10000, LENGTH = 0xf0000
+  RAM_NVIC (rwx) : ORIGIN = 0x20000000, LENGTH = 0x100
+  RAM_CRASH_DATA (rwx) : ORIGIN = (0x20000000 + 0x100), LENGTH = 0x100
+  RAM (rwx) : ORIGIN = ((0x20000000 + 0x100) + 0x100), LENGTH = (0x40000 - (0x100 + 0x100))
+}
+OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+ENTRY(Reset_Handler)
+SECTIONS
+{
+    .text :
+    {
+        KEEP(*(.Vectors))
+        *(.text*)
+        KEEP(*(.init))
+        KEEP(*(.fini))
+        *crtbegin.o(.ctors)
+        *crtbegin?.o(.ctors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
+        *(SORT(.ctors.*))
+        *(.ctors)
+        *crtbegin.o(.dtors)
+        *crtbegin?.o(.dtors)
+        *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
+        *(SORT(.dtors.*))
+        *(.dtors)
+        *(.rodata*)
+        KEEP(*(.eh_frame*))
+    } > FLASH
+    .sdh_soc_observers :
+    {
+        PROVIDE(__start_sdh_soc_observers = .);
+        KEEP(*(SORT(.sdh_soc_observers*)))
+        PROVIDE(__stop_sdh_soc_observers = .);
+    } > FLASH
+    .sdh_stack_observers :
+    {
+        PROVIDE(__start_sdh_stack_observers = .);
+        KEEP(*(SORT(.sdh_stack_observers*)))
+        PROVIDE(__stop_sdh_stack_observers = .);
+    } > FLASH
+    .sdh_req_observers :
+    {
+        PROVIDE(__start_sdh_req_observers = .);
+        KEEP(*(SORT(.sdh_req_observers*)))
+        PROVIDE(__stop_sdh_req_observers = .);
+    } > FLASH
+    .sdh_state_observers :
+    {
+        PROVIDE(__start_sdh_state_observers = .);
+        KEEP(*(SORT(.sdh_state_observers*)))
+        PROVIDE(__stop_sdh_state_observers = .);
+    } > FLASH
+    .sdh_ble_observers :
+    {
+        PROVIDE(__start_sdh_ble_observers = .);
+        KEEP(*(SORT(.sdh_ble_observers*)))
+        PROVIDE(__stop_sdh_ble_observers = .);
+    } > FLASH
+    .ARM.extab :
+    {
+        *(.ARM.extab* .gnu.linkonce.armextab.*)
+    } > FLASH
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > FLASH
+    __exidx_end = .;
+    __etext = .;
+    .data : AT (__etext)
+    {
+        __data_start__ = .;
+        *(vtable)
+        *(.data*)
+        . = ALIGN(8);
+        PROVIDE_HIDDEN (__preinit_array_start = .);
+        KEEP(*(.preinit_array))
+        PROVIDE_HIDDEN (__preinit_array_end = .);
+        . = ALIGN(8);
+        PROVIDE_HIDDEN (__init_array_start = .);
+        KEEP(*(SORT(.init_array.*)))
+        KEEP(*(.init_array))
+        PROVIDE_HIDDEN (__init_array_end = .);
+        . = ALIGN(8);
+        PROVIDE_HIDDEN (__fini_array_start = .);
+        KEEP(*(SORT(.fini_array.*)))
+        KEEP(*(.fini_array))
+        PROVIDE_HIDDEN (__fini_array_end = .);
+        . = ALIGN(8);
+        PROVIDE(__start_fs_data = .);
+        KEEP(*(.fs_data))
+        PROVIDE(__stop_fs_data = .);
+        *(.jcr)
+        . = ALIGN(8);
+        __data_end__ = .;
+    } > RAM
+    __edata = .;
+    .nvictable (NOLOAD) :
+    {
+      PROVIDE(__start_nvictable = .);
+      KEEP(*(.nvictable))
+      PROVIDE(__stop_nvictable = .);
+    } > RAM_NVIC
+    .crash_data_ram :
+    {
+      . = ALIGN(8);
+      __CRASH_DATA_RAM__ = .;
+      __CRASH_DATA_RAM_START__ = .;
+      KEEP(*(.keep.crash_data_ram))
+      *(.m_crash_data_ram)
+      . += 0x100;
+      . = ALIGN(8);
+      __CRASH_DATA_RAM_END__ = .;
+    } > RAM_CRASH_DATA
+    .noinit (NOLOAD) :
+    {
+      PROVIDE(__start_noinit = .);
+      KEEP(*(.noinit))
+      PROVIDE(__stop_noinit = .);
+    } > RAM
+    .bss :
+    {
+        . = ALIGN(8);
+        __bss_start__ = .;
+        *(.bss*)
+        *(COMMON)
+        . = ALIGN(8);
+        __bss_end__ = .;
+    } > RAM
+    .heap (NOLOAD):
+    {
+        __end__ = .;
+        end = __end__;
+        *(.heap*);
+        ASSERT(. <= (ORIGIN(RAM) + LENGTH(RAM) - 0x400), "heap region overflowed into stack");
+        . = ORIGIN(RAM) + LENGTH(RAM) - 0x400;
+        __HeapLimit = .;
+    } > RAM
+    PROVIDE(__heap_start = ADDR(.heap));
+    PROVIDE(__heap_size = SIZEOF(.heap));
+    PROVIDE(__mbed_sbrk_start = ADDR(.heap));
+    PROVIDE(__mbed_krbs_start = ADDR(.heap) + SIZEOF(.heap));
+    .stack (NOLOAD):
+    {
+        __StackLimit = .;
+        *(.stack*)
+        . = ORIGIN(RAM) + LENGTH(RAM);
+    } > RAM
+    __StackTop = ORIGIN(RAM) + LENGTH(RAM);
+    __StackLimit = __StackTop - 0x400;
+    PROVIDE(__stack = __StackTop);
+}
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/firmware.bin b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/firmware.bin
new file mode 100644
index 0000000000000000000000000000000000000000..e8b770e854d101303736c4415e4167c53af54fe3
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/firmware.bin differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/firmware.elf b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/firmware.elf
new file mode 100644
index 0000000000000000000000000000000000000000..9b44d63b332fbc4bdf28f9376350878dd58ce517
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/firmware.elf differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/idedata.json b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/idedata.json
new file mode 100644
index 0000000000000000000000000000000000000000..9727ec372d5cf2dca51a525457e3d016ca9311ff
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/idedata.json
@@ -0,0 +1 @@
+{"env_name": "nano33ble", "libsource_dirs": ["c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test\\lib", "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test\\.pio\\libdeps\\nano33ble", "C:\\Users\\lenna\\.platformio\\lib", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries"], "defines": ["PLATFORMIO=60104", "ARDUINO_ARDUINO_NANO33BLE", "ARDUINO_ARCH_NRF52840", "smnDEFBYBUILD", "smnNANOBLE33", "smnDEBUG", "ARM_MATH_CM4", "BOARD_PCA10056", "__CMSIS_RTOS", "CMSIS_VECTAB_VIRTUAL", "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"", "COMPONENT_FLASHIAP=1", "CONFIG_GPIO_AS_PINRESET", "__CORTEX_M4", "DEVICE_ANALOGIN=1", "DEVICE_FLASH=1", "DEVICE_I2C=1", "DEVICE_I2C_ASYNCH=1", "DEVICE_I2CSLAVE=1", "DEVICE_INTERRUPTIN=1", "DEVICE_LPTICKER=1", "DEVICE_PORTIN=1", "DEVICE_PORTINOUT=1", "DEVICE_PORTOUT=1", "DEVICE_PWMOUT=1", "DEVICE_SERIAL=1", "DEVICE_SERIAL_ASYNCH=1", "DEVICE_SERIAL_FC=1", "DEVICE_SLEEP=1", "DEVICE_SPI=1", "DEVICE_SPI_ASYNCH=1", "DEVICE_SYSTICK_CLK_OFF_DURING_SLEEP=1", "DEVICE_TRNG=1", "DEVICE_USBDEVICE=1", "DEVICE_USTICKER=1", "DEVICE_WATCHDOG=1", "FEATURE_BLE=1", "FEATURE_CRYPTOCELL310=1", "FEATURE_STORAGE=1", "__FPU_PRESENT=1", "__MBED__=1", "MBED_BUILD_TIMESTAMP=1652255892.88627", "__MBED_CMSIS_RTOS_CM", "MBED_MPU_CUSTOM", "MBED_TICKLESS", "MBEDTLS_CONFIG_HW_SUPPORT", "NRF52840_XXAA", "NRF52_PAN_20", "SWI_DISABLE0", "TARGET_ARDUINO_NANO33BLE", "TARGET_CORDIO", "TARGET_CORDIO_LL", "TARGET_CORTEX", "TARGET_CORTEX_M", "TARGET_LIKE_CORTEX_M4", "TARGET_LIKE_MBED", "TARGET_M4", "TARGET_MCU_NRF52840", "TARGET_NAME=ARDUINO_NANO33BLE", "TARGET_NORDIC", "TARGET_NORDIC_CORDIO", "TARGET_NRF52", "TARGET_NRF52840", "TARGET_NRF5x", "TARGET_RELEASE", "TARGET_RTOS_M4_M7", "TARGET_SDK_15_0", "TARGET_SOFTDEVICE_NONE", "TOOLCHAIN_GCC", "TOOLCHAIN_GCC_ARM", "WSF_MAX_HANDLERS=10", "MBED_NO_GLOBAL_USING_DIRECTIVE=1", "CORE_MAJOR=3", "CORE_MINOR=1", "CORE_PATCH=1", "USE_ARDUINO_PINOUT", "ARDUINO=10810", "ARDUINO_ARCH_MBED"], "includes": {"build": ["c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test\\include", "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test\\src", "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test\\include", "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test\\src", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SensorLSM9DS1", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Twi", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Gpio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\MidiNotes", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino\\api\\deprecated", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino\\api\\deprecated-avr-comp", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\variants\\ARDUINO_NANO33BLE"], "compatlib": ["C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\MidiNotes", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\MidiNotes", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SensorLSM9DS1", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SensorLSM9DS1", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Gpio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Gpio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Twi", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Twi", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment", "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Camera\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Ethernet\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\GC2145", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\GPS\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\GSM\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Himax_HM01B0", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\KernelDebug\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\MCUboot\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\MLC\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\MRI\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Nano33BLE_System\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Nicla_System\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\PDM\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_Audio\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_SDCARD\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_SDRAM\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_Video\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Portenta_lvgl\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\RPC\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\SE05X\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\SFU\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\SPI", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\STM32H747_System\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Scheduler\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\SocketWrapper\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\ThreadDebug\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\USBAudio", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\USBHID\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\USBHOST\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\USBMSD\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\WiFi\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\Wire", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\doom\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\ea_malloc", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\mbed-memory-status", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\openamp_arduino\\src", "C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\libraries\\rpclib\\src"], "toolchain": ["C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\arm-none-eabi\\include\\c++\\8.2.1", "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\arm-none-eabi\\include\\c++\\8.2.1\\arm-none-eabi", "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\lib\\gcc\\arm-none-eabi\\8.2.1\\include", "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\lib\\gcc\\arm-none-eabi\\8.2.1\\include-fixed", "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\arm-none-eabi\\include"]}, "cc_flags": "-std=gnu11 -DAPPLICATION_ADDR=0x10000 -DAPPLICATION_SIZE=0xf0000 -DMBED_RAM_SIZE=0x40000 -DMBED_RAM_START=0x20000000 -DMBED_ROM_SIZE=0x100000 -DMBED_ROM_START=0x0 -DMBED_TRAP_ERRORS_ENABLED=1 -Os -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -c -fdata-sections -ffunction-sections -fmessage-length=0 -fno-exceptions -fomit-frame-pointer -funsigned-char -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -mthumb -iprefixC:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino @C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\variants\\ARDUINO_NANO33BLE\\includes.txt -nostdlib", "cxx_flags": "-Wvla -fno-rtti -std=gnu++14 -DAPPLICATION_ADDR=0x10000 -DAPPLICATION_SIZE=0xf0000 -DMBED_RAM_SIZE=0x40000 -DMBED_RAM_START=0x20000000 -DMBED_ROM_SIZE=0x100000 -DMBED_ROM_START=0x0 -DMBED_TRAP_ERRORS_ENABLED=1 -Os -Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -c -fdata-sections -ffunction-sections -fmessage-length=0 -fno-exceptions -fomit-frame-pointer -funsigned-char -mcpu=cortex-m4 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -mthumb -iprefixC:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\cores\\arduino @C:\\Users\\lenna\\.platformio\\packages\\framework-arduino-mbed\\variants\\ARDUINO_NANO33BLE\\includes.txt -nostdlib", "cc_path": "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\bin\\arm-none-eabi-gcc.exe", "cxx_path": "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\bin\\arm-none-eabi-g++.exe", "gdb_path": "C:\\Users\\lenna\\.platformio\\packages\\toolchain-gccarmnoneeabi\\bin\\arm-none-eabi-gdb.exe", "prog_path": "c:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test\\.pio\\build\\nano33ble\\firmware.elf", "svd_path": "C:\\Users\\lenna\\.platformio\\platforms\\nordicnrf52\\misc\\svd\\nrf52840.svd", "compiler_type": "gcc", "targets": [{"name": "size", "title": "Program Size", "description": "Calculate program size", "group": "Platform"}, {"name": "upload", "title": "Upload", "description": null, "group": "Platform"}, {"name": "erase", "title": "Erase Flash", "description": null, "group": "Platform"}], "extra": {"flash_images": []}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib035/MidiNotes/MidiNotes.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib035/MidiNotes/MidiNotes.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..b7e8e7587bb8f1e33eac5b6410be298f562c849a
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib035/MidiNotes/MidiNotes.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib035/libMidiNotes.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib035/libMidiNotes.a
new file mode 100644
index 0000000000000000000000000000000000000000..12e4eef541f153641c53a8ead88eb3aabb74041d
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib035/libMidiNotes.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib22a/libnRF52840Gpio.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib22a/libnRF52840Gpio.a
new file mode 100644
index 0000000000000000000000000000000000000000..0260a18e13883332f0f0b17bd5f1291e500ad56e
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib22a/libnRF52840Gpio.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib22a/nRF52840Gpio/nRF52840Gpio.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib22a/nRF52840Gpio/nRF52840Gpio.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..fd51005553425053a45b5ee49d5fc534b45f1b8e
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib22a/nRF52840Gpio/nRF52840Gpio.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib298/libnRF52840Radio.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib298/libnRF52840Radio.a
new file mode 100644
index 0000000000000000000000000000000000000000..9497d3bc5474b1fbbc8026ca1051673676249643
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib298/libnRF52840Radio.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib298/nRF52840Radio/nRF52840Radio.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib298/nRF52840Radio/nRF52840Radio.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..00da6f15ccde22943daa6b76cddc86c58ade2a75
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib298/nRF52840Radio/nRF52840Radio.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib489/SoaapMsg/SoaapMsg.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib489/SoaapMsg/SoaapMsg.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..f07bc27cfddbf1a1f59b9261c65e55ce37fdd4f3
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib489/SoaapMsg/SoaapMsg.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib489/libSoaapMsg.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib489/libSoaapMsg.a
new file mode 100644
index 0000000000000000000000000000000000000000..0f5f101a4bf192983d3af48841d8b3da90269375
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib489/libSoaapMsg.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib55b/SensorLSM9DS1/SensorLSM9DS1.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib55b/SensorLSM9DS1/SensorLSM9DS1.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..e10942dc0ae0610df61e126a056ac77dd4ebfd4a
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib55b/SensorLSM9DS1/SensorLSM9DS1.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib55b/libSensorLSM9DS1.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib55b/libSensorLSM9DS1.a
new file mode 100644
index 0000000000000000000000000000000000000000..d2703d36923b2cd37a54ef94b9ac71c1f01ff0b4
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib55b/libSensorLSM9DS1.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib672/LoopCheck/LoopCheck.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib672/LoopCheck/LoopCheck.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..049d5d7b31ea41acfccbf2e2a40ef279ba598ee1
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib672/LoopCheck/LoopCheck.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib672/libLoopCheck.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib672/libLoopCheck.a
new file mode 100644
index 0000000000000000000000000000000000000000..940940d39109c3b8b0ac88b172812c5e29604fcc
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib672/libLoopCheck.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib743/StateMachine/StateMachine.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib743/StateMachine/StateMachine.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..62c1425dd0556265397bb8c4c0246b0162526a1e
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib743/StateMachine/StateMachine.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib743/libStateMachine.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib743/libStateMachine.a
new file mode 100644
index 0000000000000000000000000000000000000000..c5274ccd04ec4c8e5f706da07e33669bcf1ac309
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib743/libStateMachine.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib854/libnRF52840Twi.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib854/libnRF52840Twi.a
new file mode 100644
index 0000000000000000000000000000000000000000..d4289901abb5ac14c0b8e04dddc33a6ac52bcd5d
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib854/libnRF52840Twi.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib854/nRF52840Twi/nRF52840Twi.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib854/nRF52840Twi/nRF52840Twi.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..a8a48b75ceedf1ad8792df3f61889aee1b50e744
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib854/nRF52840Twi/nRF52840Twi.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib88d/libnRF52840Ser.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib88d/libnRF52840Ser.a
new file mode 100644
index 0000000000000000000000000000000000000000..d11cdf828d1270375730e8eef52a55aacd1e7c3a
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib88d/libnRF52840Ser.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib88d/nRF52840Ser/nRF52840Ser.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib88d/nRF52840Ser/nRF52840Ser.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..dc3e164731ae73159f5aa5c47867805cc62334fb
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/lib88d/nRF52840Ser/nRF52840Ser.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libFrameworkArduino.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libFrameworkArduino.a
new file mode 100644
index 0000000000000000000000000000000000000000..bc4887205d4d5a70cd946c4ebe247b9a43c614e9
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libFrameworkArduino.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libFrameworkArduinoVariant.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libFrameworkArduinoVariant.a
new file mode 100644
index 0000000000000000000000000000000000000000..cb9d1f91879fb9d2ee13cbe8b942140a6dd85b55
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libFrameworkArduinoVariant.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/liba91/Monitor/Monitor.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/liba91/Monitor/Monitor.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..deb5d277562414e9db8131c21fcb720298a91541
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/liba91/Monitor/Monitor.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/liba91/libMonitor.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/liba91/libMonitor.a
new file mode 100644
index 0000000000000000000000000000000000000000..6fa045a8eb02d6c5cc91d3b4e9dd20fb0186d567
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/liba91/libMonitor.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libae7/ComRingBuf/ComRingBuf.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libae7/ComRingBuf/ComRingBuf.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..687546aae3a7f3cd71ff00b9260c0f44e484dfa4
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libae7/ComRingBuf/ComRingBuf.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libae7/libComRingBuf.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libae7/libComRingBuf.a
new file mode 100644
index 0000000000000000000000000000000000000000..98dc83f798e0db8bc846946bdc31be05eea26b64
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libae7/libComRingBuf.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libcb6/BlePoll/BlePoll.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libcb6/BlePoll/BlePoll.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..859eb2f9d034e4f0ff59fa79e15ff573d669fef6
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libcb6/BlePoll/BlePoll.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libcb6/libBlePoll.a b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libcb6/libBlePoll.a
new file mode 100644
index 0000000000000000000000000000000000000000..8479c8dac4a068e351977eb33afbe01a62e2d5af
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/libcb6/libBlePoll.a differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/src/main.cpp.o b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/src/main.cpp.o
new file mode 100644
index 0000000000000000000000000000000000000000..e9f3e33ee37679f1555db71d936567d0a702f89f
Binary files /dev/null and b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/src/main.cpp.o differ
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/project.checksum b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/project.checksum
new file mode 100644
index 0000000000000000000000000000000000000000..8de1c7c752ebc08953959170fb7b0d8484f9df7a
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/project.checksum
@@ -0,0 +1 @@
+8949507b04c84791d764325d3c0e910241474dde
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/BlePoll.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/BlePoll.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..978477bae18199005bf305ebb4df3ac7c1191808
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/BlePoll.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "BlePoll", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\BlePoll"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/ComRingBuf.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/ComRingBuf.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..e04c4d7c552ba69f044c93cf7b6358317e29219f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/ComRingBuf.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "ComRingBuf", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\ComRingBuf"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/LoopCheck.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/LoopCheck.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..e1ac5a053fe51f9c88e8a0170bc0c60e56758be0
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/LoopCheck.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "LoopCheck", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\LoopCheck"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/MidiNotes.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/MidiNotes.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..2a8ec94b3947b495f78670ce1aca031da327ef0e
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/MidiNotes.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "MidiNotes", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\MidiNotes"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/Monitor.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/Monitor.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..8724c6e004489a40959c837ea6794f40cb63c38f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/Monitor.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "Monitor", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\Monitor"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/SensorLSM9DS1.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/SensorLSM9DS1.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..74b4363313704966664ad157112409dc4155826f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/SensorLSM9DS1.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "SensorLSM9DS1", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SensorLSM9DS1"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/SoaapMsg.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/SoaapMsg.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..63ab581b52c0a74a1872336c6d82ba54b60241d3
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/SoaapMsg.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "SoaapMsg", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\SoaapMsg"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/StateMachine.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/StateMachine.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..6e215a70373300c36c4bd0c4e9f0464487c97f70
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/StateMachine.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "StateMachine", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\StateMachine"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/environment.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/environment.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..a9b1f84a21edb89e615510bb2fb23e7445b9eccc
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/environment.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "environment", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\environment"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/integrity.dat b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/integrity.dat
new file mode 100644
index 0000000000000000000000000000000000000000..6ad1ace54354516865687e4e038f9a0c96a596f1
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/integrity.dat
@@ -0,0 +1,13 @@
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Gpio.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Gpio.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..15616b399f47d5c991efaf3829880a630e0f710d
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Gpio.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "nRF52840Gpio", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Gpio"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Radio.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Radio.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..daf4ba5b7188463cab8add7ba82e0ec2197233e8
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Radio.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "nRF52840Radio", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Radio"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Ser.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Ser.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..6138f45ed8a830ddf37c11bccb690ba38e6e2596
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Ser.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "nRF52840Ser", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Ser"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Twi.pio-link b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Twi.pio-link
new file mode 100644
index 0000000000000000000000000000000000000000..fd14e5670e139b046a6ce30d9bd18db2b58f13c2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/libdeps/nano33ble/nRF52840Twi.pio-link
@@ -0,0 +1 @@
+{"cwd": "C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\sketches\\_PIO_Sketches\\Karger\\BLE_Slae_Test", "spec": {"owner": null, "id": null, "name": "nRF52840Twi", "requirements": null, "uri": "symlink://C:\\Users\\lenna\\OneDrive\\Dokumente\\Git\\SOAAP\\libraries\\nRF52840Twi"}}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.vscode/c_cpp_properties.json b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.vscode/c_cpp_properties.json
new file mode 100644
index 0000000000000000000000000000000000000000..da5d72a3c7ed5877585eb88a016c649a897272ed
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.vscode/c_cpp_properties.json
@@ -0,0 +1,227 @@
+//
+// !!! WARNING !!! AUTO-GENERATED FILE!
+// PLEASE DO NOT MODIFY IT AND USE "platformio.ini":
+// https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
+//
+{
+    "configurations": [
+        {
+            "name": "PlatformIO",
+            "includePath": [
+                "c:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/include",
+                "c:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/src",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/StateMachine",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/SensorLSM9DS1",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/nRF52840Twi",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/nRF52840Ser",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/nRF52840Radio",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/nRF52840Gpio",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/Monitor",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/MidiNotes",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/LoopCheck",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/ComRingBuf",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/BlePoll",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/environment",
+                "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/SoaapMsg",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/cores/arduino",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/cores/arduino/api/deprecated",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/cores/arduino/api/deprecated-avr-comp",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/variants/ARDUINO_NANO33BLE",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Camera/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Ethernet/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/GC2145",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/GPS/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/GSM/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Himax_HM01B0",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/KernelDebug/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/MCUboot/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/MLC/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/MRI/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Nano33BLE_System/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Nicla_System/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/PDM/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_Audio/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_SDCARD/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_SDRAM/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_Video/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_lvgl/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/RPC/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/SE05X/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/SFU/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/SPI",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/STM32H747_System/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Scheduler/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/SocketWrapper/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/ThreadDebug/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/USBAudio",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/USBHID/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/USBHOST/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/USBMSD/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/WiFi/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Wire",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/doom/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/ea_malloc",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/mbed-memory-status",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/openamp_arduino/src",
+                "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/rpclib/src",
+                ""
+            ],
+            "browse": {
+                "limitSymbolsToIncludedHeaders": true,
+                "path": [
+                    "c:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/include",
+                    "c:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/src",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/StateMachine",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/SensorLSM9DS1",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/nRF52840Twi",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/nRF52840Ser",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/nRF52840Radio",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/nRF52840Gpio",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/Monitor",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/MidiNotes",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/LoopCheck",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/ComRingBuf",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/BlePoll",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/environment",
+                    "C:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/libraries/SoaapMsg",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/cores/arduino",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/cores/arduino/api/deprecated",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/cores/arduino/api/deprecated-avr-comp",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/variants/ARDUINO_NANO33BLE",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Camera/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Ethernet/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/GC2145",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/GPS/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/GSM/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Himax_HM01B0",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/KernelDebug/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/MCUboot/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/MLC/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/MRI/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Nano33BLE_System/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Nicla_System/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/PDM/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_Audio/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_SDCARD/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_SDRAM/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_Video/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Portenta_lvgl/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/RPC/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/SE05X/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/SFU/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/SPI",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/STM32H747_System/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Scheduler/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/SocketWrapper/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/ThreadDebug/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/USBAudio",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/USBHID/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/USBHOST/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/USBMSD/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/WiFi/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/Wire",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/doom/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/ea_malloc",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/mbed-memory-status",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/openamp_arduino/src",
+                    "C:/Users/lenna/.platformio/packages/framework-arduino-mbed/libraries/rpclib/src",
+                    ""
+                ]
+            },
+            "defines": [
+                "PLATFORMIO=60104",
+                "ARDUINO_ARDUINO_NANO33BLE",
+                "ARDUINO_ARCH_NRF52840",
+                "smnDEFBYBUILD",
+                "smnNANOBLE33",
+                "smnDEBUG",
+                "ARM_MATH_CM4",
+                "BOARD_PCA10056",
+                "__CMSIS_RTOS",
+                "CMSIS_VECTAB_VIRTUAL",
+                "CMSIS_VECTAB_VIRTUAL_HEADER_FILE=\"cmsis_nvic.h\"",
+                "COMPONENT_FLASHIAP=1",
+                "CONFIG_GPIO_AS_PINRESET",
+                "__CORTEX_M4",
+                "DEVICE_ANALOGIN=1",
+                "DEVICE_FLASH=1",
+                "DEVICE_I2C=1",
+                "DEVICE_I2C_ASYNCH=1",
+                "DEVICE_I2CSLAVE=1",
+                "DEVICE_INTERRUPTIN=1",
+                "DEVICE_LPTICKER=1",
+                "DEVICE_PORTIN=1",
+                "DEVICE_PORTINOUT=1",
+                "DEVICE_PORTOUT=1",
+                "DEVICE_PWMOUT=1",
+                "DEVICE_SERIAL=1",
+                "DEVICE_SERIAL_ASYNCH=1",
+                "DEVICE_SERIAL_FC=1",
+                "DEVICE_SLEEP=1",
+                "DEVICE_SPI=1",
+                "DEVICE_SPI_ASYNCH=1",
+                "DEVICE_SYSTICK_CLK_OFF_DURING_SLEEP=1",
+                "DEVICE_TRNG=1",
+                "DEVICE_USBDEVICE=1",
+                "DEVICE_USTICKER=1",
+                "DEVICE_WATCHDOG=1",
+                "FEATURE_BLE=1",
+                "FEATURE_CRYPTOCELL310=1",
+                "FEATURE_STORAGE=1",
+                "__FPU_PRESENT=1",
+                "__MBED__=1",
+                "MBED_BUILD_TIMESTAMP=1652255892.88627",
+                "__MBED_CMSIS_RTOS_CM",
+                "MBED_MPU_CUSTOM",
+                "MBED_TICKLESS",
+                "MBEDTLS_CONFIG_HW_SUPPORT",
+                "NRF52840_XXAA",
+                "NRF52_PAN_20",
+                "SWI_DISABLE0",
+                "TARGET_ARDUINO_NANO33BLE",
+                "TARGET_CORDIO",
+                "TARGET_CORDIO_LL",
+                "TARGET_CORTEX",
+                "TARGET_CORTEX_M",
+                "TARGET_LIKE_CORTEX_M4",
+                "TARGET_LIKE_MBED",
+                "TARGET_M4",
+                "TARGET_MCU_NRF52840",
+                "TARGET_NAME=ARDUINO_NANO33BLE",
+                "TARGET_NORDIC",
+                "TARGET_NORDIC_CORDIO",
+                "TARGET_NRF52",
+                "TARGET_NRF52840",
+                "TARGET_NRF5x",
+                "TARGET_RELEASE",
+                "TARGET_RTOS_M4_M7",
+                "TARGET_SDK_15_0",
+                "TARGET_SOFTDEVICE_NONE",
+                "TOOLCHAIN_GCC",
+                "TOOLCHAIN_GCC_ARM",
+                "WSF_MAX_HANDLERS=10",
+                "MBED_NO_GLOBAL_USING_DIRECTIVE=1",
+                "CORE_MAJOR=3",
+                "CORE_MINOR=1",
+                "CORE_PATCH=1",
+                "USE_ARDUINO_PINOUT",
+                "ARDUINO=10810",
+                "ARDUINO_ARCH_MBED",
+                ""
+            ],
+            "cStandard": "c11",
+            "cppStandard": "c++14",
+            "compilerPath": "C:/Users/lenna/.platformio/packages/toolchain-gccarmnoneeabi/bin/arm-none-eabi-gcc.exe",
+            "compilerArgs": [
+                "-mcpu=cortex-m4",
+                "-mfloat-abi=softfp",
+                "-mfpu=fpv4-sp-d16",
+                "-mthumb",
+                "-iprefixC:/Users/lenna/.platformio/packages/framework-arduino-mbed/cores/arduino",
+                "@C:/Users/lenna/.platformio/packages/framework-arduino-mbed/variants/ARDUINO_NANO33BLE/includes.txt",
+                ""
+            ]
+        }
+    ],
+    "version": 4
+}
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.vscode/extensions.json b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.vscode/extensions.json
new file mode 100644
index 0000000000000000000000000000000000000000..080e70d08b9811fa743afe5094658dba0ed6b7c2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.vscode/extensions.json
@@ -0,0 +1,10 @@
+{
+    // See http://go.microsoft.com/fwlink/?LinkId=827846
+    // for the documentation about the extensions.json format
+    "recommendations": [
+        "platformio.platformio-ide"
+    ],
+    "unwantedRecommendations": [
+        "ms-vscode.cpptools-extension-pack"
+    ]
+}
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.vscode/launch.json b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.vscode/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..7a67a423076ee1431832c657907ced496eb0ba1a
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.vscode/launch.json
@@ -0,0 +1,47 @@
+// AUTOMATICALLY GENERATED FILE. PLEASE DO NOT MODIFY IT MANUALLY
+//
+// PIO Unified Debugger
+//
+// Documentation: https://docs.platformio.org/page/plus/debugging.html
+// Configuration: https://docs.platformio.org/page/projectconf/section_env_debug.html
+
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "platformio-debug",
+            "request": "launch",
+            "name": "PIO Debug",
+            "executable": "c:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/firmware.elf",
+            "projectEnvName": "nano33ble",
+            "toolchainBinDir": "C:/Users/lenna/.platformio/packages/toolchain-gccarmnoneeabi/bin",
+            "internalConsoleOptions": "openOnSessionStart",
+            "svdPath": "C:/Users/lenna/.platformio/platforms/nordicnrf52/misc/svd/nrf52840.svd",
+            "preLaunchTask": {
+                "type": "PlatformIO",
+                "task": "Pre-Debug"
+            }
+        },
+        {
+            "type": "platformio-debug",
+            "request": "launch",
+            "name": "PIO Debug (skip Pre-Debug)",
+            "executable": "c:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/firmware.elf",
+            "projectEnvName": "nano33ble",
+            "toolchainBinDir": "C:/Users/lenna/.platformio/packages/toolchain-gccarmnoneeabi/bin",
+            "internalConsoleOptions": "openOnSessionStart",
+            "svdPath": "C:/Users/lenna/.platformio/platforms/nordicnrf52/misc/svd/nrf52840.svd"
+        },
+        {
+            "type": "platformio-debug",
+            "request": "launch",
+            "name": "PIO Debug (without uploading)",
+            "executable": "c:/Users/lenna/OneDrive/Dokumente/Git/SOAAP/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/.pio/build/nano33ble/firmware.elf",
+            "projectEnvName": "nano33ble",
+            "toolchainBinDir": "C:/Users/lenna/.platformio/packages/toolchain-gccarmnoneeabi/bin",
+            "internalConsoleOptions": "openOnSessionStart",
+            "svdPath": "C:/Users/lenna/.platformio/platforms/nordicnrf52/misc/svd/nrf52840.svd",
+            "loadMode": "manual"
+        }
+    ]
+}
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/include/README b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/include/README
new file mode 100644
index 0000000000000000000000000000000000000000..194dcd43252dcbeb2044ee38510415041a0e7b47
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/include/README
@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/lib/README b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/lib/README
new file mode 100644
index 0000000000000000000000000000000000000000..6debab1e8b4c3faa0d06f4ff44bce343ce2cdcbf
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/lib/README
@@ -0,0 +1,46 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link into executable file.
+
+The source code of each library should be placed in a an own separate directory
+("lib/your_library_name/[here are source files]").
+
+For example, see a structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+|  |
+|  |--Bar
+|  |  |--docs
+|  |  |--examples
+|  |  |--src
+|  |     |- Bar.c
+|  |     |- Bar.h
+|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+|  |
+|  |--Foo
+|  |  |- Foo.c
+|  |  |- Foo.h
+|  |
+|  |- README --> THIS FILE
+|
+|- platformio.ini
+|--src
+   |- main.c
+
+and a contents of `src/main.c`:
+```
+#include <Foo.h>
+#include <Bar.h>
+
+int main (void)
+{
+  ...
+}
+
+```
+
+PlatformIO Library Dependency Finder will find automatically dependent
+libraries scanning project source files.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/platformio.ini b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/platformio.ini
new file mode 100644
index 0000000000000000000000000000000000000000..bfec98771c70ca94f7c7c7198cb894d6330c8a09
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/platformio.ini
@@ -0,0 +1,32 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM5
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33  -DsmnDEBUG ;-DSlaveACM3
+lib_deps = 
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/src/main.cpp b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..01e687692afe5efc29fe53f7ca2b3a5df088695e
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/src/main.cpp
@@ -0,0 +1,840 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleSlave.ino
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                           P o l l i n g - S l a v e
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. November 2021
+// Letzte Bearbeitung: 1. November 2021
+//
+#include "Arduino.h"
+
+#include <LoopCheck.h>
+#include "StateMachine.h"
+
+#include  "nRF52840Twi.h"
+#include  "SensorLSM9DS1.h"
+
+#include "nRF52840Radio.h"
+#include <BlePoll.h>
+#include "Monitor.h"
+
+#include "SoaapBleSlave.h" // Eingefügt
+
+
+#define DebugTerminal
+// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden
+// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist
+
+#define SlaveACM2
+/*
+#ifdef SlaveACM1
+#define SlaveADR 1
+#define StartMsg "%@TestBleSlave (Adr=1, ttyACM1), Version 20211108 "
+#endif
+*/
+#ifdef SlaveACM2
+#define SlaveADR 2
+#define StartMsg "%@TestBleSlave (Adr=4, ttyACM2), Version 20211108 "
+#endif
+
+#ifdef SlaveACM3
+#define SlaveADR 5
+#define StartMsg "%@TestBleSlave (Adr=5, ttyACM3), Version 20211108"
+#endif
+
+LoopCheck     lc;
+// Eine statische Instanz der Klasse LoopCheck
+// Darüber wird das Zeitverhalten gesteuert (Software-Timer) und geprüft
+
+#ifdef DebugTerminal
+Monitor       mon(modeEcho | modeNl,0,&lc);
+// Eine statische Instanz (mit Konstruktordaten) der Klasse Monitor
+// Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert
+// Unter Linux werden hier GtkTerm (siehe Internet) und
+// ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt.
+// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeigent,
+// weil damit keine direkte Kommunikation (getipptes Zeichen sofort gesendet)
+// möglich ist.
+// ----- Parameter ------------------------------------------------------------
+// <mode Echo>  Alle eintreffenden Zeichen werden sofort zurückgesendet
+// <mode NL>    Vor der Ausgabe des Prompt (M>) erfolgt CR/LF
+// <0>          Für Speicherzugriffe wird von 32 Bit ARM ausgegangen
+// <&lc>        Für Zeitüberwachungen und entsprechende statisctische Daten
+//              greift die Monitor-Klasse auf die LoopCheck-Klasse zu
+#endif
+
+nRF52840Radio bleCom;
+// Eine statische Instanz der Klasse nRF52840Radio
+// Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und
+// Empfangen von BLE-Beacons angesprochen.
+
+#define bleCycle 150
+BlePoll       blePoll((IntrfRadio *) &bleCom, micros);
+// Eine statische Instanz der Klasse BlePoll
+// Darüber werden das Polling des Masters als auch die Antworten der Slaves
+// gesteuert. Es können Geräte entwickelt werden, die nur Master oder Slave
+// sind und solche mit Doppelfunktion, wenn kein expliziter Master
+// eingesetzt und das Netzwerk über Spontan-Master quasi dezentral
+// betrieben werden soll.
+// ----- Parameter ------------------------------------------------------------
+// <&bleCom>    Die Klasse (vom angenommenen Typ IntrfRadio), die die Daten-
+//              übertragung abwickelt. Hier wird eine Instanz von nRF52840Radio
+//              angebunden. Für andere Hardware kann eine entsprechende Klasse
+//              verwendet werden, die von IntrfRadio abgeleitet wurde.
+// <micros>     Eine Funktion, die die verstrichene Zeit in Mikrosekunden gibt.
+//              Damit werden Zeiten (z.B. Time-Out) berechnet.
+//              Wird hier der Wert NULL übergeben, dann werden die Zeiten aus
+//              dem Aufrufzyklus (bleCycleTime) in Mikrosekunden berechnet,
+//              was hier einer Auflösung von 500 Mikrosekunden entspricht.
+
+#ifdef DebugTerminal
+#define smCycleTime 5
+void smInit();  // Vorwärtsreferenz auf die weiter unten definierte Funktion
+StateMachine  sm(smInit, NULL, smCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für allgemeine
+// Steuerungen, Überwachungen und zum Debugging verwendet wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Millisekunden
+#endif
+
+nRF52840Twi twi;
+// Eine statische Instanz der Klasse nRF52840Twi
+// Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und
+// Empfangen von I2C (TWI) Botschaften aufgerufen.
+
+int durchlaufe=0; //hinzugefügt
+#define SensorCycle   500
+SensorLSM9DS1 sens((IntrfTw *) &twi, SensorCycle);
+// Eine statische Instanz der Klasse SensorLSM9DS1 zum Zugriff
+// auf den Sensor LSM9DS1 über den I2C-Bus (TWI)
+// ----- Parameter ------------------------------------------------------------
+// <&twi>   Die Klasse (vom angenommenen Typ IntrfTw), die die Datenüber-
+//          tragung auf I2C abwickelt. Hier wird eine Instanz von nRF52840Twi
+//          angebunden. Für andere Hardware kann eine entsprechende Klasse
+//          verwendet werden, die von IntrfTw abgeleitet wurde.
+//
+// <SensorCycle>  Der Zugriff auf den Sensor erfolgt mit einer Zustands-
+//                maschine, deren Takt über die Periodenzeit SensorCycle
+//                in Mikrosekunden definiert ist. Siehe dazu entsprechenden
+//                Timeraufruf in LOOP.
+
+bool getValues(PlpType plpType, byte *dest);  // Vorwärtsreferenz für Datenübergabe
+
+void setup()
+{
+  TwiParams   twiPar;       // Parameter für den I2C-Bus
+
+#ifdef DebugTerminal
+  mon.config(6);    // 6 Anzeigekanäle, die von ArduinoMonTerm aufgebaut werden
+
+  for(int i = 0; i < 6; i++)
+  {
+    if(i < 3)
+      mon.config(i+1,'C',16000,-16000,NULL);    // Kanalnummer, Typ, Maxwert, Minwert
+    else
+      mon.config(i+1,'C',4000,-4000,NULL);
+  }
+#endif
+
+  bleCom.begin();           // Initialisierung der Datenübertragung
+  //bleCom.setPower(0x008);   // Maximale Sendeleistung bei nRF52840
+  bleCom.setPower(0x0FC);   // Reduzierte Sendeleistung beim Schreibtisch-Test
+
+  blePoll.begin(BlePoll::ctSLAVE, SlaveADR, BlePoll::atSOAAP, 10000);
+  // Initialisierung des Polling mit folgenden Parametern:
+  // <BlePoll::ctSLAVE>     Es wird ein Slave eingerichtet
+  // <SlaveADR>             Adresse (Nummer) des Slave
+  // <BlePoll::atSOAAP>     Spezielle Anwendung SOAAP
+  // <10000>                INT-Watchdog-Timeout in Mikrosekunden
+  blePoll.setCbDataPtr(sendData);
+  //blePoll.setCbDataPtr(getValues);
+  // Callback für Datenübergabe setzen
+
+  // Spezifische Parameter für den I2C-Bus am Arduino Nano 33 BLE
+  //
+  twiPar.inst     = 0;          // 1. Instanz der I2C
+  twiPar.type     = TwiMaster;  // Auswahl Master/slave
+  twiPar.clkPort  = 0;          // Takt über Port 0 (P0)
+  twiPar.clkPin   = 15;         // Takt an Pin 15 (P0.15)
+  twiPar.dataPort = 0;          // Daten über Port 0 (P0)
+  twiPar.dataPin  = 14;         // Daten an Pin 14 (P0.14)
+  twiPar.speed    = Twi100k;    // Taktfrequenz
+
+  twi.begin(&twiPar); // Initialisierung des I2C-Bus
+
+  sens.begin(FreqAG119, 12, MaxAcc4g, MaxGyro2000dps, FreqM_OFF, 0, MaxMag4G);
+  // Initialisierung der Sensorabfrage mit folgenden Parametern
+  //
+  // <FreqAG119>  Beschleunigungssensoren und Gyroskop mit 119 Hz abgefragt
+  //
+  // <12>         Vor der Wertübergabe wird der Mittelwert über 12 Messungen
+  //              gebildet. Die Messfrequenz beträgt daher ca. 10 Hz.
+  //
+  // <MaxAcc4g>   Der Maximalausschlag der Beschleunigung ist 4g
+  //
+  // <MaxGyro2000dps> Maximalausschlag des Gyro ist 2000 Grad/s
+  //
+  // <FreqM_OFF>  Der Magnetfeldsensor ist AUS (funktioniert noch nicht)
+  //
+  // <0>          Keine Mittelwertbildung der Magnetfeldmessung
+  //
+  // <MaxMag4G>   Der Maximalwert entspricht 4 Gauss
+
+  sens.syncValuesAG();
+  // Rücksetzen des Ready-Bit für Messwertübergabe
+}
+
+#ifdef DebugTerminal
+char  runView[4] = {'|','/','-','\\'};
+int   runViewIdx = 0;
+#endif
+
+void loop()
+{
+  lc.begin();
+  // --------------------------------------------------------------------------
+
+#ifdef DebugTerminal
+  // Der Monitor wird ständig aufgerufen und stellt damit eine grundsätzliche
+  // Belastung dar. Das ist für die Entwicklung auch vorgesehen.
+  // Es entsteht dadurch eine Reserve für den produktiven Einsatz.
+  //
+  mon.run();
+#endif
+
+  // Alle 500 Mikrosekunden erfolgt der Aufruf des Ble-Polling
+  //
+  if(lc.timerMicro(lcTimer0, bleCycle, 0))
+    blePoll.run();
+  // ----- Parameter der Software-Timer ---------------------------------------
+  // <lcTimer0>   Id/Nummer des Timer, zur Zeit werden bis 10 Timer unterstützt
+  //              lcTimer0 bis lcTimer9 (einstellbar in LoopCheck.h)
+  // <bleCycleTime>   Ablaufzeit in Einheit des Timer-Typ (Micro/Milli)
+  //                  hier in Mikrosekunden (timerMicro)
+  // <0>          Anzahl der Wiederholungen, 0 = unbegrenzt
+
+  // Alle 500 Mikrosekunden erfolgt der Aufruf der Sensorzustandsmaschine
+  //
+  if(lc.timerMicro(lcTimer1, SensorCycle, 0))
+    sens.run();
+
+#ifdef DebugTerminal
+  // Alle 5 Millisekunden wird die Zustandsmaschine für
+  // betriebliche Abläufe aufgerufen
+  //
+  if(lc.timerMilli(lcTimer2, smCycleTime, 0))
+  {
+    sm.run();
+  }
+
+  // Jede halbe Sekunde erfolgt die Ausgabe der Version
+  //
+  if(lc.timerMilli(lcTimer3, 500, 0))
+  {
+    if(!mon.cFlag[0])
+    {
+      /*
+      mon.print((char *) StartMsg);
+      mon.cprintcr(runView[runViewIdx]);
+      runViewIdx++;
+      if(runViewIdx > 3) runViewIdx = 0;
+      */
+      smCtrlPolling();
+    }
+  }
+#endif
+  // --------------------------------------------------------------------------
+  lc.end();
+}
+
+// ----------------------------------------------------------------------------
+// Übergabe der Daten an die BLE-Kommunikation
+// ----------------------------------------------------------------------------
+//
+RawDataAG   rawData;
+bool sendData(PlpType plpType, byte *dest){
+  short i;
+    for (i=0;i<12;i++){
+      //i%2!=0?rawData.byteArray[i]=0:rawData.byteArray[i]=i;
+      if(i==0 || i==2 || i == 4 || i == 6 || i ==8 || i== 10 || i== 12){
+        dest[i]=i;
+      }else{
+        dest[i]=i;
+      }
+    }
+  return true;
+}
+
+bool getValues(PlpType plpType, byte *dest)
+{
+  bool  newData;
+  short   i;
+
+  memset(rawData.byteArray,0,12);
+
+  newData = sens.getValuesAG(&rawData);
+  //Debug: Messdaten überschreiben
+  /*
+  for (i=0;i<12;i++){
+    i%2!=0?rawData.byteArray[i]=1:rawData.byteArray[i]=i;
+  }
+  */
+  //Ende Lennard
+  if(newData)
+  {
+    switch(plpType)
+    {
+      case plptMeas6:
+        for(i = 0; i < 12; i++)
+          dest[i] = rawData.byteArray[i];
+        break;
+    }
+  }
+  return(newData);
+
+}
+
+
+#ifdef DebugTerminal
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e
+// ****************************************************************************
+//
+
+dword       debDword;
+byte        tmpByteArray[256];
+CalValueAG  calData;
+CalValue    calValue;
+
+
+void smInit()
+{
+  sm.enter(smCheckJobs);
+}
+
+// ----------------------------------------------------------------------------
+// Abfrage der Monitorschalter
+// ----------------------------------------------------------------------------
+//
+
+void smCheckJobs()
+{
+  if(mon.cFlag[1] && !mon.busy)
+    sm.enter(smDebDword);
+  else if(mon.cFlag[2] && !mon.busy)
+    sm.enter(smCtrlPolling);
+  else if(mon.cFlag[3] && !mon.busy)
+    sm.enter(smCheckSens);
+  /*
+  else if(mon.cFlag[4] && !mon.busy)
+    sm.enter(smCheckSens);
+  */
+}
+
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+void smDebDword()
+{
+  int idx;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "DebDword[");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn >= 0x30 && mon.lastKeyIn <= 0x39)
+  {
+    idx = mon.lastKeyIn & 0x0F;
+    mon.print(idx);
+    mon.print((char *) "]=");
+    debDword = blePoll.debGetDword(idx);
+    mon.println(debDword);
+    sm.resetEnter();
+  }
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[1] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Steuern des Polling-Prozesses
+// ----------------------------------------------------------------------------
+// Es ist sowohl die Master- als auch die Slave-Funktion vorgesehen
+//
+
+TxStatistics txStatistics;
+
+void smCtrlPolling()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "polling ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  // --------------------------------------------------------------------------
+  if(mon.lastKeyIn == 'P' || mon.lastKeyIn == 'p')
+  {
+    if(blePoll.stoppedEP())
+    {
+      blePoll.resumeEP();
+      mon.println((char *) "fortgesetzt");
+      sm.resetEnter();
+    }
+    else
+    {
+    blePoll.stopEP();
+    sm.enter(smWaitPolling);
+    }
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'S' || mon.lastKeyIn == 's')
+  {
+    mon.print((char *) "Sendepuffer = ");
+    bleCom.getPduSent(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'R' || mon.lastKeyIn == 'r')
+  {
+    mon.print((char *) "Radiopuffer = ");
+    bleCom.getPduMem(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'T' || mon.lastKeyIn == 't')
+  {
+    mon.print((char *) "TxStat [");
+    dword bleStat = blePoll.getStatistics(&txStatistics);
+    mon.print(bleStat);
+    mon.print((char *) "] ");
+    mon.print(txStatistics.mode); mon.cprint(' ');
+    mon.print(txStatistics.interrupts); mon.cprint(' ');
+    mon.print(txStatistics.recs); mon.cprint(' ');
+    mon.print(txStatistics.sendings); mon.cprint(' ');
+    mon.print(txStatistics.aliens); mon.cprint(' ');
+    mon.print(txStatistics.wrongs); mon.cprint(' ');
+    mon.print(txStatistics.pollAcks); mon.cprint(' ');
+    mon.print(txStatistics.pollNaks); mon.cprint(' ');
+    mon.print(txStatistics.crcErrors); mon.print("  r[ ");
+    mon.print(txStatistics.memDumpRec,8,' '); mon.print("]  s[ ");
+    mon.print(txStatistics.memDumpSnd,16,' '); mon.cprintln(']');
+    sm.resetEnter();
+  }
+
+
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[2] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+void smWaitPolling()
+{
+  if(!blePoll.stoppedEP()) return;
+
+  mon.println((char *) "angehalten");
+  sm.enter(smCtrlPolling);
+}
+
+// ----------------------------------------------------------------------------
+// (4) Testen der Sensorzugriffe
+// ----------------------------------------------------------------------------
+//
+
+char charOut[2];
+
+void smCheckSens()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "Sensorzugriff ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  charOut[0] = mon.lastKeyIn;
+  charOut[1] = '\0';
+  mon.println(charOut);
+
+  if(mon.lastKeyIn == '0' || mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[3] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+  else if(mon.lastKeyIn == '1')
+    sm.enter(smSensReset1);
+  else if(mon.lastKeyIn == '2')
+    sm.enter(smSensReset2);
+  else if(mon.lastKeyIn == '3')
+    sm.enter(smSensGetValues1);
+  else if(mon.lastKeyIn == '4')
+    sm.enter(smSensGetValues2);
+  else if(mon.lastKeyIn == '5')
+    sm.enter(smSensGetValues3);
+  else if(mon.lastKeyIn == '6')
+    sm.enter(smSensGetValues4);
+  else if(mon.lastKeyIn == '7')
+    sm.enter(smSensGetValues5);
+  else if(mon.lastKeyIn == '8')
+    sm.enter(smSensGetValues6);
+  else if(mon.lastKeyIn == 'c')
+    sm.enter(smSensDebugValues);
+  else if(mon.lastKeyIn == 'e')
+    sm.enter(smSensGetErrors);
+  else if(mon.lastKeyIn == 'r')
+    sm.enter(smSensGetRunCounts);
+  else if(mon.lastKeyIn == 's')
+    sm.enter(smSensGetSoaapValues);
+  else if(mon.lastKeyIn == 't')
+    sm.enter(smSensGetTimeOuts);
+  else
+    sm.resetEnter();
+  mon.lastKeyIn = ':';
+}
+
+void smSensReset1()
+{
+  int retv = sens.resetAG();
+  //int retv = twi.writeByteReg(0x6B, 0x22, 0x05);
+  mon.print((char *) "resetAG = ");
+  mon.println(retv);
+  sm.enter(smCheckSens);
+}
+
+void smSensReset2()
+{
+  int retv = sens.resetM();
+  //int retv = twi.writeByteReg(0x1E, 0x21, 0x0C);
+  mon.print((char *) "resetM = ");
+  mon.println(retv);
+  sm.enter(smCheckSens);
+}
+
+void smSensGetValues1()
+{
+  if(sm.firstEnter())
+    sens.syncValuesAG();
+
+  if(!sens.getValuesAG(&rawData)) return;
+
+  mon.print((char *) "ValueA = ");
+  mon.print(rawData.valueAG.A.x);
+  mon.print((char *) " ");
+  mon.print(rawData.valueAG.A.y);
+  mon.print((char *) " ");
+  mon.println(rawData.valueAG.A.z);
+  sm.enter(smCheckSens);
+}
+
+char  outValue[64];
+
+void smSensGetValues2()
+{
+  if(sm.firstEnter())
+    sens.syncValuesAG();
+
+  if(!sens.getValuesAG(&calData)) return;
+
+  mon.print((char *) "ValueA = ");
+  sprintf(outValue,"%f ",calData.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%f ",calData.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%f ",calData.A.z);
+  mon.println(outValue);
+  sm.enter(smCheckSens);
+}
+
+void smSensGetValues3()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+  }
+
+  if(!sens.getValuesAG(&calData)) return;
+
+  mon.print((char *) "Values A = ");
+  sprintf(outValue,"%+5.3f ",calData.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calData.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calData.A.z);
+  mon.println(outValue);
+
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+void smSensGetValues4()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+  }
+
+  if(!sens.getValuesAG(&calData)) return;
+
+  mon.print((char *) "Values AG = ");
+  sprintf(outValue,"%+5.3f ",calData.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calData.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f   ",calData.A.z);
+  mon.print(outValue);
+
+  sprintf(outValue,"%+5.1f ",calData.G.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.1f ",calData.G.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.1f ",calData.G.z);
+  mon.println(outValue);
+
+
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+void smSensGetValues5()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+    sm.setTimeOut(1000);
+  }
+
+  if(sm.timeOut())
+  {
+    mon.println((char *) " Time Out");
+    sm.enter(smCheckSens);
+    return;
+  }
+
+  if(!sens.getValuesAG(&calData)) return;
+  sm.setTimeOut(1000);
+
+  mon.print((char *) "Values AGM = ");
+
+  sprintf(outValue,"%+5.3f ",calData.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calData.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f   ",calData.A.z);
+  mon.print(outValue);
+
+  sprintf(outValue,"%+5.1f ",calData.G.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.1f ",calData.G.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.1f   ",calData.G.z);
+  mon.print(outValue);
+
+  sens.getValuesM(&calValue);
+
+  sprintf(outValue,"%+5.3f ",calValue.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calValue.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calValue.z);
+  mon.println(outValue);
+
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+void smSensGetValues6()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+    sm.setTimeOut(1000);
+  }
+
+  if(sm.timeOut())
+  {
+    mon.println((char *) " Time Out");
+    sm.enter(smCheckSens);
+    return;
+  }
+
+  if(!sens.getValuesAG(&rawData)) return;
+  sm.setTimeOut(1000);
+
+  mon.print((char *) "Values AGM = ");
+
+  sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%4X   ",(unsigned short) rawData.valueAG.A.z);
+  mon.print(outValue);
+
+  sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.G.x);
+  mon.print(outValue);
+  sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.G.y);
+  mon.print(outValue);
+  sprintf(outValue,"%4X   ",(unsigned short) rawData.valueAG.G.z);
+  mon.println(outValue);
+
+  /*
+  sens.getValuesM(&calValue);
+
+  sprintf(outValue,"%+5.3f ",calValue.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calValue.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calValue.z);
+  mon.println(outValue);
+  */
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+
+void smSensGetValues7()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+    sm.setTimeOut(1000);
+  }
+
+  if(sm.timeOut())
+  {
+    mon.println((char *) " Time Out");
+    sm.enter(smCheckSens);
+    return;
+  }
+
+  if(!sens.getValuesAG(&rawData)) return;
+  sm.setTimeOut(1000);
+
+  mon.print((char *) "%~Values AGM = $");
+
+  sprintf(outValue,"#@%04X$",(unsigned short) rawData.valueAG.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"#A%04X$",(unsigned short) rawData.valueAG.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"#B%04X$",(unsigned short) rawData.valueAG.A.z);
+  mon.print(outValue);
+
+  sprintf(outValue,"#C%04X$",(unsigned short) rawData.valueAG.G.x);
+  mon.print(outValue);
+  sprintf(outValue,"#D%04X$",(unsigned short) rawData.valueAG.G.y);
+  mon.print(outValue);
+  sprintf(outValue,"#E%04X$",(unsigned short) rawData.valueAG.G.z);
+  mon.print(outValue);
+
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+
+void smSensGetSoaapValues()
+{
+  sm.enter(smSensGetValues7);
+}
+
+void smSensDebugValues()
+{
+  mon.print((char *) "Werte: toValueStatusAG=");
+  mon.print(sens.debGetDword(1));
+  mon.print((char *) "  toValueStatusM=");
+  mon.println(sens.debGetDword(2));
+  sm.enter(smCheckSens);
+}
+
+
+void smSensGetErrors()
+{
+  mon.print((char *) "Errors AG: AdrNak=");
+  mon.print(sens.errorCntAdrNakAG);
+  mon.print((char *) "  DataNak=");
+  mon.print(sens.errorCntDataNakAG);
+  mon.print((char *) "  Overrun=");
+  mon.print(sens.errorCntOverAG);
+
+  mon.print((char *) "  M: AdrNak=");
+  mon.print(sens.errorCntAdrNakM);
+  mon.print((char *) "  DataNak=");
+  mon.print(sens.errorCntDataNakM);
+  mon.print((char *) "  Overrun=");
+  mon.println(sens.errorCntOverM);
+  sm.enter(smCheckSens);
+}
+
+void smSensGetTimeOuts()
+{
+  mon.print((char *) "TimeOuts AG: TwiStat=");
+  mon.print(sens.toCntTwiStatusAG);
+  mon.print((char *) "  TwiData=");
+  mon.print(sens.toCntTwiDataAG);
+  mon.print((char *) "  Status=");
+  mon.print(sens.toCntStatusAG);
+
+  mon.print((char *) "  M: TwiStat=");
+  mon.print(sens.toCntTwiStatusM);
+  mon.print((char *) "  TwiData=");
+  mon.print(sens.toCntTwiDataM);
+  mon.print((char *) "  Status=");
+  mon.println(sens.toCntStatusM);
+  sm.enter(smCheckSens);
+}
+
+void smSensGetRunCounts()
+{
+  mon.print((char *) "RunCounts: ");
+  for(int i = 0; i < NrOfRunStates; i++)
+  {
+    mon.print((char *) " ");
+    mon.print(sens.runStateCntArray[i]);
+  }
+  mon.print((char *) "  Total=");
+  mon.println(sens.runStateCntTotal);
+  sm.enter(smCheckSens);
+}
+#endif // DebugTerminal
+
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/template_platformio.txt b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/template_platformio.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b87a0a9c91e3731b6e71725de1178b3651d42b5a
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/template_platformio.txt
@@ -0,0 +1,32 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM5
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33  -DsmnDEBUG ;-DSlaveACM3
+lib_deps = 
+	symlink://[Pfad_Repository]\libraries\BlePoll
+	symlink://[Pfad_Repository]\libraries\environment
+	symlink://[Pfad_Repository]\libraries\ComRingBuf
+	symlink://[Pfad_Repository]\libraries\LoopCheck
+	symlink://[Pfad_Repository]\libraries\MidiNotes
+	symlink://[Pfad_Repository]\libraries\Monitor
+	symlink://[Pfad_Repository]\libraries\nRF52840Gpio
+	symlink://[Pfad_Repository]\libraries\nRF52840Radio
+	symlink://[Pfad_Repository]\libraries\nRF52840Ser
+	symlink://[Pfad_Repository]\libraries\nRF52840Twi
+	symlink://[Pfad_Repository]\libraries\SensorLSM9DS1
+	symlink://[Pfad_Repository]\libraries\SoaapMsg
+	symlink://[Pfad_Repository]\libraries\StateMachine
+	;symlink://[Pfad_Repository]\libraries\SoaapComDue
diff --git a/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/test/README b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/test/README
new file mode 100644
index 0000000000000000000000000000000000000000..9b1e87bc67c90e7f09a92a3e855444b085c655a6
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/BLE_Slae_Test/test/README
@@ -0,0 +1,11 @@
+
+This directory is intended for PlatformIO Test Runner and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PlatformIO Unit Testing:
+- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/.vscode/extensions.json b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/.vscode/extensions.json
new file mode 100644
index 0000000000000000000000000000000000000000..080e70d08b9811fa743afe5094658dba0ed6b7c2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/.vscode/extensions.json
@@ -0,0 +1,10 @@
+{
+    // See http://go.microsoft.com/fwlink/?LinkId=827846
+    // for the documentation about the extensions.json format
+    "recommendations": [
+        "platformio.platformio-ide"
+    ],
+    "unwantedRecommendations": [
+        "ms-vscode.cpptools-extension-pack"
+    ]
+}
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/include/README b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/include/README
new file mode 100644
index 0000000000000000000000000000000000000000..194dcd43252dcbeb2044ee38510415041a0e7b47
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/include/README
@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/lib/README b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/lib/README
new file mode 100644
index 0000000000000000000000000000000000000000..6debab1e8b4c3faa0d06f4ff44bce343ce2cdcbf
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/lib/README
@@ -0,0 +1,46 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link into executable file.
+
+The source code of each library should be placed in a an own separate directory
+("lib/your_library_name/[here are source files]").
+
+For example, see a structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+|  |
+|  |--Bar
+|  |  |--docs
+|  |  |--examples
+|  |  |--src
+|  |     |- Bar.c
+|  |     |- Bar.h
+|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+|  |
+|  |--Foo
+|  |  |- Foo.c
+|  |  |- Foo.h
+|  |
+|  |- README --> THIS FILE
+|
+|- platformio.ini
+|--src
+   |- main.c
+
+and a contents of `src/main.c`:
+```
+#include <Foo.h>
+#include <Bar.h>
+
+int main (void)
+{
+  ...
+}
+
+```
+
+PlatformIO Library Dependency Finder will find automatically dependent
+libraries scanning project source files.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/platformio.ini b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/platformio.ini
new file mode 100644
index 0000000000000000000000000000000000000000..441ea1198fe389208a3e3e603d50c6418189de19
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/platformio.ini
@@ -0,0 +1,59 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\BlePoll
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\environment
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\ComRingBuf
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\LoopCheck
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\MidiNotes
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\Monitor
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Gpio
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Radio
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Ser
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Twi
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SensorLSM9DS1
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SoaapMsg
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+	
+[env:Logging]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\BlePoll
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\environment
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\ComRingBuf
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\LoopCheck
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\MidiNotes
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\Monitor
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Gpio
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Radio
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Ser
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Twi
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SensorLSM9DS1
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SoaapMsg
+	symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+monitor_filters =
+  default   ; Remove typical terminal control codes from input
+  time      ; Add timestamp with milliseconds for each new line
+  log2file  ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/src/main.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..816104a6c86541ac768c4828b1796d148cf00045
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/src/main.cpp
@@ -0,0 +1,707 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleMaster.ino
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                        P o l l i n g - M a s t e r
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. November 2021
+// Letzte Bearbeitung: 4. Februar 2022
+//
+//
+//Läuft nicht mit den aktuellen Versionen der Bibliotheken. Dateien sind im Projekt SoaapBleMaster_Test_2 zu finden
+
+#include  "Arduino.h"
+#include  "SoaapBleMaster.h"
+
+
+void devSendDataML(void);
+// ----------------------------------------------------------------------------
+LoopCheck     lc;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse LoopCheck
+// Darüber wird das Zeitverhalten gesteuert (Software-Timer) und geprüft
+
+// ----------------------------------------------------------------------------
+nRF52840Radio bleCom;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse nRF52840Radio
+// Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und
+// Empfangen von BLE-Beacons angesprochen.
+
+
+#define bleCycleTime 250
+// ----------------------------------------------------------------------------
+BlePoll       blePoll((IntrfRadio *) &bleCom, micros);
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse BlePoll
+// Darüber werden das Polling des Masters als auch die Antworten der Slaves
+// gesteuert. Es können Geräte entwickelt werden, die nur Master oder Slave
+// sind und solche mit Doppelfunktion, wenn kein expliziter Master
+// eingesetzt und das Netzwerk über Spontan-Master quasi dezentral
+// betrieben werden soll.
+// ----- Parameter ------------------------------------------------------------
+// <&bleCom>    Die Klasse (vom angenommenen Typ IntrfRadio), die die Daten-
+//              übertragung abwickelt. Hier wird eine Instanz von nRF52840Radio
+//              angebunden. Für andere Hardware kann eine entsprechende Klasse
+//              verwendet werden, die von IntrfRadio abgeleitet wurde.
+// <micros>     Eine Funktion, die die verstrichene Zeit in Mikrosekunden gibt.
+//              Damit werden Zeiten (z.B. Time-Out) berechnet.
+//              Wird hier der Wert NULL übergeben, dann werden die Zeiten aus
+//              dem Aufrufzyklus (bleCycleTime) in Mikrosekunden berechnet,
+//              was hier einer Auflösung von 250 Mikrosekunden entspricht.
+
+#define NrOfSlavesToPoll  5
+// Die Anzahl der Slaves, die der Master aufrufen soll (Polling).
+// Es wird grundsätzlich mit der Adresse 1 begonnen und nach dem Aufruf die
+// Adresse inkrementiert, also immer die Slaves Adr = 1 bis
+// Adr = NrOfSlavesToPoll+1 aufgerufen.
+// ACHTUNG!
+// Diese Zahl muss kleiner/gleich der in BlePoll.h definierten maximalen
+// Anzahl der Slaves (MAXSLAVE) sein, weil die Ressourcen darüber statisch
+// festgelegt werden.
+
+SerParams     ttyParams;
+// ----------------------------------------------------------------------------
+nRF52840Ser   tty;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse nRF52840Ser (UART)
+// Darüber werden die seriellen Schnittstellen (UARTE0 und UARTE1) des
+// nRF52840 bedient.
+// Die Parameter werden in einer Struktur <SerParams> über die Funktion
+// <begin(...)> gesetzt.
+
+#define       sndBufSize  256
+byte          sndBuffer[sndBufSize];
+// ----------------------------------------------------------------------------
+ComRingBuf    crb;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse <ComRingBuf>
+// Damit wird ein Ringpuffer aufgebaut, der eine serielle Schnittstelle bedient.
+// Der Speicher muss extra eingerichtet und mit der Funktion
+//  <setWriteBuffer(sndBufSize, sndBuffer)> übergeben werden.
+// Die Klasse für die serielle Schnittstelle muss von <IntrfSerial> abgeleitet
+// sein, die Instanz wird mit der Funktion <begin(...)> übergeben.
+
+#define appCycleTime 500
+StateMachine  ap(apInit, NULL, appCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für die
+// Anwendung (App) von SOAAP eingesetzt wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Mikrosekunden
+
+
+// ----------------------------------------------------------------------------
+SoaapMsg  sMsg;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse <SoaapMsg>
+// Damit werden SOAAP-spezifische Meldungen/Telegramme generiert und ausgewertet
+// und SOAAP-spezifische Datentypen und Parameter definiert.
+
+#ifdef DebugTerminal
+// ----------------------------------------------------------------------------
+// Zum Debuggen und weitere Analysen der Programmumgebung und Funktionstests
+// Es ist ein (richtiges) Terminal erforderlich, mit dem einzelnen Zeichen
+// direkt abgeschickt und die eintreffenden direkt angezeigt werden.
+// ----------------------------------------------------------------------------
+#define smCycleTime 5
+StateMachine  sm(smInit, NULL, smCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für allgemeine
+// Steuerungen, Überwachungen und zum Debugging verwendet wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Millisekunden
+
+Monitor       mon(modeEcho | modeNl,0,&lc);
+// Eine statische Instanz (mit Konstruktordaten) der Klasse Monitor
+// Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert
+// Unter Linux werden hier GtkTerm (siehe Internet) und
+// ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt.
+// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeigent,
+// weil damit keine direkte Kommunikation (getipptes Zeichen sofort gesendet)
+// möglich ist.
+// ----- Parameter ------------------------------------------------------------
+// <mode Echo>  Alle eintreffenden Zeichen werden sofort zurückgesendet
+// <mode NL>    Vor der Ausgabe des Prompt (M>) erfolgt CR/LF
+// <0>          Für Speicherzugriffe wird von 32 Bit ARM ausgegangen
+// <&lc>        Für Zeitüberwachungen und entsprechende statisctische Daten
+//              greift die Monitor-Klasse auf die LoopCheck-Klasse zu
+// ----------------------------------------------------------------------------
+#endif
+
+
+// ============================================================================
+void setup()
+// ============================================================================
+{
+  bleCom.begin();           // Initialisierung der Datenübertragung
+  //bleCom.setPower(0x08);     // Maximale Sendeleistung bei nRF52840
+  // TEST
+  bleCom.setPower(0x0FC);   // Reduzierte Sendeleistung beim Schreibtisch-Test
+
+  blePoll.begin(BlePoll::ctMASTER, NrOfSlavesToPoll, BlePoll::atDevSOAAP, 10000);
+  // Initialisierung des Polling mit folgenden Parametern:
+  // <BlePoll::ctMASTER>    Es wird ein Master eingerichtet
+  // <NrOfSlavesToPoll>     Anzahl gepollter Slaves (s.o.)
+  // <BlePoll::atSOAAP>     Spezielle Anwendung SOAAP
+  // <10000>                INT-Watchdog-Timeout beim Lesen in Mikrosekunden
+
+  blePoll.setEmptyPollParams(2000, 500, 2000);
+  // Setzen der Parameter für das leere Polling zur Feststellung der
+  // vorhandenen Slaves und Aufbau einer Poll-Liste für den Datenaustausch
+  // ----- Parameter ----------------------------------------------------------
+  // <2000>   Anzahl der Poll-Durchläufe, solange kein Slave gefunden wird
+  // <500>    Anzahl weiterer Durchläufe, nachdem wenigstens ein Slave gefunden ist
+  // <2000>   Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden
+
+  for(int i = 1; i <= NrOfSlavesToPoll; i++)
+    blePoll.setDataPollParams(i, 1, 10, 1000);
+  // Setzen der Parameter beim Datenpolling, für Slaves individuell
+  // ----- Parameter ----------------------------------------------------------
+  // <i>      Adresse des Slave (1-..)
+  // <1>      Priorität beim Aufruf, 0 = immer bis max 65535 = sehr selten
+  // <10>     minimale Priorität bei automatischer Prioritätsreduzierung
+  //          im Fall von Störungen (Time-Out)
+  // <1000>   Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden
+
+#ifdef DebugTerminal
+  //blePoll.stopEP();   // Das Polling muss extra gestartet werden
+    if(blePoll.stoppedEP())
+    {
+      blePoll.resumeEP();}
+#endif
+
+  // Initialisierung von serieller Schnittstelle und Ringpuffer
+  // --------------------------------------------------------------------------
+  ttyParams.inst    = 0;    // Instanzindex der Schnittstelle (0,1)
+  ttyParams.rxdPort = 1;    // Nummer des IO-Port mit RxD-Pin
+  ttyParams.rxdPin  = 10;   // Nummer des RxD-Pin am Port
+  ttyParams.txdPort = 1;    // Nummer des IO-Port mit TxD-Pin
+  ttyParams.txdPin  = 3;    // Nummer des TxD-Pin am Port
+  ttyParams.speed   = Baud115200;   // Enumerator für Bitrate
+  ttyParams.type    = stStd;        // Spannungsausgang
+
+  tty.begin(&ttyParams, (IntrfBuf *) &crb);
+  // Übergeben von Parametern und Referenz auf Ringpufferverwaltung
+  // für die Übergabe empfangener Zeichen
+
+  tty.startSend();    // Sendebetrieb aktivieren
+
+  crb.setWriteBuffer(sndBufSize, sndBuffer);
+  // Speicher an Ringpufferverwaltung übergeben
+
+  crb.begin((IntrfSerial *) &tty);
+  // Referenz auf Schnittstelle an Ringpufferverwaltung
+  // für die Übergabe zu sendender Zeichen
+}
+
+// ============================================================================
+void loop()
+// ============================================================================
+{
+  lc.begin();     // Muss am Anfang von LOOP aufgerufen werden
+  // --------------------------------------------------------------------------
+
+#ifdef DebugTerminal
+  mon.run();      // Der Monitor bekommt bei jedem Durchlauf die CPU
+#endif
+
+  // Alle 250 Mikrosekunden erfolgt der Aufruf des Ble-Polling
+  //
+  if(lc.timerMicro(lcTimer0, bleCycleTime, 0))
+    blePoll.run();
+  // ----- Parameter der Software-Timer ---------------------------------------
+  // <lcTimer0>   Id/Nummer des Timer, zur Zeit werden bis 10 Timer unterstützt
+  //              lcTimer0 bis lcTimer9 (einstellbar in LoopCheck.h)
+  // <bleCycleTime>   Ablaufzeit in Einheit des Timer-Typ (Micro/Milli)
+  //                  hier in Mikrosekunden (timerMicro)
+  // <0>          Anzahl der Wiederholungen, 0 = unbegrenzt
+
+  // Alle 500 Mikrosekunden erfolgt der Aufruf der Anwendung
+  //
+  if(lc.timerMicro(lcTimer1, appCycleTime, 0, 10000))
+    ap.run();
+
+
+#ifdef DebugTerminal
+  // Jede Sekunde erfolgt die Ausgabe einer Versionsmeldung
+  // das kann über c0 am Terminal abgeschaltet werden
+  //
+  if(lc.timerMilli(lcTimer2, 1000, 0))
+  {
+    //if(!mon.cFlag[0])
+      //mon.printcr((char *)"%@TestBleMaster (ttyACM0), Version 20220303");
+      //smWaitPolling();
+  }
+  // Die Zeichen %@ am Anfang steuern die Ausgabe bei AndroidMonTerm in ein
+  // Textfeld (Label) statt auf das Terminal-Display
+
+  // Alle 5 Millisekunden erfolgt der Aufruf der Zustandsmaschine
+  //
+  if(lc.timerMilli(lcTimer3, smCycleTime, 0))
+  {
+    sm.run();
+  }
+#endif
+
+  // --------------------------------------------------------------------------
+  lc.end();       // Muss vor dem Ende von LOOP aufgerufen werden
+}
+
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e   S O A A P - A n w e n d u n g  (ap)
+// ****************************************************************************
+//
+byte  apTmpByteArray[256];              // Zwischenspeicher für Zeichenfolgen
+int   apNrOfMeasBytes;                  // Anzahl der empfangenen Messwertbytes
+int   apNrOfCtrlBytes;                  // Anzahl der empfangenen Steuerbytes inkl count und path
+byte  apMeasByteArray[32];              // Zwischenspeicher für Messwerte
+byte  apCtrlByteArray[32];              // Zwischenspeicher für Steuerbytes
+byte  apSlaveList[NrOfSlavesToPoll];    // Merker für gepollte Slaves
+int   apNrOfSlaves;                     // Aktuelle Anzahl von Slaves
+int   curListIdx;                       // Aktueller Index für Slaveliste
+int   area;                             // Area des aktuellen Slave
+int   sMsgLen;                          // Länge einer SOAAP-Meldung
+int   slNr;                             // Slave-Nummer (Adresse)
+int   txNr;                             // Anzahl versendeter Zeichen
+
+SoaapApId sAppId;                       // Anwendungs-Id aus Sicht SOAAP
+PlpType   pAppId;                       // Anwendungs-Id aus Polling-Sicht
+
+#ifdef TEST001
+char testMsgBuf[256];
+#endif
+// ----------------------------------------------------------------------------
+// Initialisierungen
+//
+void apInit()
+{
+#ifdef TEST001
+  crb.putLine("Initialisierung");
+#endif
+
+  // Eventuelle Initialisierung
+  ap.enter(apWaitDE);     // in nächsten Zustand schalten
+}
+
+// ----------------------------------------------------------------------------
+// Warten, bis Datenaustausch Master/Slave erfolgt
+//
+void apWaitDE()
+{
+  if(!blePoll.DataExchange)
+    return;   // Verbleiben in diesem Zustand bis Leerpolling beendet
+
+  apNrOfSlaves = blePoll.getSlaveList(apSlaveList, NrOfSlavesToPoll);
+  // Ermitteln der angeschlossenen Slaves
+
+#ifdef TEST001
+  crb.putStr("Slaveliste\r\n");
+#endif
+
+  ap.enter(apWaitMeas);
+}
+
+// ----------------------------------------------------------------------------
+// Warten auf neuen Messwert von einem Slave
+//
+void apWaitMeas()
+{
+  // Ermitteln, ob einer der Slaves einen Messwert hat
+  //
+  for(curListIdx = 0; curListIdx < apNrOfSlaves; curListIdx++)
+  {
+    slNr = apSlaveList[curListIdx];
+    if(blePoll.measAvail(slNr)) break;
+  }
+  if(curListIdx == apNrOfSlaves) return;
+  // Wenn kein Slave neue Messwerte hat,
+  // dann im nächsten Zustandstakt Abfrage wiederholen
+
+#ifdef TEST001
+  crb.putStr("Messwerte\r\n");
+#endif
+
+  // Slave (curListIdx) hat Messwerte übermittelt
+  // diese werden mit dem nächsten Takt verarbeitet
+  ap.enter(apProcMeas);
+}
+
+// ----------------------------------------------------------------------------
+// Verarbeiten der Daten vom Slave
+//
+void apProcMeas()
+{
+#ifdef TEST001
+  if(ap.firstEnter())
+  {
+    slNr = apSlaveList[curListIdx];
+    sprintf(testMsgBuf,"Slave-Nr = %d\r\n",slNr);
+    crb.putStr(testMsgBuf);
+  }
+  //ap.enter(apWaitMeas);
+  //return;
+#endif
+
+  // Parameter und Daten für die SOAAP-Meldung holen
+  //
+  slNr = apSlaveList[curListIdx];
+  area = blePoll.getArea(slNr);
+  pAppId = blePoll.getAppId(slNr);
+  apNrOfMeasBytes = blePoll.getMeas(slNr, apMeasByteArray);
+  apNrOfCtrlBytes = blePoll.getCtrlM(slNr, apCtrlByteArray);
+
+#ifdef TEST001
+  ap.enter(apWaitMeas);
+  return;
+#endif
+
+  // Abbildung des Polling-Telegramm-Typs auf die SOAAP-Anwendungs-Id
+  //
+  switch(pAppId)
+  {
+    case plptMeas9:
+      sAppId = saiDefaultMeas;
+      break;
+
+    case plptMeas13:
+      sAppId = saiMaximalMeas;
+      break;
+
+    case plptMeas9Ctrl4:
+      sAppId = saiDefaultMeasCtrl;
+      break;
+
+    default:
+      sAppId = saiDefaultMeas;
+      break;
+  }
+
+  // Konstruktion der SOAAP-Meldung
+  //
+  //sMsgLen = sMsg.getMsgA(area, slNr, sAppId, (char *) apTmpByteArray, apMeasByteArray);
+  // Senden des Telegramm über serielle Schnittstelle
+  //
+  //txNr = crb.putStr((char *) apTmpByteArray);
+  // Auf nächsten Messwert von einem Slave warten
+  //
+  devSendDataML();
+  ap.enter(apWaitMeas);
+}
+
+void devSendDataML(void){
+    PlpMeas9Ptr resPtr;
+    short tmpShort;
+    SlavePtr slPtr = blePoll.getSlavePtr(1);
+    resPtr = (PlpMeas9Ptr) &slPtr->result;
+      for (int i = 0; i < 9; i++)
+      {
+        // tmpShort = (short) slPtr->result.meas[i];
+        tmpShort = (short)resPtr->meas[i];
+        mon.prints(tmpShort);
+        if(i<8)mon.cprint(' ');
+      }
+      mon.print("\n");
+}
+
+#ifdef DebugTerminal
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e   z u m   D e b u g g e n   (sm)
+// ****************************************************************************
+//
+dword   debDword;
+byte    tmpByteArray[256];
+
+
+void smInit()
+{
+  sm.enter(smCheckJobs);
+}
+
+// ----------------------------------------------------------------------------
+// Abfrage der Monitorschalter
+// ----------------------------------------------------------------------------
+//
+
+void smCheckJobs()
+{
+  if(mon.cFlag[1] && !mon.busy)
+    sm.enter(smDebDword);
+  else if(mon.cFlag[2] && !mon.busy)
+    sm.enter(smCtrlPolling);
+  else if(mon.cFlag[3] && !mon.busy)
+    sm.enter(smReadPollValues);
+  else if(mon.cFlag[4] && !mon.busy)
+    sm.enter(smCheckSer);
+}
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+void smDebDword()
+{
+  int idx;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "DebDword[");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn >= 0x30 && mon.lastKeyIn <= 0x39)
+  {
+    idx = mon.lastKeyIn & 0x0F;
+    mon.print(idx);
+    mon.print((char *) "]=");
+    debDword = blePoll.debGetDword(idx);
+    mon.println(debDword);
+    sm.resetEnter();
+  }
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[1] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Steuern des Polling-Prozesses
+// ----------------------------------------------------------------------------
+//
+
+TxStatistics txStatistics;
+
+void smCtrlPolling()
+{
+  dword   tmpDw;
+  short   tmpShort;
+  int     i;
+
+  PlpMeas9Ptr resPtr;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "polling ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  // --------------------------------------------------------------------------
+  if(mon.lastKeyIn == 'P' || mon.lastKeyIn == 'p')
+  {
+    if(blePoll.stoppedEP())
+    {
+      blePoll.resumeEP();
+      mon.println((char *) "fortgesetzt");
+      sm.resetEnter();
+    }
+    else
+    {
+    blePoll.stopEP();
+    sm.enter(smWaitPolling);
+    }
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'C' || mon.lastKeyIn == 'c')
+  {
+    blePoll.resetPollCounters();
+    mon.println((char *) "Zähler zurückgesetzt");
+    sm.resetEnter();
+  }
+
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'R' || mon.lastKeyIn == 'r')
+  {
+    mon.print((char *) "Radiopuffer = ");
+    bleCom.getPduMem(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'S' || mon.lastKeyIn == 's')
+  {
+    mon.print((char *) "Sendepuffer = ");
+    bleCom.getPduSent(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+    // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'K' || mon.lastKeyIn == 'k')
+  {
+    mon.print(slNr); mon.print((char *)"|");
+    for(int i= 0; i< apNrOfCtrlBytes; i++){
+      mon.print(apCtrlByteArray[i]);
+      mon.print((char *)" ");
+    }
+    mon.print((char *) "\n");
+    sm.resetEnter();
+  }
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'L' || mon.lastKeyIn == 'l')
+  {
+    mon.print((char *) "Slave-Liste: ");
+    int nrOfSlaves = blePoll.getSlaveList(tmpByteArray, 255);
+    mon.println(tmpByteArray, nrOfSlaves, ',');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'T' || mon.lastKeyIn == 't')
+  {
+    mon.print((char *) "TxStat [");
+    dword bleStat = blePoll.getStatistics(&txStatistics);
+    mon.print(bleStat);
+    mon.print((char *) "] ");
+    mon.print(txStatistics.mode); mon.cprint(' ');
+    mon.print(txStatistics.interrupts); mon.cprint(' ');
+    mon.print(txStatistics.recs); mon.cprint(' ');
+    mon.print(txStatistics.sendings); mon.cprint(' ');
+    mon.print(txStatistics.aliens); mon.cprint(' ');
+    mon.print(txStatistics.wrongs); mon.cprint(' ');
+    mon.print(txStatistics.pollAcks); mon.cprint(' ');
+    mon.print(txStatistics.pollNaks); mon.cprint(' ');
+    mon.print(txStatistics.crcErrors); mon.print("  s[ ");
+    mon.print(txStatistics.memDumpSnd,8,' '); mon.print("]  r[ ");
+    mon.print(txStatistics.memDumpRec,16,' '); mon.cprintln(']');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn >= '0' && mon.lastKeyIn <= '9')
+  {
+    int idx = mon.lastKeyIn & 0x0F;
+    SlavePtr slPtr = blePoll.getSlavePtr(idx);
+    PollStatePtr pPtr = blePoll.getPollPtr(slPtr->pIdx);
+
+    mon.print((char *) "Slave[");
+    mon.print(idx);
+    mon.print((char *) "] ");
+    mon.print(slPtr->cntTo); mon.cprint(' ');
+    mon.print(slPtr->cntNakEP); mon.cprint(' ');
+    mon.print(slPtr->cntAckDP); mon.cprint(' ');
+
+    if(slPtr->cntAckDP == 0)
+    {
+      if(slPtr->cntTo == 0)
+        tmpDw = slPtr->cntNakEP;
+      else
+        tmpDw = slPtr->cntNakEP / slPtr->cntTo;
+    }
+    else
+    {
+      if(slPtr->cntTo == 0)
+        tmpDw = slPtr->cntAckDP;
+      else
+        tmpDw = slPtr->cntAckDP / slPtr->cntTo;
+    }
+    mon.print(tmpDw); mon.cprint(' ');
+
+    resPtr = (PlpMeas9Ptr) &slPtr->result;
+
+    mon.print(slPtr->cntLostPdu); mon.cprint('|');
+    mon.print(slPtr->cntErrCrc); mon.cprint('|');
+    //mon.print(slPtr->result.measCnt); mon.cprint('|');
+    mon.print(resPtr->measCnt); mon.cprint('|');
+    mon.print(slPtr->cntLostMeas); mon.cprint(' ');
+
+    for(i = 0; i < 9; i++)
+    {
+      //tmpShort = (short) slPtr->result.meas[i];
+      tmpShort = (short) resPtr->meas[i];
+            mon.prints(tmpShort); mon.cprint(' ');
+    }
+    mon.print((char *) "  Poll[");
+    mon.print(slPtr->pIdx);
+    mon.print((char *) "] ");
+    mon.print(pPtr->status); mon.cprint(' ');
+    mon.println(pPtr->slIdx);
+    sm.resetEnter();
+  }
+
+
+
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[2] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+void smWaitPolling()
+{
+  if(!blePoll.stoppedEP()) return;
+
+  mon.println((char *) "angehalten");
+  sm.enter(smCtrlPolling);
+}
+
+// ----------------------------------------------------------------------------
+// Testen der seriellen Schnittstelle
+// ----------------------------------------------------------------------------
+//
+void smCheckSer()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "TestSer...");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[4] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+  else
+  {
+    crb.putChr(mon.lastKeyIn);
+    mon.cprint(mon.lastKeyIn);
+    mon.lastKeyIn = ':';
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+void smReadPollValues()
+{
+
+}
+
+#endif // DebugTerminal
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/template_platformio.txt b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/template_platformio.txt
new file mode 100644
index 0000000000000000000000000000000000000000..15fc69d85e05ee9d499f73ed91bde12711b55562
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/template_platformio.txt
@@ -0,0 +1,59 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+	
+[env:Logging]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+monitor_filters =
+  default   ; Remove typical terminal control codes from input
+  time      ; Add timestamp with milliseconds for each new line
+  log2file  ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/test/README b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/test/README
new file mode 100644
index 0000000000000000000000000000000000000000..9b1e87bc67c90e7f09a92a3e855444b085c655a6
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMasterMessdatenAusgabe/test/README
@@ -0,0 +1,11 @@
+
+This directory is intended for PlatformIO Test Runner and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PlatformIO Unit Testing:
+- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/.vscode/extensions.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/.vscode/extensions.json
new file mode 100644
index 0000000000000000000000000000000000000000..080e70d08b9811fa743afe5094658dba0ed6b7c2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/.vscode/extensions.json
@@ -0,0 +1,10 @@
+{
+    // See http://go.microsoft.com/fwlink/?LinkId=827846
+    // for the documentation about the extensions.json format
+    "recommendations": [
+        "platformio.platformio-ide"
+    ],
+    "unwantedRecommendations": [
+        "ms-vscode.cpptools-extension-pack"
+    ]
+}
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/README.md b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a38fa89c3f61ca00246497ef2b7ba9e35902a5ed
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/README.md
@@ -0,0 +1,12 @@
+Speicherort für PlatformIO projekte.
+
+Workflow:
+    -PlatformIO öffnen
+    -Projekt öffnen -> Projektordner wählen, in dem die platformio.ini liegt.
+    -platformio.ini anpassen:
+        Inhalt für die platformio.ini aus der template_platformio.txt kopieren.
+        Dabei den Pfad für die libraries für den jeweiligen Rechner anpassen.
+
+        
+Trotz implementierung in der .gitignore will git nachwievor die platformio.ini synchronisieren, obwohl das eigentlich nicht der Fall sein soll.
+Synchronisierung dieser ist aufgrund der unterschiedlichen Dateipfade nicht gewünscht.
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/include/README b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/include/README
new file mode 100644
index 0000000000000000000000000000000000000000..194dcd43252dcbeb2044ee38510415041a0e7b47
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/include/README
@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/lib/README b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/lib/README
new file mode 100644
index 0000000000000000000000000000000000000000..6debab1e8b4c3faa0d06f4ff44bce343ce2cdcbf
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/lib/README
@@ -0,0 +1,46 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link into executable file.
+
+The source code of each library should be placed in a an own separate directory
+("lib/your_library_name/[here are source files]").
+
+For example, see a structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+|  |
+|  |--Bar
+|  |  |--docs
+|  |  |--examples
+|  |  |--src
+|  |     |- Bar.c
+|  |     |- Bar.h
+|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+|  |
+|  |--Foo
+|  |  |- Foo.c
+|  |  |- Foo.h
+|  |
+|  |- README --> THIS FILE
+|
+|- platformio.ini
+|--src
+   |- main.c
+
+and a contents of `src/main.c`:
+```
+#include <Foo.h>
+#include <Bar.h>
+
+int main (void)
+{
+  ...
+}
+
+```
+
+PlatformIO Library Dependency Finder will find automatically dependent
+libraries scanning project source files.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/platformio.ini b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/platformio.ini
new file mode 100644
index 0000000000000000000000000000000000000000..e77e37f74cf92af39372d3f9a0c619877b28010b
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/platformio.ini
@@ -0,0 +1,59 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\BlePoll
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\environment
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\ComRingBuf
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\LoopCheck
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\MidiNotes
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\Monitor
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Gpio
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Radio
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Ser
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Twi
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SensorLSM9DS1
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SoaapMsg
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+	
+[env:Logging]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\BlePoll
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\environment
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\ComRingBuf
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\LoopCheck
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\MidiNotes
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\Monitor
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Gpio
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Radio
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Ser
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Twi
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SensorLSM9DS1
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SoaapMsg
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+monitor_filters =
+  default   ; Remove typical terminal control codes from input
+  time      ; Add timestamp with milliseconds for each new line
+  log2file  ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/BlePoll/BlePoll.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/BlePoll/BlePoll.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2b89ae3d67d527cf753ec12a685ac02e0bde3ae
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/BlePoll/BlePoll.cpp
@@ -0,0 +1,1624 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   BlePoll.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. September 2021
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Kommunikation
+// über BLE-Funkmodule auf niedriger Ebene, also dem direkten Telegrammaustausch.
+// Darauf aufbauend sollen mehrkanalige Messeinrichtungen mit möglichst
+// geringen Latenzzeiten entwickelt werden.
+//
+
+#include "BlePoll.h"
+
+// --------------------------------------------------------------------------
+// Textmakros zur Vereinfachung der Programmierung
+// --------------------------------------------------------------------------
+
+#define next(x) nextState = &BlePoll::x
+
+// --------------------------------------------------------------------------
+// Initialisierungen
+// --------------------------------------------------------------------------
+
+BlePoll::BlePoll(IntrfRadio *refRadio, dword inCycleMics)
+{
+  init(refRadio, inCycleMics, NULL);
+}
+
+BlePoll::BlePoll(IntrfRadio *refRadio, MicsecFuPtr inMicroFu)
+{
+  init(refRadio, 0, inMicroFu);
+}
+
+void BlePoll::init(IntrfRadio *refRadio, dword inCycleMics, MicsecFuPtr inMicroFu)
+{
+  radio = refRadio;
+  radio->setPacketParms(bptAdv);
+  radio->setAccessAddress(AdvAccAddr);
+  chn = adr = area = 0;
+  master = nak = eadr = false;
+  plMode = plmIdle;
+  plpType = plptEmpty;
+  micSec = inMicroFu;
+  cycleMics = inCycleMics;
+  cycleCnt = 0;
+  toValue = 0;
+  toSet = 0;
+  nextState = NULL;
+  slaveIdx = 0;
+  pollIdx = 0;
+  pollNr = 0;
+  maxAdr = MAXSLAVE;
+  curSlave = NULL;
+  cntAlien = 0;
+  cntWrong = 0;
+  cntAllNaks = 0;
+  cntWaitDisabled = 0;
+  cntPolling = 0;
+  cntAllRecs = 0;
+  cntAllTo = 0;
+  pollStopped = false;
+  pollStop = false;
+  recStopped = false;
+  recStop = false;
+  runCounter = 0;
+  newValue = false;
+  cbData = NULL;
+
+  for(int i = 1; i <= MAXSLAVE; i++)
+  {
+    slaveList[i].cntNakEP = 0;
+    slaveList[i].cntTo = 0;
+    slaveList[i].pIdx = 0;
+    slaveList[i].delayCnt = 5;
+    slaveList[i].newPdu = false;
+    slaveList[i].newMeas = false;
+    pollList[i].prioCnt = 0;
+    pollList[i].slIdx = 0;
+    pollList[i].status = 0;
+  }
+
+  DataExchange = false;
+}
+
+// ----------------------------------------------------------------------------
+void BlePoll::begin(ComType typeIn, int adrIn, AppType appType, dword watchDog)
+{
+  // TODO
+  // --------------------------------------------------------------------------
+  // Das muss nochmal völlig neu überarbeitet werden.
+  // Zur Zeit sind viele Redundanzen und teilweise Mehrdeutigkeiten enthalten,
+  // weil für jede Testanwendung spezifische Vorbereitungen gemacht wurden.
+  // --------------------------------------------------------------------------
+  //
+  wdTimeOut = watchDog;   // WatchDog-Time-Out in Mikrosekunden
+
+  if(typeIn == ctMASTER)
+    master  = true;
+  else
+    master = false;  void  resetPollCounters();
+
+
+  chn     = 0;          // 1. Bewerbungskanal
+  area    = 0;          // Default-Anwendungsbereich
+  eadr    = true;       // Start mit leerem Polling
+
+  // --------------------------------------------------------------------------
+  plMode  = plmEmpty;   // Leeres Polling (Adressenliste)
+  // --------------------------------------------------------------------------
+
+  if(master)
+  {
+    nak = true;         // Nak-Bit vom Master forciert leere Antwort
+    maxAdr = adrIn;
+    if(maxAdr > MAXSLAVE)
+      maxAdr = MAXSLAVE;
+    adr  = 1;
+    slaveIdx = adr;     // Reserve für getrennte Verwaltung von adr und slaveIdx
+    next(smInit);
+  }
+  else
+  {
+    nak = true;
+    adr = adrIn;
+    next(smInit);
+  }
+
+  if(appType == atSOAAP || appType == atTestSend || appType == atDevSOAAP)
+  {
+    pduOut.adr5 = 0x53;
+    pduOut.adr4 = 0x4F;
+    pduOut.adr3 = 0x41;
+
+    pduIn.adr5 = 0x53;
+    pduIn.adr4 = 0x4F;
+    pduIn.adr3 = 0x41;
+  }
+
+  if(appType == atTestSend)
+    plMode = plmTest;
+
+  pduOut.head = HeadS0B;
+  pduIn.head = HeadS0B;
+
+  pduOut.data[0] = 0;         // Pdu-Zähler (CNT)
+  pduIn.data[0] = 0;
+
+  pduOut.data[1] = appType;   // Pdu-Typ (TYPE)
+  pduIn.data[1] = appType;
+
+  if(appType == atSOAAP)
+  {
+    if(master)
+    {
+      valuePdu.appId = plptMeas9Ctrl4;
+      ctrlPdu.appId = plptCtrlX;
+      plMode = plmSoaapM;
+      fullCycle = true;
+    }
+    else
+    {
+      valuePdu.appId = plptMeas9Ctrl4;
+      ctrlPdu.appId = plptCtrlX;
+      plMode = plmSoaapS;
+    }
+  }
+  else if (appType == atDevSOAAP)
+  {
+    if(master)
+    {
+      valuePdu.appId = plptMeas13;
+      ctrlPdu.appId = plptCtrl2;
+      plMode = plmSoaapM;
+      fullCycle = true;
+    }
+    else
+    {
+      valuePdu.appId = plptMeas13;
+      ctrlPdu.appId = plptCtrl2;
+      plMode = plmSoaapS;
+    }
+  }
+
+  valuePdu.measCnt = 0;
+  valuePdu.counter = 0;
+  valuePdu.type = appType;
+}
+
+
+// --------------------------------------------------------------------------
+// Konfiguration
+// --------------------------------------------------------------------------
+//
+void BlePoll::setPollAddress(int chnIn, int adrIn, int areaIn, bool masterIn, bool eadrIn, bool nakIn)
+{
+  chn     = chnIn;
+  adr     = adrIn;
+  area    = areaIn;
+  master  = masterIn;
+  eadr    = eadrIn;
+  nak     = nakIn;
+}
+
+void BlePoll::setPduAddress()
+{
+  setPduAddress(&pduOut);
+}
+
+void BlePoll::setPduAddress(bcPduPtr pduPtr)
+{
+  pduPtr->adr0 = (byte) adr;
+  pduPtr->adr1 = (byte) (area & 0x3F);
+  if(nak) pduPtr->adr1 |= 0x40;
+  if(eadr) pduPtr->adr1 |= 0x80;
+  pduPtr->adr2 = (byte) chn;
+  if(master) pduPtr->adr2 |= 0x80;
+}
+
+void BlePoll::setEmptyPollParams(int cycleTotal, int cycleRun, dword timeOut)
+{
+  epCycleTotal  = cycleTotal;
+  epCycleRun    = cycleRun;
+  epTimeOut     = timeOut;
+}
+
+void BlePoll::setDataPollParams(int slAdr, int prio, int minPrio, dword timeOut)
+{
+  if(slAdr > MAXSLAVE) return;
+  slaveList[slAdr].prioSet = prio;
+  slaveList[slAdr].minPrio = minPrio;
+  slaveList[slAdr].timeOut = timeOut;
+}
+
+void BlePoll::setCbDataPtr(cbDataPtr cbPtr)
+{
+  cbData = cbPtr;
+}
+
+void BlePoll::setCbCtrlPtr(cbCtrlPtr cbPtr)
+{
+  cbCtrl = cbPtr;
+}
+
+
+dword smStartComESCnt;
+bcPdu recBeacon;
+int   lenBeacon = 0;
+
+// --------------------------------------------------------------------------
+// Hilfsfunktionen
+// --------------------------------------------------------------------------
+//
+void BlePoll::setTimeOut(dword value)
+{
+  if(micSec != NULL)
+  {
+    toSet = micSec();
+    toValue = value;
+  }
+  else
+  {
+    if(cycleMics > 1)
+      cycleCnt = value / cycleMics;
+    else
+      cycleCnt = value;
+  }
+}
+
+bool BlePoll::timeOut()
+{
+  if(micSec != NULL)
+  {
+    if((micSec() - toSet) > toValue)
+      return(true);
+    else
+      return(false);
+  }
+  else
+  {
+    if(cycleCnt > 0)
+      return(false);
+    else
+      return(true);
+  }
+}
+
+bool BlePoll::getValues(bcPduPtr pduPtr, PlpType appId)
+{
+  bool  retv = false;
+
+  switch (appId)
+  {
+    case plptMeas6:
+      pduPtr->len = sizeof(PlpMeas6) + 6;
+      break;
+
+    case plptMeas9Ctrl4:
+      pduPtr->len = sizeof(PlpM9C4) + 6;
+      break;
+  }
+  pduPtr->data[0]++;      // Pdu-Counter
+  pduPtr->data[1] = valuePdu.type;
+  pduPtr->data[2] = appId;
+
+  newValue = cbData(appId, &pduPtr->data[4]);
+
+  if(newValue)
+  {
+    retv = true;
+    pduPtr->data[3]++;              // measCnt
+  }
+  return(retv);
+}
+
+
+bool BlePoll::getCtrls(bcPduPtr pduPtr, PlpType appId)
+{
+  int   ctrlLen;
+
+  if(recBeacon.len > 6)
+    ctrlLen = recBeacon.len - 6;
+  else
+    ctrlLen = 4;
+
+  newCtrl = cbCtrl((PlpType) appId, &pduPtr->data[22], &recBeacon.data[0], ctrlLen);
+
+  return(newCtrl);
+}
+
+
+// --------------------------------------------------------------------------
+// Steuerung des Polling
+// --------------------------------------------------------------------------
+//
+
+// Aktuellen Betriebszustand einstellen
+//
+void BlePoll::start(PlMode inPlMode)
+{
+  oldPlMode = plMode;
+  plMode = inPlMode;
+  pollStop = true;
+}
+
+// Anhalten des leeren Polling
+//
+void BlePoll::stopEP()
+{
+  pollStop = true;
+}
+
+// Weiterlaufen des leeren Polling
+//
+void BlePoll::resumeEP()
+{
+  pollStop    = false;
+  pollStopped = false;
+}
+
+// Abfrage, ob gestoppt
+//
+bool BlePoll::stoppedEP()
+{
+  return(pollStopped);
+}
+
+// Anhalten des Empfangs beim Slave
+//
+void BlePoll::stopSR()
+{
+  recStop = true;
+}
+
+// Weiterlaufen des Empfangs beim Slave
+//
+void BlePoll::resumeSR()
+{
+  recStop     = false;
+  recStopped  = false;
+}
+
+// Abfrage, ob Slaveempfang gestoppt
+//
+bool BlePoll::stoppedSR()
+{
+  return(recStopped);
+}
+
+
+// Eintritt in die Zustandsmaschine
+//
+void BlePoll::run()
+{
+  runCounter++;
+  if(cycleCnt > 0) cycleCnt--;
+
+  if(nextState != NULL)
+    (this->*nextState)();
+}
+
+// --------------------------------------------------------------------------
+// Zugriff auf Polling-Informationen
+// --------------------------------------------------------------------------
+//
+int BlePoll::getSlaveList(byte *dest, int maxByte)
+{
+  int           slIdx;
+
+  for(int i = 1; i <= pollMaxNr; i++)
+  {
+    if(i == maxByte) break;
+    slIdx = pollList[i].slIdx;
+    dest[i-1] = slaveList[slIdx].adr;
+  }
+  return(pollMaxNr);
+}
+
+void  BlePoll::resetPollCounters()
+{
+  int           slIdx;
+  SlavePtr      slPtr;
+
+  for(int i = 1; i <= pollMaxNr; i++)
+  {
+    slIdx = pollList[i].slIdx;
+    slPtr = &slaveList[slIdx];
+    slPtr->cntAckDP = 0;
+    slPtr->cntErrCrc = 0;
+    slPtr->cntLostMeas = 0;
+    slPtr->cntLostPdu = 0;
+    slPtr->cntNakEP = 0;
+    slPtr->cntTo = 0;
+  }
+}
+
+
+
+
+// ****************************************************************************
+// Zustandsmaschine
+// ****************************************************************************
+//
+
+// ----------------------------------------------------------------------------
+// Verzweigung nach Anwendung (nach Anlauf)
+// ----------------------------------------------------------------------------
+//
+dword smInitCnt;
+
+void BlePoll::smInit()
+{
+  bleState = 100;
+  smInitCnt++;
+
+  switch(plMode)
+  {
+    case plmIdle:
+      break;
+
+    case plmTest:
+      next(smStartTest);
+      break;
+
+    case plmEmpty:
+      epCycleTotal = -1;
+      epCycleRun = -1;
+      next(smStartEP);
+      break;
+
+    case plmScan:
+      break;
+
+    case plmSoaapM:
+      if(pollStop)
+        pollStopped = true;
+      if(!pollStopped)
+        next(smStartEP);
+      break;
+
+    case plmSoaapS:
+      next(smStartComES);
+      break;
+
+    case plmXchg:
+      break;
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Verzweigung nach Anwendung (im Betrieb)
+// ----------------------------------------------------------------------------
+//
+dword smIdleCnt;
+
+void BlePoll::smIdle()
+{
+  bleState = 200;
+  smIdleCnt++;
+
+  switch(plMode)
+  {
+    case plmIdle:
+      break;
+
+    case plmTest:
+      next(smStartTest);
+      break;
+
+    case plmEmpty:
+      next(smStartEP);
+      break;
+
+    case plmScan:
+      if(master)
+        next(smReqComS);
+      break;
+
+    case plmXchg:
+      if(!master)
+        next(smStartComES);
+      break;
+
+    case plmSoaapM:
+      if(!pollStopped)
+        next(smStartEP);
+      break;
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Low Level Tests
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smStartTest()
+{
+  bleState = 500;
+
+  if(master)
+  {
+    nak = false;
+    adr = 1;
+    slaveIdx = adr;
+    setTimeOut(500000);
+  }
+  else
+  {
+    nak = true;
+  }
+  pduOut.len  = 6;
+  setPduAddress();
+  radio->setChannel(chn);
+  next(smWaitTest);
+}
+
+void BlePoll::smWaitTest()
+{
+  if(!timeOut()) return;
+  radio->disable(txmRead);
+  next(smLoopTest);
+}
+
+void BlePoll::smLoopTest()
+{
+  pduOut.adr0++;
+  radio->send(&pduOut, txmRead);
+  setTimeOut(500000);
+  next(smWaitTest);
+}
+
+
+
+// ----------------------------------------------------------------------------
+// L e e r e s   P o l l i n g
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smStartEP()
+{
+  bleState = 1000;
+
+  pduOut.len  = 6;          // Nur Adresse
+  radio->setChannel(chn);
+  pollMaxNr = 0;
+
+  nak = true;
+
+  if(master)
+  {
+    adr = 1;
+    slaveIdx = adr;         // Slave-Array[0] reserviert
+    pollIdx = 1;            // Poll-Array[0] reserviert
+    pollNr = 0;             // Anzahl in der Poll-Liste
+    next(smReqEadr);
+  }
+  else
+  {
+    next(smWaitEadr);
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Leeres Polling           M a s t e r
+// ----------------------------------------------------------------------------
+//
+
+void BlePoll::smReqEadr()
+{
+  bleState = 1100;
+
+  // Datenstruktur für den Slave definieren
+  //
+  curSlave = &slaveList[slaveIdx];    // Zeiger auf zu pollenden Slave
+  curSlave->adr  = adr;
+  curSlave->area = area;
+  curSlave->chn  = chn;
+
+  curPoll = &pollList[pollIdx];       // Zeiger auf freien Platz in Poll-Liste
+
+  setPduAddress();
+  setTimeOut(epTimeOut);
+
+  radio->getStatistics(&statistic);
+
+  radio->send(&pduOut, txmPoll);
+  cntPolling++;
+  next(smWaitNak);
+}
+
+
+void BlePoll::smWaitNak()
+{
+  bleState = 1110;
+
+  if(timeOut())
+  {
+    // Für die Adresse ist kein Teilnehmer vorhanden, oder die Übertragung ist gestört
+    //
+    radio->disable(txmPoll);
+
+    if(curSlave->pIdx != 0)
+    {
+      // Wenn der Teilnehmer bereits in die Poll-Liste eingetragen ist
+      // dann wird darin seine temporäre Abwesenheit markiert
+      pollList[(int) curSlave->pIdx].status &= ~psSlaveIsPresent;
+    }
+
+    // Der Time-Out-Zähler macht erkenntlich, wie stark sich Störungen auswirken
+    //
+    curSlave->cntTo++;
+    cntAllTo++;
+
+    // Nächste Adresse und zur Anforderung
+    //
+    adr++;
+    slaveIdx = adr;
+    if(adr > maxAdr)
+      next(smEndEP);
+    else
+      next(smReqEadr);
+    return;
+  }
+
+
+  if(radio->fin(txmPoll, &crcError))
+  {
+    // Auf dem Kanal wurde ein Datensatz (BLE-Beacon) empfangen
+    // und es werden die ersten 8 Byte (Header, Len und Adresse) geholt
+    //
+    cntAllRecs++;
+    radio->getRecData(&pduIn, 8);
+
+    if(pduIn.adr3 != pduOut.adr3 || pduIn.adr4 != pduOut.adr4 || pduIn.adr5 != pduOut.adr5)
+    {
+      // Wenn die höherwertigen 3 Byte der Adresse nicht mit der Anwendungskodierung
+      // übereinstimmen, dann ist es ein Fremd-Beacon.
+      // Diese werden gezählt und kennzeichnen, wie stark aktiv ein anderes
+      // BLE-Netzwerk in Reichweite ist.
+      //
+      cntAlien++;
+
+      // Nächste Adresse und zur Anforderung, nicht auf Time-Out warten
+      //
+      adr++;
+      slaveIdx = adr;
+      if(adr > maxAdr)
+        next(smEndEP);
+      else
+        next(smReqEadr);
+      return;
+    }
+
+    if(pduIn.adr0 != pduOut.adr0 || (pduIn.adr1 & 0x3F) != (pduOut.adr1 & 0x3F))
+    {
+      // Wenn die Teinehmernummer oder die Gebietsnummer falsch sind, dann ist
+      // möglicherweise ein weiterer Master aktiv, der fehlerhafterweise denselben
+      // Kanal verwendet.
+      // Auch dieses Ereignis wird gezäht.
+      cntWrong++;
+
+      // Nächste Adresse und zur Anforderung, nicht auf Time-Out warten
+      //
+      adr++;
+      slaveIdx = adr;
+      if(adr > maxAdr)
+        next(smEndEP);
+      else
+        next(smReqEadr);
+      return;
+    }
+
+    // Alles korrekt, der adressierte Teilnehmer hat rechtzeitig geantwortet
+    // Radio ist abgeschaltet
+    //
+
+    if(curSlave->pIdx != 0)
+    {
+      // Wenn der Teilnehmer bereits in die Poll-Liste eingetragen ist,
+      // dann wird er darin als aktuell anwesend markiert
+      //
+      pollList[(int) curSlave->pIdx].status |= psSlaveIsPresent;
+      pollNr++;
+    }
+    else
+    {
+      // Wenn nicht, wird der aktuelle Listeneintrag definiert
+      //
+      curPoll->status |= psSlaveIsPresent | psSlaveWasPresent;
+      curPoll->slIdx = slaveIdx;  // Querverweis zur Liste möglicher Teilnehmer
+      curSlave->pIdx = pollIdx;   // Und in der Liste auch ein Verweis zur Poll-Liste
+      pollIdx++;                  // Weiter mit nächstem Listenplatz
+      pollNr++;                   // Anzahl der beantworteten Pollings
+    }
+
+    // Die Nak-Antworten werden gezählt
+    //
+    curSlave->cntNakEP++; // Teilnehmerspezifisch
+    cntAllNaks++;         // und insgesamt
+
+    // Weiter mit nächstem Teilnehmer und nächster Adresse (TN-Nummer)
+    //
+    adr++;
+    slaveIdx = adr;
+
+    // Wenn die vorgegeben Endadresse erreicht ist
+    // dann zum Ende des Polldurchgangs über alle möglichen Teilnehmer,
+    // ansonsten nächsten Teilnehmer pollen
+    //
+    if(adr > maxAdr)
+      next(smEndEP);
+    else
+      next(smReqEadr);
+  }
+}
+
+
+void BlePoll::smEndEP()
+{
+  // Nach jedem vollständigen Polldurchlauf kann das Polling
+  // abgebrochen werden.
+  //
+  if(pollStop || pollStopped)
+  {
+    pollStopped = true;
+    next(smIdle);
+    return;
+  }
+
+  // Es werden die Maximalwerte der rechtzeitigen Antworten gebildet
+  //
+  if(pollNr > pollMaxNr)
+    pollMaxNr = pollNr;
+
+  if(pollMaxNr == 0)
+  {
+    // Wenn noch kein Teilnehmer angeschlossen ist (oder Kanal total gestört)
+    //
+    if(epCycleTotal > 0)
+    {
+      // dann wird der Pollvorgang so oft wie vorgegeben wiederholt
+      //
+      epCycleTotal--;
+      pollNr = 0;
+      pollIdx = 1;
+      adr = 1;
+      slaveIdx = adr;
+      next(smReqEadr);
+      return;
+    }
+    else if(epCycleTotal == 0)
+    {
+      // und anschließend der Idle-Zustand angenommen
+      next(smIdle);
+      return;
+    }
+  }
+  else
+  {
+    // Wenn wenigstens schon ein Teilnehmer geantwortet hat
+    //
+    if(epCycleRun > 0)
+    {
+      // dann wird der Pollvorgang auch so oft wie anderweitig vorgegeben wiederholt
+      //
+      epCycleRun--;
+      pollNr = 0;
+      //pollIdx = 1; falsch, pollIdx zeigt auf nächsten freien Platz
+      adr = 1;
+      slaveIdx = adr;
+      next(smReqEadr);
+      return;
+    }
+    else if(epCycleRun == 0)
+    {
+      // und anschließend die Datenübertragung gestartet
+      // oder das Polling ganz beendet
+      //
+      if(fullCycle)
+        next(smStartCom);
+      else
+        next(smIdle);
+      return;
+    }
+  }
+
+  // Nächster Poll-Lauf, wenn epCycleXXX noch nicht abgelaufen ist
+  // oder auf einen wert kleiner 0 gestellt wurde
+  //
+  pollNr = 0;
+  //pollIdx = 1; falsch, pollIdx zeigt auf nächsten freien Platz
+  adr = 1;
+  slaveIdx = adr;
+  next(smReqEadr);
+}
+
+// ----------------------------------------------------------------------------
+// Leeres Polling           S l a v e
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smWaitEadr()
+{
+  bleState = 1200;
+
+  if(!radio->disabled(txmRespE))
+  {
+    radio->disable(txmRespE);
+    cntWaitDisabled++;
+    return;
+  }
+
+  setPduAddress();
+  radio->send(&pduOut, txmRespE);
+  next(smEvalPoll);
+}
+
+void BlePoll::smEvalPoll()
+{
+  bleState = 1210;
+
+  radio->getStatistics(&statistic);
+  if(!radio->fin(txmRespE, &crcError)) return;
+  next(smWaitEadr);
+}
+
+// ----------------------------------------------------------------------------
+// D a t e n ü b e r t r a g u n g
+// ----------------------------------------------------------------------------
+//
+
+// Vorbereitung der Datenübertragung
+//
+void BlePoll::smStartCom()
+{
+  bleState = 2000;
+
+  if(pollStop || pollStopped) // Der Start der Datenübertragung kann
+  {                           // verzögert werden
+    pollStopped = true;
+    return;
+  }
+
+  // --------------------------------------------
+  // Auswahl des Funkkanals (Frequenz)
+  // --------------------------------------------
+  //
+  radio->setChannel(chn);
+
+  // --------------------------------------------
+  // Voreinstellungen für den Master
+  // --------------------------------------------
+  //
+  if(master)
+  {
+    // Aufbau der Polling-Liste
+    //
+    for(int i = 1; i <= pollMaxNr; i++)
+    {
+      int slIdx = pollList[i].slIdx;
+      pollList[i].prioCnt = slaveList[slIdx].prioSet;
+    }
+    pollIdx = 1;
+
+    // Vorbereitung der mit dem Polling übermittelten Daten
+    //
+    pduOut.len  = 13;                 // Adresse (6) + 7 Byte Steuerung
+    ctrlPdu.counter = 0;              // Zähler im Steuertelegramm
+    ctrlPdu.appId = plptMeas9Ctrl4;   // Info für Slave zur Antwort
+
+    next(smReqComS);
+  }
+  // --------------------------------------------
+  // Voreinstellungen für den Slave
+  // --------------------------------------------
+  //
+  else
+  {
+    nak = true;
+    next(smWaitEadr);
+  }
+
+  DataExchange = true;
+}
+
+// ----------------------------------------------------------------------------
+// Datenübertragung Master          S l a v e  - >  M a s t e r
+// ----------------------------------------------------------------------------
+//
+
+// M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M
+// Polling : Anfordern von Daten beim Slave
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smReqComS()
+{
+  bleState = 2100;
+
+  if(pollStop || pollStopped) // Das Polling kann
+  {                           // angehalten werden
+    pollStopped = true;
+    return;
+  }
+
+  // Es ist von einem vorherigen Funkempfang auszugehen
+  // Die Hardware muss erst ausgeschaltet werden
+  //
+  if(!radio->disabled(txmPoll))
+  {
+    radio->disable(txmPoll);
+    return;
+  }
+
+  // Der aufzufordernde Teilnehmer wird der Poll-Liste entnommen
+  //
+  curPoll = &pollList[pollIdx];
+
+  // Ein Aufruf erfolgt nur, wenn der Prioritätszähler auf 0 steht
+  // ansonsten wird er dekrementiert und der nächste Teilnehmer
+  // im nächsten Zustandslauf ausgewählt.
+  //
+  if(curPoll->prioCnt > 0)
+  {
+    curPoll->prioCnt--;
+    pollIdx++;
+    if(pollIdx > pollMaxNr)
+      pollIdx = 1;
+    return;
+  }
+
+  // Zugriff auf den Slave aus der Poll-Liste vorbereiten
+  //
+  slaveIdx = curPoll->slIdx;
+  curSlave = &slaveList[slaveIdx];
+
+  // Slave-spezifische Parameter setzen
+  //
+  eadr = false;         // Ist true, wenn Daten nur zum Slave übertragen werden
+  nak = false;          // Ist true, wenn keine Daten übertragen werden (empty poll)
+  adr = curSlave->adr;
+  area = curSlave->area;
+  setPduAddress();
+  setTimeOut(curSlave->timeOut);
+
+
+  // Statistic-Daten einholen für evt. Auswertung
+  //
+  radio->getStatistics(&statistic);
+
+  // Aufruf des Slave starten
+  //
+  radio->send(&pduOut, txmPoll);
+
+  cntPolling++;
+  next(smWaitAckComS);
+}
+
+// M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M
+// Warten auf die Antwort vom Slave
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smWaitAckComS()
+{
+  byte    tmpByte;
+  short   tmpShort;
+
+  // Zeiger zur spezifischen Betrachtung von Empfangsdaten
+  PlPduMeasPtr resPtr;
+
+  bleState = 2110;
+
+  if(timeOut())
+  {
+    // Wenn der Slave nicht antwortet (kann auch eine Störung sein),
+    // dann wird seine Priorität heruntergesetzt (Zählwert erhöht)
+    // und der nächste Slave aus der Poll-Liste angefragt
+    //  byte      oldPduCount;
+
+    curSlave->prioSet++;
+    if(curSlave->prioSet > curSlave->minPrio)
+      curSlave->prioSet = curSlave->minPrio;
+
+    curPoll->prioCnt = curSlave->prioSet;
+
+    curSlave->cntTo++;
+    pollIdx++;
+    if(pollIdx > pollMaxNr)
+      pollIdx = 1;
+
+    radio->disable(txmPoll);
+    next(smReqComS);
+    return;
+  }
+
+  if(radio->fin(txmPoll, &crcError))
+  {
+    cntAllRecs++;
+
+    // Wenn (irgend-) ein Beacon eingegangen ist,
+    // wird die maximale (BLE-Standard) Anzahl von Bytes kopiert
+    //
+    radio->getRecData(&pduIn, 39);
+
+    if(pduIn.adr3 != pduOut.adr3 || pduIn.adr4 != pduOut.adr4 || pduIn.adr5 != pduOut.adr5)
+    {
+      // Beacons aus fremdem Netzen werden nur gezählt und es wird weiter gewartet
+      //
+      cntAlien++;
+      pollIdx++;
+      if(pollIdx > pollMaxNr)
+        pollIdx = 1;
+
+      next(smReqComS);
+      return;
+    }
+
+    if(pduIn.adr0 != pduOut.adr0 || (pduIn.adr1 & 0x3F) != (pduOut.adr1 & 0x3F))
+    {
+      // Beacons mit falscher Slaveadresse werden ebenfalls nur gezählt
+      // Hier wird später die Rundrufübertragung implementiert
+      //
+      cntWrong++;
+      pollIdx++;
+      if(pollIdx > pollMaxNr)
+        pollIdx = 1;
+
+      next(smReqComS);
+      return;
+    }
+
+    // Antwort vom richtigen Teilnehmer ist eingegangen
+    //
+
+    if(crcError)
+    {
+      // Die Daten werden bei einem CRC-Fehler verworfen.
+      // Der Fehler wird gezählt und ist ein Hinweis auf fremde
+      // Funkaktivitäten
+      //
+      curSlave->cntErrCrc++;
+      pollIdx++;
+      if(pollIdx > pollMaxNr)
+        pollIdx = 1;
+
+      next(smReqComS);
+      return;
+    }
+
+    // Die Daten werden in der Slave-Struktur abgelegt
+    //
+    resPtr = (PlPduMeasPtr) &curSlave->result;
+
+    resPtr->counter  = pduIn.data[0];
+    resPtr->type     = pduIn.data[1];
+    resPtr->appId    = pduIn.data[2];
+    resPtr->measCnt  = pduIn.data[3];
+
+    // Die Inhalte sind abhängig von der <appId>
+    //
+    switch(resPtr->appId)
+    {
+      case plptMeas9Ctrl4:
+        ((PlpM9C4Ptr) resPtr)->meas[0]  = *(word *) &pduIn.data[4];
+        ((PlpM9C4Ptr) resPtr)->meas[1]  = *(word *) &pduIn.data[6];
+        ((PlpM9C4Ptr) resPtr)->meas[2]  = *(word *) &pduIn.data[8];
+        ((PlpM9C4Ptr) resPtr)->meas[3]  = *(word *) &pduIn.data[10];
+        ((PlpM9C4Ptr) resPtr)->meas[4]  = *(word *) &pduIn.data[12];
+        ((PlpM9C4Ptr) resPtr)->meas[5]  = *(word *) &pduIn.data[14];
+        ((PlpM9C4Ptr) resPtr)->meas[6]  = *(word *) &pduIn.data[16];
+        ((PlpM9C4Ptr) resPtr)->meas[7]  = *(word *) &pduIn.data[18];
+        ((PlpM9C4Ptr) resPtr)->meas[8]  = *(word *) &pduIn.data[20];
+        ((PlpM9C4Ptr) resPtr)->ctrlPath = pduIn.data[22];
+        ((PlpM9C4Ptr) resPtr)->procCnt  = pduIn.data[23];
+        ((PlpM9C4Ptr) resPtr)->ctrl[0]  = pduIn.data[24];
+        ((PlpM9C4Ptr) resPtr)->ctrl[1]  = pduIn.data[25];
+        break;
+
+      case plptMeas6:
+        ((PlpM9C4Ptr) resPtr)->meas[0]  = *(word *) &pduIn.data[4];
+        ((PlpM9C4Ptr) resPtr)->meas[1]  = *(word *) &pduIn.data[6];
+        ((PlpM9C4Ptr) resPtr)->meas[2]  = *(word *) &pduIn.data[8];
+        ((PlpM9C4Ptr) resPtr)->meas[3]  = *(word *) &pduIn.data[10];
+        ((PlpM9C4Ptr) resPtr)->meas[4]  = *(word *) &pduIn.data[12];
+        ((PlpM9C4Ptr) resPtr)->meas[5]  = *(word *) &pduIn.data[14];
+        ((PlpM9C4Ptr) resPtr)->meas[6]  = *(word *) &pduIn.data[16];
+        break;
+    }
+
+
+    // Zählen der verlorenen Telegramme und Messwerte
+    // beginnt um <delayCnt> Pollzyklen verzögert
+    //
+    if(curSlave->delayCnt == 0)
+    {
+      tmpByte = curSlave->result.counter - curSlave->oldPduCount;
+      if(tmpByte > 1)
+        curSlave->cntLostPdu += tmpByte - 1;
+
+      tmpByte = resPtr->measCnt - curSlave->oldMeasCount;
+      if(tmpByte != 0)
+        curSlave->newMeas = true;
+      if(tmpByte > 1)
+        curSlave->cntLostMeas += tmpByte - 1;
+    }
+    else curSlave->delayCnt--;
+
+    curSlave->oldPduCount = curSlave->result.counter;
+    curSlave->oldMeasCount = resPtr->measCnt;
+
+    curSlave->newPdu  = true;
+    curSlave->cntAckDP++;
+    curPoll->prioCnt = curSlave->prioSet;
+
+    pollIdx++;
+    if(pollIdx > pollMaxNr)
+      pollIdx = 1;
+
+    next(smReqComS);
+    return;
+  }
+}
+
+void BlePoll::smEndComS()
+{
+  if(pollStop || pollStopped)
+  {
+    pollStopped = true;
+    return;
+  }
+  // Von vorne (zur Zeit, Test)
+  //
+  adr = 1;
+  slaveIdx = adr;
+  next(smReqEadr);
+}
+
+// ----------------------------------------------------------------------------
+// Datenübertragung Master         M a s t e r  - >  S l a v e
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smReqComE()
+{
+  bleState = 4100;
+
+  if(!radio->disabled(txmRead))
+  {
+    radio->disable(txmRead);
+    return;
+  }
+
+  curSlave = &slaveList[slaveIdx];
+  curSlave->adr  = adr;
+  curSlave->area = area;
+  curSlave->chn  = chn;
+
+  setPduAddress();
+  //setTimeOut(2000);
+  // Test
+  setTimeOut(1000000);
+  radio->send(&pduOut, txmRead);
+  radio->getStatistics(&statistic);
+  cntPolling++;
+  next(smWaitNak);
+}
+
+void BlePoll::smWaitAckComE()
+{
+  bleState = 4110;
+
+  if(timeOut())
+  {
+    radio->disable(txmRead);
+    curSlave->cntTo++;
+    adr++;
+    slaveIdx = adr;
+    if(adr > maxAdr)
+      next(smEndEP);
+    else
+      next(smReqEadr);
+    return;
+  }
+
+
+  if(radio->fin(txmRead, &crcError))
+  {
+    radio->getRecData(&pduIn, 8);
+
+    if(pduIn.adr3 != pduOut.adr3 || pduIn.adr4 != pduOut.adr4 || pduIn.adr5 != pduOut.adr5)
+    {
+      cntAlien++;
+      radio->cont(txmRead);
+      return;
+    }
+
+    if(pduIn.adr0 != pduOut.adr0 || (pduIn.adr1 & 0x3F) != (pduOut.adr1 & 0x3F))
+    {
+      cntWrong++;
+      radio->cont(txmRead);
+      return;
+    }
+
+    radio->disable(txmRead);
+    curSlave->cntNakEP++;
+    cntAllNaks++;
+    adr++;
+    slaveIdx = adr;
+    if(adr > maxAdr)
+      next(smEndEP);
+    else
+      next(smReqEadr);
+  }
+  radio->getStatistics(&statistic);
+}
+
+void BlePoll::smEndComE()
+{
+  if(pollStop || pollStopped)
+  {
+    pollStopped = true;
+    return;
+  }
+  // Von vorne (zur Zeit, Test)
+  //
+  adr = 1;
+  slaveIdx = adr;
+  next(smReqEadr);
+}
+
+
+// S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S
+// ----------------------------------------------------------------------------
+// Datenübertragung Slave         M a s t e r  < - >  S l a v e
+// ----------------------------------------------------------------------------
+//
+
+// S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S
+// Vorbereitungen für den Empfang (Polling durch Master)
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smStartComES()
+{
+  bool  newValues;
+  bool  newCtrl;
+  byte  lenValues;
+  byte  appId;
+
+  bleState = 1310;
+  smStartComESCnt++;
+
+  if(recStop || recStopped)
+  {
+    recStopped = true;
+    return;
+  }
+
+  // Wenn keine Daten von der Anwendung zur Verfügung gestellt werden,
+  // dann macht der Betrieb hier keinen Sinn und der Slave geht in IDLE
+  //
+  if(cbData == NULL)
+  {
+    next(smIdle);
+    return;
+  }
+
+  // Falls der Sender noch nicht ausgeschaltet ist, muss gewartet werden
+  //
+  if(!radio->disabled(txmResp))
+  {
+    radio->disable(txmResp);
+    cntWaitDisabled++;
+    return;
+  }
+
+  // Vorbereiten des erwarteten Inhalts beim Polling durch den Master
+  //
+  nak = true;
+  eadr = true;
+  setPduAddress(&pduIn);
+  pduIn.len = 6;
+
+
+  // Vorbereiten des zu sendenden Inhalts als Antwort auf das Polling
+  //
+  nak = false;
+  eadr = false;
+  setPduAddress(&pduOut);
+
+  // Eintragen der Messwerte in das Sendetelegramm
+  //
+  if(lenBeacon == 0)            // Wenn noch kein Empfangszyklus vorliegt
+    appId = valuePdu.appId;     // dann wird der voreingestellte Satz gewählt
+  else
+    appId = recBeacon.data[2];  // ansonsten der speziell angeforderte
+
+  newValues = getValues(&pduOut, (PlpType) appId);
+
+  if((appId == plptMeas9Ctrl4) && (cbCtrl != NULL))
+    getCtrls(&pduOut, (PlpType) appId);
+
+  radio->setChannel(chn);
+  radio->send(&pduIn, &pduOut, txmResp, newValues);
+
+  setTimeOut(wdTimeOut);
+  next(smWaitComES);
+}
+
+// S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S
+void BlePoll::smWaitComES()
+{
+  bleState = 1320;
+
+  radio->getStatistics(&statistic);
+  if(timeOut())
+  {
+    next(smStartComES);
+    return;
+  }
+
+  if(!radio->fin(txmResp, &crcError)) return;
+  //
+  // Übertragung beendet, Daten empfangen (polling) und versendet (response)
+  //
+  //lenBeacon = radio->getRecData(&recBeacon, txmResp, sizeof(recBeacon));
+  next(smStartComES);
+}
+
+// --------------------------------------------------------------------------
+// Anwenderfunktionen
+// --------------------------------------------------------------------------
+//
+
+// neue Steuerungsdaten für einen Slave
+
+void BlePoll::updControl(int adr, byte *ctrlList, int nr)
+{
+  if(adr <= 0) return;
+  if(adr >= MAXSLAVE) return;
+  if(nr <= 1) return;
+  if(nr > 27) return;
+
+  SlavePtr  slavePtr = &slaveList[adr];
+  PlpCtrl27Ptr ctrlPtr = (PlpCtrl27Ptr) &slavePtr->control;
+  for(int i = 0; i < nr; i++)
+    ctrlPtr->ctrl[i] = ctrlList[i];
+  ctrlPtr->ctrlCnt++;
+  slavePtr->rspOk = false;
+}
+
+// Feststellenn, ob Übertragung der Steuerungsdaten erfolgt ist
+
+bool BlePoll::ackTrans(int adr)
+{
+  if(adr <= 0) return(false);
+  if(adr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[adr];
+  return(slavePtr->rspOk);
+}
+
+// Feststellen, ob Steuerungsdaten beim Slave verarbeitet sind
+
+bool BlePoll::ackControl(int adr)
+{
+  if(adr <= 0) return(false);
+  if(adr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[adr];
+  PlpCtrl27Ptr ctrlPtr = (PlpCtrl27Ptr) &slavePtr->control;
+  if(ctrlPtr->ctrlCnt == slavePtr->rspCtrlCount)
+    return(true);
+  else
+    return(false);
+}
+
+// ----------------------------------------------------------------------------
+// Zugriff auf Slavedaten über die Adresse
+// ----------------------------------------------------------------------------
+//
+
+// Feststellen, ob ein Slave neue Messwerte hat
+//
+bool  BlePoll::measAvail(int slAdr)
+{
+  if(slAdr < 1) return(false);
+  if(slAdr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[slAdr];
+
+  if(!slavePtr->newMeas)
+    return(false);
+
+  slavePtr->newMeas = false;
+  return(true);
+}
+
+// Auslesen der Netzwerk-Area
+//
+int BlePoll::getArea(int slAdr)
+{
+  if(slAdr < 1) return(false);
+  if(slAdr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[slAdr];
+
+  return(slavePtr->area);
+}
+
+// Auslesen der AppId aus Sicht der Klasse BlePoll
+//
+PlpType BlePoll::getAppId(int slAdr)
+{
+  if(slAdr < 1) return(plptError);
+  if(slAdr >= MAXSLAVE) return(plptError);
+
+  SlavePtr  slavePtr = &slaveList[slAdr];
+
+  return((PlpType) slavePtr->result.plData[0]);
+}
+
+// Auslesen der Messwerte
+//
+int BlePoll::getMeas(int slAdr, byte *dest)
+{
+  int     anzByte;
+  PlpType appId;
+
+  if(slAdr < 1) return(false);
+  if(slAdr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[slAdr];
+
+  appId = (PlpType) slavePtr->result.plData[0];
+
+  switch(appId)
+  {
+    case plptMeas6:
+      anzByte = 12;
+      break;
+
+    case plptMeas9:
+      anzByte = 18;
+      break;
+
+    case plptMeas9Ctrl4:
+      anzByte = 22;
+      break;
+
+    case plptMeas13:
+      anzByte = 26;
+      break;
+
+    default:
+      anzByte = 18;
+      break;
+  }
+
+  for (int i = 0; i < anzByte; i++)
+  {
+    dest[i] = slavePtr->result.plData[i+2];
+  }
+
+  return(anzByte);
+}
+
+int BlePoll::getCtrlM(int slAdr, byte *dest){
+  int     anzByte;
+  PlpType appId;
+
+  if(slAdr < 1) return(false);
+  if(slAdr >= MAXSLAVE) return(false);
+
+  
+  SlavePtr  slavePtr = &slaveList[slAdr];
+  appId = (PlpType) slavePtr->result.plData[0];
+
+  switch(appId)
+  {
+    case plptMeas6:
+      anzByte = 0;
+      break;
+
+    case plptMeas9:
+      anzByte = 0;
+      break;
+
+    case plptMeas9Ctrl4:
+      anzByte = 4;
+      break;
+
+    case plptMeas13:
+      anzByte = 0;
+      break;
+
+    default:
+      anzByte = 0;
+      break;
+  }
+
+  for (int i = 0; i < anzByte; i++)
+  {
+    dest[i] = slavePtr->result.plData[i+20];
+  }
+
+  return(anzByte);
+}
+
+
+// --------------------------------------------------------------------------
+// Debugging
+// --------------------------------------------------------------------------
+//
+dword BlePoll::debGetDword(int idx)
+{
+  dword retv = 0;
+
+  switch(idx)
+  {
+    case 0:
+      retv = plMode;
+      break;
+
+    case 1:
+      retv = cntAllRecs;
+      break;
+
+    case 2:
+      retv = cntAllNaks;
+      break;
+
+    case 3:
+      retv = cntAllTo;
+      break;
+
+    case 4:
+      retv = cntAlien;
+      break;
+
+    case 5:
+      retv = cntWrong;
+      break;
+
+    case 6:
+      retv = statistic.pollAcks;
+      break;
+
+    case 7:
+      retv = statistic.pollNaks;
+      break;
+
+    case 8:
+      retv = bleState;
+      break;
+
+    case 9:
+      retv = radio->getState();
+      break;
+  }
+
+  return(retv);
+}
+
+dword BlePoll::getStatistics(TxStatisticsPtr dest)
+{
+  *dest = statistic;
+  return(bleState);
+}
+
+
+SlavePtr      BlePoll::getSlavePtr(int idx)
+{
+  return(&slaveList[idx]);
+}
+
+PollStatePtr  BlePoll::getPollPtr(int idx)
+{
+  return(&pollList[idx]);
+}
+
+
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/BlePoll/BlePoll.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/BlePoll/BlePoll.h
new file mode 100644
index 0000000000000000000000000000000000000000..721d22c5c1b2fd65fc1415d7707fb2d93383e036
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/BlePoll/BlePoll.h
@@ -0,0 +1,513 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   BlePoll.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. September 2021
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Kommunikation
+// über BLE-Funkmodule auf niedriger Ebene, also dem direkten Telegrammaustausch.
+// Darauf aufbauend sollen mehrkanalige Messeinrichtungen mit möglichst
+// geringen Latenzzeiten entwickelt werden.
+//
+
+#ifndef BlePoll_h
+#define BlePoll_h
+// ----------------------------------------------------------------------------
+
+#include "stddef.h"
+#include "string.h"
+#include "arduinoDefs.h"
+#include "bleSpec.h"
+#include "IntrfRadio.h"
+
+#define MAXSLAVE  100
+
+// Betriebsmodus (Polling und Slave)
+//
+typedef enum _PlMode
+{
+  plmIdle,        // Ruhezustand, Gerät nicht im Netz aktiv
+  plmTest,        // Low Level Tests
+  plmEmpty,       // Leeres Polling (Aufbau Adressliste)
+  plmScan,        // Daten aller aktiven Teilnehmer holen (Master)
+  plmSoaapM,      // Vollständiger Betrieb SOAAP (Master)
+  plmSoaapS,      // Vollständiger Betrieb SOAAP (Slave)
+  plmXchg         // Daten übertragen (Slave, beide Richtungen)
+} PlMode;
+
+// Grundsätzliche Datenstruktur für die Nutzdaten (ohne 6 Bytes Adresse)
+//
+typedef struct _PlPduBase   // maximale Länge Beacon = 31 Bytes
+{
+  byte  counter;      // zyklischer Telegrammmzähler
+  byte  type;         // Kennzeichnung der Datenstruktur (AppType)
+  byte  plData[29];   // weitere spezifische Nutzdaten
+} PlPduBase, *PlPduBasePtr;
+
+// Grundsätzliche Datenstruktur für Messwerte (ohne 6 Bytes Adresse)
+//
+typedef struct _PlPduMeas   // maximale Länge Beacon = 31 Bytes
+{
+  byte  counter;      // zyklischer Telegrammmzähler
+  byte  type;         // Kennzeichnung der Datenstruktur (AppType)
+  byte  appId;        // Kennzeichnung für Dateninhalte (PlpType)
+  byte  measCnt;      // Zähler für Messwertaktualisierung
+  byte  plData[27];   // weitere spezifische Nutzdaten
+} PlPduMeas, *PlPduMeasPtr;
+
+// Erweiterte Datenstruktur für die Nutzdaten (ohne 6 Bytes Adresse)
+// zur Zeit noch nicht genutzt
+//
+typedef struct _PlPduExtd   // grundsätzliche maximale Länge = 249 Bytes
+{
+  byte  counter;      // zyklischer Telegrammmzähler
+  byte  type;         // Kennzeichnung der Datenstruktur (AppType)
+  byte  plData[247];  // weitere spezifische Nutzdaten
+} PlPduExtd, *PlPduExtdPtr;
+
+// Datentypen (appId in plPduBase)
+//
+typedef enum _PlpType
+{
+  plptError,        // Fehler erkannt
+  plptEmpty,        // Leeres Telegramm (nur adresse)
+  plptBasic,        // Grundlegende Bytestruktur
+  plptFullMeas,     // Maximale Belegung mit 16-Bit Messwerten (word)
+  plptMeas3,        // 3 Messwerte (1 Raumsensor)
+  plptMeas6,        // 6 Messwerte (2 Raumsensoren)
+  plptMeas9,        // 9 Messwerte (3 Raumsensoren)
+  plptMeas9Ctrl4,   // 9 Messwerte + 4 Byte Steuerung
+  plptMeas10Ctrl4,  // 10 Messwerte + 4 Byte Steuerung
+  plptMeas12,       // 12 Messwerte (9 + 6 Byte Extradaten)
+  plptMeas13,       // 13 Messwerte (9 + 8 Byte Extradaten)
+  plptMeasX,        // Variable Anzahl Messwerte
+  plptCtrl0,        // Keine Steuerung
+  plptCtrl2,        // 2 Byte Steuerung
+  plptCtrl27,       // 27 Byte Steuerung
+  plptCtrlX,        // Variable Anzahl Steuerbytes
+  plptMsg           // (Quittierte) Meldung an Slave
+} PlpType, *PlpTypePtr;
+
+// Spezifische Datenstrukturen
+//
+typedef struct _PlpFullMeas   // Ausnahme für vordefinierte Spezialfälle
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  word    meas[14];   // Liste von 14 Messwerten
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    align;      // Wird nicht gesendet, kennzeichnet Alignement
+} PlpFullMeas, *PlpFullMeasPtr;
+
+typedef struct _PlpMeas3      // Länge 10 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[3];    // Liste von 3 Messwerten
+} PlpMeas3, *PlpMeas3Ptr;
+
+typedef struct _PlpMeas6      // Länge 16 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[6];    // Liste von 6 Messwerten
+} PlpMeas6, *PlpMeas6Ptr;
+
+typedef struct _PlpMeas9      // Länge 22 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[9];    // Liste von 9 Messwerten
+} PlpMeas9, *PlpMeas9Ptr;
+
+typedef struct _PlpM9C4      // Länge 26 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[9];    // Liste von 9 Messwerten
+  byte    ctrlPath;   // Steuerungspfad (für Verzweigungen/Funktionen)
+  byte    procCnt;    // Prozesszähler
+  byte    ctrl[2];    // Steuerungsdaten
+} PlpM9C4, *PlpM9C4Ptr;
+
+typedef struct _PlpMeas12      // Länge 28 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[12];   // Liste von 12 Messwerten
+} PlpMeas12, *PlpMeas12Ptr;
+
+typedef struct _PlpMeas13      // Länge 30 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[13];   // Liste von 13 Messwerten
+} PlpMeas13, *PlpMeas13Ptr;
+
+typedef struct _PlpCtrl2        // Länge 7 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    ctrlCnt;    // Zähler für Kommandoaktualisierung
+  byte    procCnt;    // Zähler für Prozessaktualisierung
+  byte    ctrl[2];    // Liste von 2 Steuerbytes
+} PlpCtrl2, *PlpCtrl2Ptr;
+
+typedef struct _PlpCtrl27        // Länge 31 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    ctrlCnt;    // Zähler für Kommandoaktualisierung
+  byte    procCnt;    // Zähler für Prozessaktualisierung
+  byte    ctrl[26];   // Liste von bis zu 26 Steuerbytes
+} PlpCtrl27, *PlpCtrl27Ptr;
+
+// Identifikator für die Art der Daten
+//
+typedef enum _MeasId
+{
+  app               // Gestaltung/Bedeutung der Daten aus Anwendung
+} MeasId, *MeasIdPtr;
+
+typedef struct _Slave
+{
+  dword     timeOut;        // Wartezeit beim Polling in Mikrosekunden
+  dword     cntTo;          // Zähler für ausbleibende Antworten
+  dword     cntErrCrc;      // Zähler für CRC-Fehler bei der Übertragung
+  dword     cntNakEP;       // Zähler für NAK-Antworten beim Empty-Polling
+  dword     cntAckDP;       // Zähler für ACK-Antworten beim Data-Polling
+  dword     cntLostPdu;     // Zähler für verlorene Telegramme
+  dword     cntLostMeas;    // Zähler für verlorene Messwerte
+  dword     delayCnt;       // Verzögerung (Polldurchläufe) vor Fehlerzählung
+  byte      adr;            // Adresse (Nummer) des Slave (1-255)
+  byte      area;           // Einsatzgebiet des Slave (Adresserweiterung)
+  byte      chn;            // Aktueller Übertragungskanal (0-39)
+  byte      pIdx;           // Index in der aktuellen Pollingliste
+  word      prioSet;        // Anfangspriorität (rel. Häufigkeit) beim Polling
+  word      minPrio;        // Minimale Priorität (maximale Prioritätszahl)
+  PlPduBase result;         // Daten vom Slave
+  PlPduBase control;        // Daten zum Slave
+  bool      newPdu;         // Kennzeichnung für neues Telegramm
+  bool      rspOk;          // Rücksetz-Kennnzeichnung für neues Telegramm
+  bool      newMeas;        // Kennzeichnung für neuen Messwert
+  byte      oldPduCount;    // Merker für die Telegrammüberwachung
+  byte      oldMeasCount;   // Merker für die Messwertüberwachung
+  byte      rspCtrlCount;   // Merker für Steuerungsüberwachung
+} Slave, *SlavePtr;
+
+
+typedef struct _PollInfo
+{
+  dword   aliens;     // Anzahl der netzfremden Aktivitäten
+  dword   wrongs;     // Anzahl ungewünschter Netzaktivitäten
+} PollInfo, *PollInfoPtr;
+
+
+typedef struct _PollState
+{
+  byte    slIdx;      // Index in der Slave-Liste
+  byte    status;     // Zustand
+  word    prioCnt;    // Prioritätszähler
+} PollState, *PollStatePtr;
+
+typedef bool (*cbDataPtr)(PlpType dataType, byte *dest);
+typedef bool (*cbCtrlPtr)(PlpType plpType, byte *dest, byte *src, int sSize);
+
+#define psSlaveWasPresent 0x01
+#define psSlaveIsPresent  0x02
+
+// ----------------------------------------------------------------------------
+//                            B l e P o l l
+// ----------------------------------------------------------------------------
+class BlePoll
+{
+public:
+  // -------------------------------------------------------------------------
+  // Öffentliche Datentypen
+  // -------------------------------------------------------------------------
+  //
+  typedef enum _ComType
+  {
+    ctMASTER,
+    ctSLAVE,
+    ctHybrid
+  } ComType;
+
+  // Identifikator für die Anwendung
+  //
+  typedef enum _AppType
+  {
+    atDefault,        // Standard-Default-Anwendung
+    atTestSend,       // einfacher Sendetest (Soaap)
+    atSOAAP,          // Steuerung optischer und akustischer Ausgaben für Performance-Künstler
+    atDevSOAAP,       // Entwicklerbetrieb für SOAAP
+    atDHA             // Dezentrale Hausautomatisierung
+  } AppType;
+
+  // --------------------------------------------------------------------------
+  // Öffentliche Daten
+  // --------------------------------------------------------------------------
+  //
+  bool    DataExchange;
+
+private:
+  // -------------------------------------------------------------------------
+  // Private Datentypen
+  // -------------------------------------------------------------------------
+  //
+
+  typedef void (BlePoll::*cbVector)(void);
+  typedef dword (*MicsecFuPtr)(void);
+
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  IntrfRadio    *radio;
+  bcPdu         pduOut;
+  bcPdu         pduIn;
+  cbVector      nextState;
+  MicsecFuPtr   micSec;
+  cbDataPtr     cbData;
+  cbCtrlPtr     cbCtrl;
+  dword         toSet;
+  dword         toValue;
+  dword         cycleMics;
+  dword         cycleCnt;
+  dword         wdTimeOut;
+
+  int           chn;
+  int           adr;
+  int           area;
+  bool          master;
+  bool          eadr;
+  bool          nak;
+  bool          crcError;
+
+  PlMode        plMode;
+  PlMode        oldPlMode;
+  PlpType       plpType;
+
+  Slave         slaveList[MAXSLAVE+1];
+  SlavePtr      curSlave;
+  int           slaveIdx; // ist z.Zt. identisch mit Slaveadresse adr
+  PollState     pollList[MAXSLAVE+1];
+  PollStatePtr  curPoll;
+  int           pollIdx;
+  int           pollNr;
+  int           pollMaxNr;
+
+  int           maxAdr;
+  dword         cntPolling;
+  dword         cntAllRecs;
+  dword         cntAllTo;
+  bool          pollStop;
+  bool          pollStopped;
+
+  dword         cntAllNaks;
+  dword         cntAlien;
+  dword         cntWrong;
+  dword         cntWaitDisabled;
+
+  dword         bleState;
+  dword         runCounter;
+  bool          recStop;
+  bool          recStopped;
+
+  TxStatistics  statistic;
+  PlPduMeas     valuePdu;
+  PlpCtrl27     ctrlPdu;
+  bool          newValue;
+  bool          newCtrl;
+
+  // Einstellungen für den Anwendungsbetrieb
+  //
+  bool          fullCycle;      // Vollständige Anwendung (EP & Data)
+  int           epCycleTotal;   // Anzahl der leeren Pollings gesamt
+  int           epCycleRun;     // Anzahl der leeren Pollings nach Kontakt
+  dword         epTimeOut;      // Time-Out in Mikrosekunden
+
+
+  // --------------------------------------------------------------------------
+  // Lokale Funktionen
+  // --------------------------------------------------------------------------
+  //
+  void setPduAddress();
+  void setPduAddress(bcPduPtr pduPtr);
+  void setTimeOut(dword value);
+  bool timeOut();
+  bool getValues(bcPduPtr pduPtr, PlpType appId);
+  bool getCtrls(bcPduPtr pduPtr, PlpType appId);
+
+
+  // Zustandsmaschine
+  // -----------------------------
+  void smInit();
+  void smIdle();
+
+  // Leeres Polling Master
+  //
+  void smStartEP();
+  void smReqEadr();
+  void smWaitNak();
+  void smEndEP();
+
+  // Leeres Polling Slave
+  //
+  void smWaitEadr();
+  void smEvalPoll();
+
+  // Datenübertragung
+  //
+  void smStartCom();
+
+  // Master: Master -> Slave
+  //
+  void smReqComE();
+  void smWaitAckComE();
+  void smEndComE();
+
+  // Master: Slave -> Master
+  //
+  void smReqComS();
+  void smWaitAckComS();
+  void smEndComS();
+
+  // Slave: Master <-> Slave
+  //
+  void smStartComES();
+  void smWaitComES();
+  void smEvalComES();
+
+  // Test
+  //
+  void smStartTest();
+  void smWaitTest();
+  void smLoopTest();
+
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+  BlePoll(IntrfRadio *refRadio, dword inCycleMics);
+  BlePoll(IntrfRadio *refRadio, MicsecFuPtr inMicroFu);
+  void init(IntrfRadio *refRadio, dword inCycleMics, MicsecFuPtr inMicroFu);
+
+  void begin(ComType typeIn, int adrIn, AppType appType, dword watchDog);
+  void setCbDataPtr(cbDataPtr cbPtr);
+  void setCbCtrlPtr(cbCtrlPtr cbPtr);
+
+  // --------------------------------------------------------------------------
+  // Konfiguration
+  // --------------------------------------------------------------------------
+  //
+  void setPollAddress(int chnIn, int adrIn, int areaIn, bool masterIn, bool eadrIn, bool nakIn);
+  void setEmptyPollParams(int cycleTotal, int cycleRun, dword timeOut);
+  void setDataPollParams(int slAdr, int prio, int minPrio, dword timeOut);
+
+  // --------------------------------------------------------------------------
+  // Steuerung des Telegrammaustausches (Polling)
+  // --------------------------------------------------------------------------
+  //
+  void run();       // Ablaufsteuerung (CPU-Übergabe) dieses Moduls
+/**
+ * @brief Sendet neue Steuerungsdaten an einen Slave
+ * 
+ * @param adr Addresse d. zu Steuernden Slaves
+ * @param ctrlList Liste mit Bytes zum Austausch der Steuerbytes
+ * @param nr Anzahl d. Steuerbytes
+ */
+  void updControl(int adr, byte *ctrlList, int nr);   // neue Steuerungsdaten
+  //
+/**
+ * @brief Prüft ob Steuerungsdaten übertragen wurden
+ * 
+ * @param adr Adresse d. Slaves
+ * @return true Erfolgreiche übertragung
+ * @return false Fehler in Übertragung / Falsche Adresse
+ */
+  bool ackTrans(int adr);         // Bestätigung Steuerungsdaten übertragen
+  /**
+ * @brief Überprüft ob Steuerungsdaten korrekt übertragen wurden
+ * 
+ * @param adr Adresse d. Slavrs
+ * @return true Daten erfolgreich verarbeitet
+ * @return false Fehler in Übertragung
+ */
+  bool ackControl(int adr);       // Bestätigung Steuerung ausgeführt
+
+
+  // Test
+  //
+
+  // Leeres Polling
+  //
+  void stopEP();
+  void resumeEP();
+  bool stoppedEP();
+
+  // Empfangsbetrieb beim Slave
+  //
+  void stopSR();
+  void resumeSR();
+  bool stoppedSR();
+
+  // Laufender Betrieb
+  //
+  void start(PlMode inPlMode);
+
+
+
+  // --------------------------------------------------------------------------
+  // Zugriff auf Polling-Informationen
+  // --------------------------------------------------------------------------
+  //
+  int   getSlaveList(byte *dest, int maxByte);
+  void  resetPollCounters();
+
+  // --------------------------------------------------------------------------
+  // Zugriff auf Slavedaten
+  // --------------------------------------------------------------------------
+  // Der Index wird von 0 an ausgewertet. Allerdings ist [0] in der Slave-Liste
+  // auf den Index [1] abzubilden, weil Slave[0] für besondere Aufgaben
+  // reserviert und für den Anwender nicht zugänglich ist.
+  //
+  bool      measAvail(int slIdx);   // Feststellen, ob neue Messwerte da sind
+  int       getArea(int slIdx);     // Wert der Area auslesen
+  PlpType   getAppId(int slIdx);    // Wert der AppId (BlePoll) auslesen
+  int       getMeas(int slIdx, byte *dest);    // Messwerte übergeben
+  int       getCtrlM(int slIdx, byte *dest);
+
+
+  // --------------------------------------------------------------------------
+  // Debugging
+  // --------------------------------------------------------------------------
+  //
+  dword debGetDword(int idx);
+  dword getStatistics(TxStatisticsPtr dest);
+
+  SlavePtr      getSlavePtr(int idx);
+  PollStatePtr  getPollPtr(int idx);
+};
+
+
+// ----------------------------------------------------------------------------
+#endif // BlePoll_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/BlePoll/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/BlePoll/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..477225b9ff50f19fdf4a1ffb19f791f80efa4870
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/BlePoll/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "BlePoll",
+    "version": "0.0.0+20220804174235"
+  }
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/ComRingBuf/ComRingBuf.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/ComRingBuf/ComRingBuf.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..66a9784b5507d680cc700b0f7fe5e68379da7e3e
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/ComRingBuf/ComRingBuf.cpp
@@ -0,0 +1,782 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   ComRingBuf.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   21. November 2021
+//
+// Der Inhalt dieser Datei sind Festlegungen zur Gestaltung eines Ringpuffers.
+//
+
+#include "ComRingBuf.h"
+
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+
+  ComRingBuf::ComRingBuf()
+  {
+    rbReadIdx = 0;
+    rbWriteIdx = 0;
+    sbReadIdx = 0;
+    sbWriteIdx = 0;
+    newLineMode = NewLineModeNL;
+  }
+
+  void ComRingBuf::begin(IntrfSerial *ser)
+  {
+    serIf = ser;
+  }
+
+  // --------------------------------------------------------------------------
+  // Konfiguration
+  // --------------------------------------------------------------------------
+  //
+  void ComRingBuf::setNewLineMode(byte nlMode)
+  {
+    newLineMode = nlMode;
+  }
+
+
+  // --------------------------------------------------------------------------
+  // Schnittstellen
+  // --------------------------------------------------------------------------
+  //
+  // Byte aus dem Sendepuffer lesen
+  //
+  bool  ComRingBuf::getByteSnd(byte *dest)
+  {
+    if(sbReadIdx == sbWriteIdx) return(false);
+
+    *dest = sndBuffer[sbReadIdx];
+    sbReadIdx++;
+    if(sbReadIdx >= sbSize)
+      sbReadIdx = 0;
+    return(true);
+  }
+
+  // Byte in den Empfangspuffer schreiben
+  //
+  void  ComRingBuf::putByteRec(byte b)
+  {
+    int space = rbReadIdx - rbWriteIdx - 1;
+    if(space == 0) return;
+  }
+
+
+// ----------------------------------------------------------------------------
+// Writing and reading data via circular buffer (default usage)
+// ----------------------------------------------------------------------------
+//
+
+// ----------------------------------------------------------------------------
+// Lesen (Empfangsvorgänge)
+// ----------------------------------------------------------------------------
+
+void  ComRingBuf::setReadBuffer(int size, byte *bufPtr)
+{
+  recBuffer = bufPtr;
+  rbSize = size;
+  rbReadIdx = 0;
+  rbWriteIdx = 0;
+}
+
+int   ComRingBuf::getChr()
+{
+  int retv;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(EOF);
+
+  retv = recBuffer[rbReadIdx];
+  rbReadIdx++;
+  if(rbReadIdx >= rbSize)
+    rbReadIdx = 0;
+  return(retv);
+}
+
+void  ComRingBuf::clrRecBuf()
+{
+  rbReadIdx  = 0;
+  rbWriteIdx = 0;
+}
+
+int   ComRingBuf::getAll(byte *buffer)
+{
+  int   count, i;
+  int   tmpInt;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(EOF);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  for(i = 0; i < count; i++)
+  {
+    buffer[i] = recBuffer[rbReadIdx];
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+  }
+
+  return(count);
+}
+
+int   ComRingBuf::getCount(int len, byte *buffer)
+{
+  int  count, i;
+  int  tmpInt;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  if(len > count)
+    len = count;
+
+  for(i = 0; i < len; i++)
+  {
+    buffer[i] = recBuffer[rbReadIdx];
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+  }
+
+  return(len);
+}
+
+int   ComRingBuf::getCountStr(int len, char *buffer)
+{
+  int nrChar;
+
+  nrChar = getCount(len, (uint8_t *) buffer);
+  if(nrChar == EOF) return(EOF);
+
+  buffer[nrChar] = 0;
+  return(nrChar);
+}
+
+int   ComRingBuf::getLine(char *buffer)
+{
+  bool      eol;
+  int       count, i;
+  int       tmpInt;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  eol = false;
+
+  for(i = 0; i < count; i++)
+  {
+    buffer[i] = recBuffer[rbReadIdx];
+    if(!eol)
+    {
+    if(buffer[i] == '\r' || buffer[i] == '\n')
+      eol = true;
+    }
+    else
+    {
+      if(buffer[i] != '\r' && buffer[i] != '\n')
+        break;
+    }
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+  }
+
+  if(!eol) return(0);
+
+  buffer[i] = 0;
+  return(i);
+}
+
+int   ComRingBuf::getLineDec(int *intValue)
+{
+  bool      eol, inVal;
+  int       count, i, j;
+  int       tmpInt;
+  char      c;
+  char      buffer[32];
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  if(count > 30)
+    count = 30;
+
+  eol = false;
+
+  j = 0;
+  inVal = false;
+
+  for(i = 0; i < count; i++)
+  {
+    c = recBuffer[rbReadIdx];
+    if(!inVal)
+    {
+      if(c > '9')
+      {
+        rbReadIdx++;
+        if(rbReadIdx >= rbSize)
+          rbReadIdx = 0;
+        continue;
+      }
+      inVal = true;
+    }
+
+    if(!eol)
+    {
+    if(c == '\r' || c == '\n')
+      eol = true;
+    }
+    else
+    {
+      if(c != '\r' && c != '\n')
+        break;
+    }
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+    buffer[j++] = c;
+  }
+
+  if(!eol) return(0);
+
+  buffer[j] = 0;
+  *intValue = atoi(buffer);
+  return(i);
+}
+
+char ComRingBuf::getC()
+{
+  char retC;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  retC = recBuffer[rbReadIdx];
+  rbReadIdx++;
+  if(rbReadIdx >= rbSize)
+    rbReadIdx = 0;
+
+  return(retC);
+}
+
+
+int   ComRingBuf::waitLine(int waitLoop, char *buffer)
+{
+  char inChar;
+  bool eol;
+
+  if(loopCount == 0)
+  {
+    tmpIdx = 0;
+  }
+
+  tmpVal = inCount();
+  if(tmpVal < 1)
+  {
+    loopCount++;
+    if(loopCount < waitLoop)
+      return(0);
+    else
+    {
+      loopCount = 0;
+      return(EOF);
+    }
+  }
+
+  eol = false;
+
+  for(int i = 0; i < tmpVal; i++)
+  {
+    inChar = getC();
+    buffer[tmpIdx++] = inChar;
+    if(inChar == '\r' || inChar == '\n')
+    {
+      eol = true;
+      break;
+    }
+  }
+
+  if(eol)
+  {
+    buffer[tmpIdx] = 0;
+    loopCount = 0;
+    return(tmpIdx);
+  }
+
+  return(0);
+}
+
+//int   ComRingBuf::waitLineDec(int waitLoop, int *intValue)
+//{
+//};
+
+int   ComRingBuf::chkLine(char *rsp)
+{
+  int     i,chkVal;
+  char    chkChar;
+
+  chkVal = inCount();
+  if(chkVal <= strlen(rsp))
+    return(0);
+
+  chkVal = 0;
+
+  for(i = 0; i < strlen(rsp); i++)
+  {
+    chkChar = getC();
+    if(rsp[i] != chkChar)
+    {
+      chkVal = -100000;
+      break;
+    }
+    else
+      chkVal++;
+  }
+
+  if(chkVal < 0) chkVal = EOF;
+
+  while( (recBuffer[rbReadIdx] == '\r' || recBuffer[rbReadIdx] == '\n' )
+         && (rbReadIdx != rbWriteIdx))
+  {
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+  }
+
+  return(chkVal);
+}
+
+int   ComRingBuf::chkBuf(char *rsp)
+{
+  int     i,chkVal;
+  char    chkChar;
+
+  chkVal = inCount();
+  if(chkVal < strlen(rsp))
+    return(0);
+
+  chkVal = 0;
+
+  for(i = 0; i < strlen(rsp); i++)
+  {
+    chkChar = getC();
+    if(rsp[i] != chkChar)
+      chkVal = -100;
+    else
+      chkVal++;
+  }
+
+  return(chkVal);
+}
+
+int   ComRingBuf::waitAll(int waitLoop, byte *buffer)
+{
+}
+
+int   ComRingBuf::waitChkBuf(int waitLoop, char *rsp)
+{
+  int   i;
+  int   chkVal;
+  char  chkChar;
+
+  if(loopCount == 0)
+  {
+    tmpVal = strlen(rsp);
+  }
+
+  chkVal = inCount();
+  if(chkVal < tmpVal)
+  {
+    loopCount++;
+    if(loopCount < waitLoop)
+      return(0);
+    else
+    {
+      loopCount = 0;
+      return(-10);
+    }
+  }
+
+  chkChar = getC();
+
+  if(rsp[0] != chkChar)
+    return(0);
+
+  if(tmpVal == 1)
+  {
+     loopCount = 0;
+     return(1);
+  }
+
+  chkVal = 1;
+
+  for(i = 1; i < tmpVal; i++)
+  {
+    chkChar = getC();
+    if(rsp[i] != chkChar)
+      return(0);
+    else
+      chkVal++;
+  }
+
+  loopCount = 0;
+  return(chkVal);
+}
+
+int   ComRingBuf::inCount(void)
+{
+  int count = rbWriteIdx - rbReadIdx;
+  if(count < 0)
+    count += rbSize;
+  return(count);
+}
+
+int   ComRingBuf::getRestChar(byte tagChr, int len, byte *buffer)
+{
+  int       count, i, j;
+  byte      inChr;
+  int       tmpInt;
+  bool      tagged;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  if(len > count)
+    len = count;
+
+  tagged = false;
+  j = 0;
+
+  for(i = 0; i < len; i++)
+  {
+    inChr = recBuffer[rbReadIdx];
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+
+    if(!tagged)
+    {
+      if(inChr != tagChr)
+        continue;
+
+      tagged = true;
+      continue;
+    }
+
+    buffer[j++] = inChr;
+  }
+
+  if(!tagged) j = -1;
+
+  return(j);
+}
+
+int   ComRingBuf::getRestStr(char *tagStr, int len, byte *buffer)
+{
+  int       count, i, j, tmpIdx;
+  byte      inChr;
+  int       tmpInt;
+  bool      tagged;
+  int       tagLen;
+  int       tagIdx;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpIdx = rbReadIdx;
+  tmpInt = rbWriteIdx - tmpIdx;
+
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  if(len > count)
+    len = count;
+
+  tagged = false;
+  j = 0;
+
+  tagLen = (int) strlen(tagStr);
+  tagIdx = 0;
+
+  if(len < tagLen)
+    return(0);
+
+  for(i = 0; i < len; i++)
+  {
+    inChr = recBuffer[tmpIdx];
+    tmpIdx++;
+    if(tmpIdx >= rbSize)
+      tmpIdx = 0;
+
+    if(!tagged)
+    {
+      if(inChr != tagStr[tagIdx])
+      {
+        tagIdx = 0;
+        continue;
+      }
+
+      tagIdx++;
+
+      if(tagIdx == tagLen)
+        tagged = true;
+      continue;
+    }
+
+    buffer[j++] = inChr;
+  }
+
+  if(!tagged) return(EOF);
+  else
+  {
+    rbReadIdx = tmpIdx;
+    return(j);
+  }
+}
+
+int   ComRingBuf::reqChkLine(char *req, char *rsp)
+{
+  int   i;
+  int   chkVal;
+  char  chkChar;
+
+  switch(reqChkState)
+  {
+    case 0:
+      rbReadIdx  = 0;
+      rbWriteIdx = 0;
+      chkVal = putLine(req);
+      if(chkVal <= 0)
+        return(EOF);
+      tmpVal = strlen(rsp);
+      reqChkState = 1;
+      return(0);
+
+    case 1:
+      chkVal = inCount();
+      if(chkVal <= tmpVal)
+        return(0);
+      chkVal = 0;
+
+      for(i = 0; i < tmpVal; i++)
+      {
+        chkChar = getC();
+        if(rsp[i] != chkChar)
+          chkVal = -100;
+        else
+          chkVal++;
+      }
+
+      while(     (recBuffer[rbReadIdx] == '\r' || recBuffer[rbReadIdx] == '\n')
+          && (rbReadIdx != rbWriteIdx) )
+      {
+        rbReadIdx++;
+        if(rbReadIdx >= rbSize)
+          rbReadIdx = 0;
+      }
+
+      reqChkState = 0;
+      return(chkVal);
+  }
+
+  return(-1000);    // internal error with <reqChkState>
+}
+
+// ----------------------------------------------------------------------------
+// Schreiben (Sendevorgänge)
+// ----------------------------------------------------------------------------
+
+void  ComRingBuf::setWriteBuffer(int size, byte *bufPtr)
+{
+  sndBuffer = bufPtr;
+  sbSize = size;
+  sbReadIdx = 0;
+  sbWriteIdx = 0;
+}
+
+int   ComRingBuf::putChr(int chr)
+{
+  int       space;
+  bool      txDone;
+
+  if(sndBuffer == NULL) return(EOF);
+  if(serIf == NULL) return(EOF);
+
+  space = getSpace();
+
+  if(space == 0)
+  {
+    // Wenn der Sendepuffer voll ist, dann kann der Entlader feststecken
+    serIf->resuSend();
+    return(EOF);
+  }
+
+  if(sbReadIdx == sbWriteIdx)
+  {
+    // Wenn der Sendepuffer leer ist, dann kann das Zeichen evt.
+    // direkt gesendet werden.
+    txDone = serIf->condSend(chr);
+    if(txDone) return(chr);
+  }
+
+  putBufB(chr);
+  return(chr);
+}
+
+int   ComRingBuf::putStr(char *msg)
+{
+  int sIdx = 0;
+
+  if(sndBuffer == NULL) return(EOF);
+  if(serIf == NULL) return(EOF);
+
+  int space = getSpace();
+  int len = strlen(msg);
+  if(space < len)
+  {
+    serIf->resuSend();
+    return(EOF);
+  }
+
+  if(sbReadIdx == sbWriteIdx)
+  {
+    // Wenn der Sendepuffer leer ist, dann kann das erste Zeichen evt.
+    // direkt gesendet werden.
+    if(serIf->condSend(msg[0]))
+      sIdx = 1;
+  }
+
+  for (int i = sIdx; i < len; i++)
+   {
+     sndBuffer[sbWriteIdx] = msg[i];
+     sbWriteIdx++;
+     if(sbWriteIdx >= sbSize)
+       sbWriteIdx = 0;
+   }
+
+  return(len);
+}
+
+int   ComRingBuf::putSeq(byte *msg, int n)
+{
+  int sIdx = 0;
+
+  if(sndBuffer == NULL) return(EOF);
+  if(serIf == NULL) return(EOF);
+
+  int space = getSpace();
+
+  if(space < n)
+  {
+    serIf->resuSend();
+    return(EOF);
+  }
+
+  if(sbReadIdx == sbWriteIdx)
+  {
+    // Wenn der Sendepuffer leer ist, dann kann das erste Zeichen evt.
+    // direkt gesendet werden.
+    if(serIf->condSend(msg[0]))
+      sIdx = 1;
+  }
+
+  for (int i = sIdx; i < n; i++)
+   {
+     sndBuffer[sbWriteIdx] = msg[i];
+     sbWriteIdx++;
+     if(sbWriteIdx >= sbSize)
+       sbWriteIdx = 0;
+   }
+
+  return(n);
+
+}
+
+int   ComRingBuf::putNL()
+{
+  int retv = 0;
+
+  if(newLineMode & NewLineModeCR)
+  {
+    putBufB('\r');
+    retv++;
+  }
+
+  if(newLineMode & NewLineModeNL)
+  {
+    putBufB('\n');
+    retv++;
+  }
+
+  return(retv);
+}
+
+int   ComRingBuf::putLine(char *msg)
+{
+  int retv, nl;
+
+  retv = putStr(msg);
+  if(retv < 0)
+    return(retv);
+
+  nl = putNL();
+  return(retv);
+}
+
+//int   ComRingBuf::putLine(char *msg, char c)
+//{
+//}
+
+//int   ComRingBuf::putLine(char *msg, int n)
+//{
+//}
+
+
+  // --------------------------------------------------------------------------
+  // Debugging
+  // --------------------------------------------------------------------------
+  //
+
+
+
+
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/ComRingBuf/ComRingBuf.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/ComRingBuf/ComRingBuf.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd8ee0c8e604ac8ca5a6c344ca9966bb856f365b
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/ComRingBuf/ComRingBuf.h
@@ -0,0 +1,227 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   ComRingBuf.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   21. November 2021
+//
+// Der Inhalt dieser Datei sind Festlegungen zur Gestaltung eines Ringpuffers.
+//
+
+#ifndef ComRingBuf_h
+#define ComRingBuf_h
+// ----------------------------------------------------------------------------
+
+#include "stddef.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "arduinoDefs.h"
+#include "IntrfBuf.h"
+#include "IntrfSerial.h"
+
+#define NewLineModeCR     0x01
+#define NewLineModeNL     0x02
+
+// ----------------------------------------------------------------------------
+//                            C o m R i n g B u f
+// ----------------------------------------------------------------------------
+class ComRingBuf : IntrfBuf
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  // Zugang zur Peripherie
+  //
+  IntrfSerial *serIf;
+
+  // Lesen und Schreiben von Zeichen (Bytes)
+  //
+  byte      *ptrSend;         // Der (veraenderliche) Sendezeiger
+  byte      *ptrRec;          // Der (veraenderliche) Empfangszeiger
+  int       maxRec;           // Maximale Anzahl zu empfangender Bytes
+  byte      endChrRec;        // Abschlusszeichen beim Empfang
+  byte      condMaskCom;      // Bedingungen fuer den Datenaustausch
+  byte      newLineMode;      // Art für eine neue Zeile (CR/LF)
+
+  byte      *recBuffer;       // Receive ring buffer start address
+  word      rbReadIdx;        // Read index
+  word      rbWriteIdx;       // Write index
+  word      rbSize;           // Buffer size
+
+  byte      *sndBuffer;       // Transmit ring buffer start address
+  word      sbReadIdx;        // Read index
+  word      sbWriteIdx;       // Write index
+  word      sbSize;           // Buffer size
+
+  int       loopCount;        // For internal time out checking
+  int       reqChkState;      // State of request/check procedure
+  int       tmpVal;           // Variable for temporary data storage
+  int       tmpIdx;           // Variable for temporary array index
+
+
+  // --------------------------------------------------------------------------
+  // Lokale Funktionen
+  // --------------------------------------------------------------------------
+  //
+  char  getC();
+  int   putNL();
+
+  // --------------------------------------------------------------------------
+  // Inline-Funktionen
+  // --------------------------------------------------------------------------
+  //
+  void putBufB(byte b)
+  {
+    sndBuffer[sbWriteIdx] = b;
+    sbWriteIdx++;
+    if(sbWriteIdx >= sbSize)
+      sbWriteIdx = 0;
+  }
+
+  int getSpace()
+  {
+    int space = sbReadIdx - sbWriteIdx - 1;
+    if(space < 0) space += sbSize;
+    return(space);
+  }
+
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+  ComRingBuf();
+
+  void begin(IntrfSerial *ser);
+
+  // --------------------------------------------------------------------------
+  // Konfiguration
+  // --------------------------------------------------------------------------
+  //
+  void setNewLineMode(byte nlMode);
+
+  // --------------------------------------------------------------------------
+  // Schnittstellen
+  // --------------------------------------------------------------------------
+  //
+  bool  getByteSnd(byte *dest);
+  void  putByteRec(byte b);       // Byte vom Empfang an Puffer geben
+
+
+  // Zuweisen eines Speichers (*bufPtr) der Größe size für den Lesepuffer
+  //
+  void  setReadBuffer(int size, byte *bufPtr);
+
+
+  // --------------------------------------------------------------------------
+  // Steuerung
+  // --------------------------------------------------------------------------
+  //
+
+  // ----------------------------------------------
+  // Ein einzelnes Zeichen aus dem Ringpuffer lesen
+  // ----------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst das älteste Zeichen aus dem Ringpuffer
+  //
+  int   getChr();
+
+  // ----------------------------------------------
+  // Löschen des Emmpfangspuffers
+  // ----------------------------------------------
+  //
+  void  clrRecBuf();
+
+  // --------------------------------------------------
+  // Alle empfangenen Zeichen aus dem Ringpuffer lesen
+  // --------------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der empfangenen Zeichen
+  //
+  int   getAll(byte *buffer);
+
+  // ----------------------------------------------------------
+  // Begrenzte Anzahl empfangener Zeichen aus Ringpuffer lesen
+  // ----------------------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der ausgelesenen Zeichen
+  //
+  int   getCount(int count, byte *buffer);
+
+  // ------------------------------------------------------------------------
+  // Begrenzte Anzahl Zeichen als 0-terminierten String aus Ringpuffer lesen
+  // ------------------------------------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der ausgelesenen Zeichen
+  //
+  int   getCountStr(int count, char *buffer);
+
+  // ---------------------------------------------------------
+  // Die nächste Zeile (Zeichen bis CR und/oder LF) als String
+  // ---------------------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der ausgelesenen Zeichen
+  //
+  int   getLine(char *buffer);
+
+  // -----------------------------------------------
+  // Die nächste im Puffer enthaltene Zeile auslesen
+  // und die darin enthaltene Dezimalzahl übergeben
+  // -----------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der ausgelesenen Zeichen
+  // oder 0, wenn keine Dezimalzahl enthalten war
+  //
+  int   getLineDec(int *intValue);
+
+  // ---------------------------------------------------------
+  // Warten auf Zeile (Zeichen bis CR und/oder LF) als String
+  // ---------------------------------------------------------
+  // Rückgabe EOF (-1), wenn Wartezyklen verstrichen
+  // Rückgabe 0, solange kein Zeilenende gelesen
+  // sonst die Anzahl der ausgelesenen Zeichen
+  //
+  int   waitLine(int waitLoop, char *buffer);
+
+  //int   waitLineDec(int waitLoop, int *intValue);
+
+  // ---------------------------------------------------------
+  // Testen der Zeile im Puffer
+  // ---------------------------------------------------------
+  // Rückgabe 0, wenn Teststring (noch) nicht enthalten
+  // sonst die Länge des Teststring
+  // EOF, wenn Zeile im Puffer (gelöscht) nicht passte
+  //
+  int   chkLine(char *rsp);
+
+  int   chkBuf(char *rsp);
+  int   waitAll(int waitLoop, byte *buffer);
+  int   waitChkBuf(int waitLoop, char *rsp);
+  int   inCount(void);
+  int   getRestChar(byte tagChr, int len, byte *buffer);
+  int   getRestStr(char *tagStr, int len, byte *buffer);
+  int   reqChkLine(char *req, char *rsp);
+
+  void  setWriteBuffer(int size, byte *bufPtr);
+  int   putChr(int chr);
+  int   putStr(char *msg);
+  int   putSeq(byte *msg, int n);
+  int   putLine(char *msg);
+  //int   putLine(char *msg, char c);
+  //int   putLine(char *msg, int n);
+
+  // --------------------------------------------------------------------------
+  // Debugging
+  // --------------------------------------------------------------------------
+  //
+
+};
+
+
+// ----------------------------------------------------------------------------
+#endif // beacon_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/ComRingBuf/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/ComRingBuf/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..054f2c8c3093791dc7ce4f7de879b26a019e900b
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/ComRingBuf/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "BlePoll",
+  "version": "0.0.0+20220804174235"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/LoopCheck.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/LoopCheck.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b01795b4f033ebb0286340840a3b1507c6ef0302
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/LoopCheck.cpp
@@ -0,0 +1,838 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Software Loop Checking and Timing
+// Datei:   LoopCheck.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (siehe Wikipedia: Creative Commons)
+//
+
+#include "LoopCheck.h"
+
+
+  // -------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // -------------------------------------------------------------------------
+  //
+  LoopCheck::LoopCheck()
+  {
+    firstLoop       = true;
+    taskHappened    = false;
+    toggleMilli     = true;
+
+    initStatistics();
+    initTasks();
+    initClock();
+  }
+
+  void LoopCheck::initStatistics()
+  {
+    backgroundMicros        = 0;
+    loopMicros              = 0;
+    loopStartMicros         = 0;
+    loopEndMicros           = 0;
+    backgroundMaxMicros     = 0;
+    backgroundMinMicros     = (unsigned long) -1;
+    backgroundAvgMicros     = 0;
+    loopMaxMicros           = 0;
+    loopMinMicros           = (unsigned long) -1;
+    loopAvgMicros           = 0;
+    loopCounter             = 0;
+    periodFailCount         = 0;
+    periodMaxMicros         = 0;
+    periodMinMicros         = (unsigned int) -1;
+    periodMicros            = 0;
+    periodFailAlarm         = false;
+
+    year    = 0;
+    day     = 0;
+    hour    = 0;
+    min     = 0;
+    sec     = 0;
+    msec    = 0;
+
+    measureRuntime = 0;
+
+    calcAvgCounter = 0;
+  }
+
+  void LoopCheck::initTasks()
+  {
+    for (int i = 0; i < NrOfTimerTasks; i++)
+    {
+      timerTaskList[i].counterStarted    = false;
+      timerTaskList[i].finished          = false;
+      timerTaskList[i].firstRun          = true;
+      timerTaskList[i].runCounter        = 0;
+    }
+
+    for( int i = 0; i < NrOfOnceTasks; i++)
+    {
+      onceTaskList[i].finished      = false;
+      onceTaskList[i].firstRun      = true;
+      onceTaskList[i].waitCounter   = 0;
+    }
+  }
+
+  void LoopCheck::initClock()
+  {
+    strcpy(dateTimeStr,"2017-12-07T17:11:35.456+00:00");
+    dtYear      = 2017;
+    dtMonth     = 12;
+    dtDay       = 7;
+    dtHour      = 17;
+    dtMin       = 11;
+    dtSec       = 35;
+    dtmSec      = 456;
+  }
+
+  // -------------------------------------------------------------------------
+  // Anwenderfunktionen
+  // -------------------------------------------------------------------------
+  //
+
+  void LoopCheck::begin()
+  {
+    unsigned int    cycleMillis;
+    unsigned int    restMicros;
+    unsigned int    tmpInt;
+    unsigned int    tmpInt100, tmpInt10, tmpInt1;
+    div_t           divResult;
+
+    loopStartMicros = SYSMICSEC;
+    clockCycleMicros = loopStartMicros - lastClockMicros + lastRestMicros;
+    //
+    // Zeit seit dem letzten Aufruf von begin()
+
+  
+    //
+    if(firstLoop == true)
+    {
+      clockCycleMicros = 0;
+      lastClockMicros = loopStartMicros;
+    }
+
+    // Aufteilen in Millisekunden und Mikrosekunden
+    //
+    divResult = DIV((int) clockCycleMicros, 1000);
+
+    restMicros = divResult.rem;
+    cycleMillis = divResult.quot;
+
+    if(cycleMillis > 0)
+    {
+      lastRestMicros = restMicros;
+      lastClockMicros = loopStartMicros;
+      msec += cycleMillis;
+      dtmSec += cycleMillis;
+
+      // Betriebsstundenzähler
+      //
+      if(msec >= 1000)
+      {
+        msec -= 1000;
+        sec++;
+        measureRuntime++;
+
+        if(sec == 60)
+        {
+          sec = 0;
+          min++;
+          if(min == 60)
+          {
+            min = 0;
+            hour++;
+            if(hour == 24)
+            {
+              hour = 0;
+              day++;
+              if(day == 365)
+              {
+                day = 0;
+                year++;
+              }
+            }
+          }
+        }
+      }
+
+      // Software-Uhr
+      //
+      if(dtmSec >= 1000)
+      {
+        dtmSec -= 1000;
+
+        dtSec++;
+        dateTimeStr[20] = '0';
+        dateTimeStr[21] = '0';
+        dateTimeStr[22] = '0';
+
+        if(dtSec == 60)
+        {
+          dtSec = 0;
+          dtMin++;
+          dateTimeStr[17] = '0';
+          dateTimeStr[18] = '0';
+
+          if(dtMin == 60)
+          {
+            dtMin = 0;
+            dtHour++;
+            dateTimeStr[14] = '0';
+            dateTimeStr[15] = '0';
+
+            if(dtHour == 24)
+            {
+              dtHour = 0;
+              dtDay++;
+              dateTimeStr[11] = '0';
+              dateTimeStr[12] = '0';
+
+              if  (
+                       (dtDay == (febLen + 1) && dtMonth == 2)
+                    || (dtDay == 31 && (dtMonth == 4 ||
+                                        dtMonth == 6 ||
+                                        dtMonth == 9 ||
+                                        dtMonth == 11))
+                    || dtDay == 32
+                  )
+              {
+                dtDay = 1;
+                dtMonth++;
+                dateTimeStr[8] = '0';
+                dateTimeStr[9] = '1';
+
+                if(dtMonth == 13)
+                {
+                  dtMonth = 1;
+                  dtYear++;
+                  tmpInt = dtYear - 2000;
+                  if((tmpInt % 4) == 0)
+                    febLen = 29;
+                  else
+                    febLen = 28;
+                  dateTimeStr[5] = '0';
+                  dateTimeStr[6] = '1';
+
+                  divResult   = DIV(tmpInt,100);
+                  tmpInt100   = divResult.quot;
+                  tmpInt      = divResult.rem;
+
+                  divResult   = DIV(tmpInt,10);
+                  tmpInt10    = divResult.quot;
+                  tmpInt1     = divResult.rem;
+
+                  dateTimeStr[1] = (char) (tmpInt100 | 0x30);
+                  dateTimeStr[2] = (char) (tmpInt10  | 0x30);
+                  dateTimeStr[3] = (char) (tmpInt1   | 0x30);
+                }
+                else
+                {
+                  divResult      = DIV(dtMonth,10);
+                  dateTimeStr[5] = (char) (divResult.quot | 0x30);
+                  dateTimeStr[6] = (char) (divResult.rem  | 0x30);
+                }
+              }
+              else
+              {
+                divResult      = DIV(dtDay,10);
+                dateTimeStr[8] = (char) (divResult.quot | 0x30);
+                dateTimeStr[9] = (char) (divResult.rem  | 0x30);
+              }
+            }
+            else
+            {
+              divResult       = DIV(dtHour,10);
+              dateTimeStr[11] = (char) (divResult.quot | 0x30);
+              dateTimeStr[12] = (char) (divResult.rem  | 0x30);
+            }
+          }
+          else
+          {
+            divResult       = DIV(dtMin,10);
+            dateTimeStr[14] = (char) (divResult.quot | 0x30);
+            dateTimeStr[15] = (char) (divResult.rem  | 0x30);
+          }
+        }
+        else
+        {
+          divResult     = DIV(dtSec,10);
+          dateTimeStr[17] = (char) (divResult.quot | 0x30);
+          dateTimeStr[18] = (char) (divResult.rem  | 0x30);
+        }
+      }
+      else
+      {
+        divResult   = DIV(dtmSec,100);
+        tmpInt100   = divResult.quot;
+        tmpInt      = divResult.rem;
+
+        divResult   = DIV(tmpInt,10);
+        tmpInt10    = divResult.quot;
+        tmpInt1     = divResult.rem;
+
+        dateTimeStr[20] = (char) (tmpInt100 | 0x30);
+        dateTimeStr[21] = (char) (tmpInt10  | 0x30);
+        dateTimeStr[22] = (char) (tmpInt1   | 0x30);
+      }
+
+    }
+
+    if(firstLoop == false)
+    {
+      backgroundMicros = loopStartMicros - loopEndMicros;
+      if(backgroundMicros > backgroundMaxMicros)
+        backgroundMaxMicros = backgroundMicros;
+      if(backgroundMicros < backgroundMinMicros)
+        backgroundMinMicros = backgroundMicros;
+      periodMicros = loopStartMicros - lastStartMicros;
+      if(periodMicros > periodMaxMicros)
+        periodMaxMicros = periodMicros;
+      periodSumMicros += periodMicros;
+      if(periodMicros < periodMinMicros)
+        periodMinMicros = periodMicros;
+      if(periodMicros > PeriodMinTime)
+      {
+        periodFailAlarm = true;
+        periodFailCount++;
+      }
+
+      divResult = DIV(periodMicros, 1000);
+      if(divResult.quot > 0)
+      {
+        if(divResult.quot >= LoopScreeningGrades)
+          ++loopScreening[LoopScreeningGrades - 1];
+        else
+          ++loopScreening[divResult.quot -1];
+      }
+    } // if()
+
+    lastStartMicros = loopStartMicros;
+
+  }
+
+
+  unsigned int LoopCheck::done()
+  {
+    return(SYSMICSEC - loopStartMicros);
+  }
+
+  void LoopCheck::end()
+  {
+    loopEndMicros = SYSMICSEC;
+    loopMicros = loopEndMicros - loopStartMicros;
+    if(loopMicros > loopMaxMicros)
+      loopMaxMicros = loopMicros;
+    if(loopMicros < loopMinMicros)
+      loopMinMicros = loopMicros;
+
+    if(firstLoop == false)
+    {
+      loopSumMicros += loopMicros;
+      backgroundSumMicros += backgroundMicros;
+      calcAvgCounter++;
+      if(calcAvgCounter == CalcAverageDepth)
+      {
+        loopAvgMicros = loopSumMicros / CalcAverageDepth;
+        backgroundAvgMicros = backgroundSumMicros / CalcAverageDepth;
+        periodAvgMicros = periodSumMicros / CalcAverageDepth;
+        calcAvgCounter = 0;
+        loopSumMicros = 0;
+        backgroundSumMicros = 0;
+        periodSumMicros = 0;
+      }
+    }
+    else
+    {
+      loopAvgMicros = loopMicros;
+      backgroundAvgMicros = backgroundMicros;
+    }
+
+    loopCounter++;
+    firstLoop = false;
+    taskHappened = false;
+  }
+
+  bool LoopCheck::timerMicro
+    (int taskIdx, unsigned long repeatTime, unsigned int repetitions, unsigned long delay)
+  {
+    TimerTask     *ctrlPtr;
+    unsigned long calcMics;
+
+    // Test the limit of enabled timers
+    //
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfTimerTasks) return(false);
+
+    // Get the reference to timer data for the selected timer
+    //
+    ctrlPtr = &timerTaskList[taskIdx];
+
+    // If the timer task has finished, we are ready here
+    //
+    if(ctrlPtr->finished == true) return(false);
+
+    // If it is the first run (initialisation 1)
+    //
+    if(ctrlPtr->firstRun == true)
+    {
+      ctrlPtr->firstRun     = false;
+      ctrlPtr->repCounter   = repetitions;
+      ctrlPtr->delayCounter = delay;
+    }
+
+    // If counting is not started yet (initialisation 2)
+    //
+    if(ctrlPtr->counterStarted == false)
+    {
+      ctrlPtr->startCount = loopStartMicros;
+      ctrlPtr->counterStarted = true;
+      return(false);
+    }
+
+    // If another count task has happened in this loop, we have to wait
+    //
+    if(taskHappened == true) return(false);
+
+    // Calculate the number of microseconds since the start of the counter
+    //
+    calcMics = loopStartMicros - ctrlPtr->startCount;
+    ctrlPtr->ticks = calcMics;
+
+    // If there is a delay, wait the delay time
+    //
+    if(ctrlPtr->delayCounter > 0)
+    {
+      if(calcMics < ctrlPtr->delayCounter)
+        return(false);
+      else
+      {
+        ctrlPtr->delayCounter = 0;                // delay finished
+        ctrlPtr->startCount = loopStartMicros;    // reset counter
+      }
+      return(false);
+    }
+
+    // There is no delay (or delay is finished)
+    // If repeatTime is not passed, leave with FALSE
+    //
+    if(calcMics < repeatTime)
+    {
+      return(false);
+    }
+
+    // One counter period finished
+    //
+    taskHappened            = true;               // disable other timers in this loop
+    ctrlPtr->counterStarted = false;              // prepare resetting the counter
+    ctrlPtr->runCounter++;                        // count the timer events
+
+    // If the number of periods is limited finish in time
+    //
+    if(ctrlPtr->repCounter > 0)
+    {
+      ctrlPtr->repCounter--;
+      if(ctrlPtr->repCounter == 0)
+        ctrlPtr->finished = true;
+    }
+
+    return(true);
+  }
+
+  bool LoopCheck::timerMicro
+    (int taskIdx, unsigned long repeatTime, unsigned int repetitions)
+  {
+    return(timerMicro(taskIdx, repeatTime, repetitions, 0));
+  }
+
+
+  bool LoopCheck::timerMilli
+    (int taskIdx, unsigned long repeatTime, unsigned int repetitions, unsigned long delay)
+  {
+    return(timerMicro(taskIdx, repeatTime * 1000, repetitions, delay * 1000));
+  }
+
+  bool LoopCheck::timerMilli
+    (int taskIdx, unsigned long repeatTime, unsigned int repetitions)
+  {
+    return(timerMicro(taskIdx,repeatTime * 1000,repetitions,0));
+  }
+
+  bool LoopCheck::once(int taskIdx)
+  {
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfOnceTasks) return(false);
+
+    if(onceTaskList[taskIdx].finished == true) return(false);
+    onceTaskList[taskIdx].finished = true;
+    return(true);
+  }
+
+  bool LoopCheck::once(int taskIdx, unsigned int nrOfLoops)
+  {
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfOnceTasks) return(false);
+
+    if(onceTaskList[taskIdx].finished == true) return(false);
+    if(nrOfLoops <= 1)
+    {
+      onceTaskList[taskIdx].finished = true;
+      return(true);
+    }
+
+    if(onceTaskList[taskIdx].firstRun == true)
+    {
+      onceTaskList[taskIdx].firstRun = false;
+      onceTaskList[taskIdx].waitCounter = nrOfLoops;
+    }
+
+    onceTaskList[taskIdx].waitCounter--;
+    if(onceTaskList[taskIdx].waitCounter > 0)
+      return(false);
+
+    onceTaskList[taskIdx].finished = true;
+    return(true);
+  }
+
+  bool LoopCheck::onceDelayed(int taskIdx, unsigned long delay)
+  {
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfOnceTasks) return(false);
+
+    if(onceTaskList[taskIdx].finished == true) return(false);
+
+    if(onceTaskList[taskIdx].firstRun == true)
+    {
+      onceTaskList[taskIdx].firstRun = false;
+      onceTaskList[taskIdx].startCount = loopStartMicros;
+    }
+
+    if(loopStartMicros - onceTaskList[taskIdx].startCount < delay)
+      return(false);
+
+    onceTaskList[taskIdx].finished = true;
+    return(true);
+  }
+
+  bool LoopCheck::toggle(int taskIdx)
+  {
+    bool    toggleBit;
+
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfToggleTasks) return(false);
+    toggleBit = toggleTaskList[taskIdx];
+    toggleTaskList[taskIdx] = !toggleBit;
+    return(toggleBit);
+  }
+
+  unsigned long LoopCheck::timerCycle(int taskIdx)
+  {
+    if(taskIdx < 0) return(0);
+    if(taskIdx >= NrOfTimerTasks) return(0);
+    return(timerTaskList[taskIdx].runCounter);
+  }
+
+  bool LoopCheck::timerCycleMod(int taskIdx, int modulo)
+  {
+    div_t divResult;
+
+    if(taskIdx < 0) return(0);
+    if(taskIdx >= NrOfTimerTasks) return(0);
+    divResult   = DIV(timerTaskList[taskIdx].runCounter,modulo);
+    if(divResult.rem == 0)
+      return(true);
+    else
+      return(false);
+  }
+
+  unsigned long LoopCheck::tick(int taskIdx)
+  {
+    if(taskIdx < 0) return(0);
+    if(taskIdx >= NrOfTimerTasks) return(0);
+    return(timerTaskList[taskIdx].ticks);
+  }
+
+  unsigned long LoopCheck::operationTime(OpHourMeter *opHourMeter)
+  {
+    opHourMeter->Milliseconds    = msec;
+    opHourMeter->Seconds         = sec;
+    opHourMeter->Minutes         = min;
+    opHourMeter->Hours           = hour;
+    opHourMeter->Days            = day;
+    opHourMeter->Years           = year;
+    return(loopStartMicros);
+  }
+
+  unsigned long LoopCheck::getStatistics(LoopStatistics *statistics)
+  {
+    statistics->loopTime    =   (unsigned int) loopMicros;
+    statistics->loopMaxTime =   (unsigned int) loopMaxMicros;
+    statistics->loopMinTime =   (unsigned int) loopMinMicros;
+    statistics->loopAvgTime =   (unsigned int) loopAvgMicros;
+
+    statistics->bgTime      =   (unsigned int) backgroundMicros;
+    statistics->bgMaxTime   =   (unsigned int) backgroundMaxMicros;
+    statistics->bgMinTime   =   (unsigned int) backgroundMinMicros;
+    statistics->bgAvgTime   =   (unsigned int) backgroundAvgMicros;
+
+    statistics->alarmCount  =   periodFailCount;
+    statistics->periodAlarm =   periodFailAlarm;
+    periodFailAlarm = false;
+
+    statistics->loopPeriod  =   periodMicros;
+    statistics->maxPeriod   =   periodMaxMicros;
+    statistics->minPeriod   =   periodMinMicros;
+    statistics->avgPeriod   =   periodAvgMicros;
+
+    for (int i = 0; i < LoopScreeningGrades; i++)
+      statistics->rtScreening[i] = loopScreening[i];
+
+    return(loopCounter);
+  }
+
+  void LoopCheck::resetStatistics()
+  {
+    backgroundMicros        = 0;
+    loopMicros              = 0;
+
+    backgroundMaxMicros     = 0;
+    backgroundMinMicros     = (unsigned long) -1;
+    backgroundAvgMicros     = 0;
+
+    loopMaxMicros           = 0;
+    loopMinMicros           = (unsigned long) -1;
+    loopAvgMicros           = 0;
+    loopCounter             = 0;
+
+    periodFailCount         = 0;
+    periodMaxMicros         = 0;
+    periodMinMicros         = (unsigned int) -1;
+    periodAvgMicros         = 0;
+    periodMicros            = 0;
+    periodFailAlarm         = false;
+
+    for (int i = 0; i < LoopScreeningGrades; i++)
+      loopScreening[i] = 0;
+
+    calcAvgCounter          = 0;
+  }
+
+  bool LoopCheck::setDateTime(const char *dtStr)
+  {
+    int tmpInt;
+
+     if(strlen(dtStr) < 23) return(false);
+     strcpy(dateTimeStr,dtStr);
+     dtYear   = (dateTimeStr[0]  & 0x0F) * 1000 +
+                (dateTimeStr[1]  & 0x0F) * 100  +
+                (dateTimeStr[2]  & 0x0F) * 10   +
+                (dateTimeStr[3]  & 0x0F);
+
+     tmpInt = dtYear - 2000;
+     if((tmpInt % 4) == 0)
+       febLen = 29;
+     else
+       febLen = 28;
+
+
+     dtMonth  = (dateTimeStr[5]  & 0x0F) * 10   +
+                (dateTimeStr[6]  & 0x0F);
+
+     dtDay    = (dateTimeStr[8]  & 0x0F) * 10   +
+                (dateTimeStr[9]  & 0x0F);
+
+     dtHour   = (dateTimeStr[11] & 0x0F) * 10   +
+                (dateTimeStr[12] & 0x0F);
+
+     dtMin    = (dateTimeStr[14] & 0x0F) * 10   +
+                (dateTimeStr[15] & 0x0F);
+
+     dtSec    = (dateTimeStr[17] & 0x0F) * 10   +
+                (dateTimeStr[18] & 0x0F);
+
+     dtmSec   = (dateTimeStr[20] & 0x0F) * 10   +
+                (dateTimeStr[21] & 0x0F) * 10   +
+                (dateTimeStr[22] & 0x0F);
+
+     return(true);
+  }
+
+  bool LoopCheck::setDateTime(lcDateTime dt)
+  {
+    div_t   divResult;
+    int     tmpInt;
+
+    dtYear    = dt.Year;
+
+    tmpInt = dtYear - 2000;
+    if((tmpInt % 4) == 0)
+      febLen = 29;
+    else
+      febLen = 28;
+
+
+    divResult = DIV(dtYear,1000);
+    dateTimeStr[0] = (char) (0x30 + divResult.quot);
+
+    divResult = DIV(divResult.rem,100);
+    dateTimeStr[1] = (char) (0x30 + divResult.quot);
+
+    divResult = DIV(divResult.rem,10);
+    dateTimeStr[2] = (char) (0x30 + divResult.quot);
+    dateTimeStr[3] = (char) (0x30 + divResult.rem);
+
+    dtMonth   = dt.Month;
+    divResult = DIV(dtMonth,10);
+    dateTimeStr[5] = (char) (0x30 + divResult.quot);
+    dateTimeStr[6] = (char) (0x30 + divResult.rem);
+
+    dtDay     = dt.Day;
+    divResult = DIV(dtDay,10);
+    dateTimeStr[8] = (char) (0x30 + divResult.quot);
+    dateTimeStr[9] = (char) (0x30 + divResult.rem);
+
+    dtHour    = dt.Hour;
+    divResult = DIV(dtHour,10);
+    dateTimeStr[11] = (char) (0x30 + divResult.quot);
+    dateTimeStr[12] = (char) (0x30 + divResult.rem);
+
+    dtMin     = dt.Minute;
+    divResult = DIV(dtMin,10);
+    dateTimeStr[14] = (char) (0x30 + divResult.quot);
+    dateTimeStr[15] = (char) (0x30 + divResult.rem);
+
+    dtSec     = dt.Second;
+    divResult = DIV(dtSec,10);
+    dateTimeStr[17] = (char) (0x30 + divResult.quot);
+    dateTimeStr[18] = (char) (0x30 + divResult.rem);
+
+    dtmSec    = dt.Millisecond;
+    divResult = DIV(dtmSec, 100);
+    dateTimeStr[20] = (char) (0x30 + divResult.quot);
+    divResult = DIV(divResult.rem, 10);
+    dateTimeStr[21] = (char) (0x30 + divResult.quot);
+    dateTimeStr[22] = (char) (0x30 + divResult.rem);
+
+    return(true);
+  }
+
+  bool LoopCheck::getDateTime(lcDateTime *dt)
+  {
+    dt->Year        = dtYear;
+    dt->Month       = dtMonth;
+    dt->Day         = dtDay;
+    dt->Hour        = dtHour;
+    dt->Minute      = dtMin;
+    dt->Second      = dtSec;
+    dt->Millisecond = dtmSec;
+    return(true);
+  }
+
+  const char * LoopCheck::refDateTime()
+  {
+    return(dateTimeStr);
+  }
+
+  unsigned long LoopCheck::locMicros()
+  {
+#ifdef smnSimLinux
+    struct timespec clockTime;
+    unsigned long retv;
+
+    clock_gettime(CLOCK_MONOTONIC, &clockTime);
+    retv = clockTime.tv_nsec / 1000;
+    return(retv);
+#endif
+
+#ifdef smnSimWindows
+    LARGE_INTEGER countValue, frequency, result;
+
+    QueryPerformanceCounter(&countValue);
+    QueryPerformanceFrequency(&frequency);
+
+    result.QuadPart = (countValue.QuadPart * 1000000) / frequency.QuadPart;
+    return((unsigned long) result.QuadPart);
+#endif
+
+#ifdef smnSloeber
+    return(micros());
+#endif
+  }
+
+#ifdef smnESP8266
+  div_t LoopCheck::locDiv(int numer, int denom)
+  {
+    div_t retv;
+
+    retv.quot = numer / denom;
+    retv.rem  = numer % denom;
+
+    return(retv);
+  }
+#endif
+
+  void LoopCheck::startTimeMeasure()
+  {
+    measureTimeSet = SYSMICSEC;
+  }
+
+  unsigned long LoopCheck::getTimeMeasure()
+  {
+    return(SYSMICSEC - measureTimeSet);
+  }
+
+  unsigned long LoopCheck::getRuntime()
+  {
+    return(measureRuntime);
+  }
+
+  void LoopCheck::hexAsc(char * dest, byte val)
+  {
+    char cv;
+
+    cv = val >> 4;
+    if(cv < 10)
+      cv += 0x30;
+    else
+      cv += 0x37;
+    dest[0] = cv;
+
+    cv = val & 0x0F;
+    if(cv < 10)
+      cv += 0x30;
+    else
+      cv += 0x37;
+    dest[1] = cv;
+
+    dest[2] = '\0';
+  }
+
+
+  // -------------------------------------------------------------------------
+  // Debug-Funktionen
+  // -------------------------------------------------------------------------
+  //
+#ifdef smnLoopCheckDebug
+
+  void LoopCheck::dbgGetStatistics(char *buffer, int idxItem)
+  {
+    switch(idxItem)
+    {
+      case 0:
+        sprintf(buffer,"lT=%d, lMaxT=%d, lMinT=%d, lAvgT=%d",
+            loopMicros,loopMaxMicros,loopMinMicros,loopAvgMicros);
+        break;
+
+      case 1:
+        sprintf(buffer,"bT=%d, bMaxT=%d, bMinT=%d, bAvgT=%d",
+            backgroundMicros,backgroundMaxMicros,backgroundMinMicros,backgroundAvgMicros);
+        break;
+
+      case 2:
+        sprintf(buffer,"rtAlCnt=%d, lCnt=%d, Scr=%d,%d,%d,%d,%d,%d",
+            periodFailCount, loopCounter, loopScreening[0],loopScreening[1],loopScreening[2],loopScreening[3],loopScreening[4],loopScreening[5]);
+        break;
+    }
+  }
+
+#endif
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/LoopCheck.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/LoopCheck.h
new file mode 100644
index 0000000000000000000000000000000000000000..9588f3e56dc3ebe52890b772533793e533aad05d
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/LoopCheck.h
@@ -0,0 +1,343 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   LoopCheck.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (siehe Wikipedia: Creative Commons)
+//
+#ifndef _LoopCheck_h
+#define _LoopCheck_h
+//-----------------------------------------------------------------------------
+
+#define PeriodMinTime       5000
+// Wenn der Aufrufzyklus der Loop diese Zeit (in Mikrosekunden) überschreitet,
+// dann wird ein Alarmbit gesetzt und ein Alarmzähler inkrementiert
+
+#ifndef LoopScreeningGrades
+  #define LoopScreeningGrades 6
+#endif
+
+#define NrOfTimerTasks      10
+
+#define lcTimer0  0
+#define lcTimer1  1
+#define lcTimer2  2
+#define lcTimer3  3
+#define lcTimer4  4
+#define lcTimer5  5
+#define lcTimer6  6
+#define lcTimer7  7
+#define lcTimer8  8
+#define lcTimer9  9
+
+
+#define NrOfOnceTasks       4
+
+#define lcOnce0  0
+#define lcOnce1  1
+#define lcOnce2  2
+#define lcOnce3  3
+
+#define NrOfToggleTasks     4
+
+#define lcToggle0  0
+#define lcToggle1  1
+#define lcToggle2  2
+#define lcToggle3  3
+
+#define CalcAverageDepth    32
+
+#ifdef UseGithubPath
+  #include "../environment/environment.h"
+#else
+  #include "environment.h"
+#endif
+
+#if defined(smnSimLinux) || defined(smnSimWindows)
+  #include <stdlib.h>
+  #include <string.h>
+  #include <time.h>
+  #define SYSMICSEC locMicros()
+#endif
+
+#ifdef smnSimWindows
+#include <Windows.h>
+#endif
+
+#ifdef smnSloeber
+  #include "Arduino.h"
+  #define SYSMICSEC    micros()
+#endif
+
+#ifdef smnESP8266
+  #define DIV(x,y)    locDiv(x,y)
+#else
+  #define DIV(x,y)    div(x,y)
+#endif
+
+typedef struct _OpHourMeter
+{
+  int   Years;
+  int   Days;
+  int   Hours;
+  int   Minutes;
+  int   Seconds;
+  int   Milliseconds;
+} OpHourMeter;
+
+typedef struct _lcDateTime
+{
+  int   Year;
+  int   Month;
+  int   Day;
+  int   Hour;
+  int   Minute;
+  int   Second;
+  int   Millisecond;
+} lcDateTime;
+
+typedef struct _LoopStatistics
+{
+  unsigned int  loopTime;       // Schleifenzeit in Mikrosekunden
+  unsigned int  loopMaxTime;    // Maximale Schleifenzeit
+  unsigned int  loopMinTime;    // Minimale Schleifenzeit
+  unsigned int  loopAvgTime;    // Mittlere Schleifenzeit
+
+  unsigned int  bgTime;         // Zeit außerhalb der Schleife
+  unsigned int  bgMaxTime;      // Maximale Außenzeit
+  unsigned int  bgMinTime;      // Minimale Außenzeit
+  unsigned int  bgAvgTime;      // Mittlere Außenzeit
+
+  unsigned int  loopPeriod;     // Zeit zwischen loop-Aufrufen
+  unsigned int  maxPeriod;      // Maximale Aufrufdistanz
+  unsigned int  minPeriod;      // Minimale Aufrufdistanz
+  unsigned int  avgPeriod;      // Mittlere Aufrufdistanz
+
+  bool          periodAlarm;    // Aufrufdistanz > PeriodMinTime
+  unsigned int  alarmCount;     // Anzahl der Überschreitungen
+
+  unsigned int  rtScreening[LoopScreeningGrades];
+  // Echtzeitüberwachung (Klassierung der ms Überschreitungen)
+} LoopStatistics;
+
+
+// ---------------------------------------------------------------------------
+// class LoopCheck
+// ---------------------------------------------------------------------------
+//
+class LoopCheck
+{
+  // -------------------------------------------------------------------------
+  // Klassenspezifische Datentypen
+  // -------------------------------------------------------------------------
+  //
+  typedef struct _TimerTask
+  {
+    bool            counterStarted;
+    bool            finished;
+    bool            firstRun;
+    unsigned long   startCount;
+    unsigned long   runCounter;
+    unsigned long   delayCounter;
+    unsigned long   ticks;
+    unsigned int    repCounter;
+  } TimerTask;
+
+  typedef struct _OnceTask
+  {
+    bool            finished;
+    bool            firstRun;
+    unsigned int    waitCounter;
+    unsigned long   startCount;
+  } OnceTask;
+
+private:
+  // -------------------------------------------------------------------------
+  // Lokale Variablen
+  // -------------------------------------------------------------------------
+  //
+  unsigned long checkStartMicros;       // Zeit des ersten Aufrufs von begin()
+
+  unsigned long backgroundMicros;       // Zeit, die außerhalb von loop()
+                                        // verstrichen ist (in Mikrosekunden)
+  unsigned long loopMicros;             // Zeit, die innerhalb von loop()
+                                        // verstrichen ist (in Mikrosekunden)
+  unsigned long loopStartMicros;        // Loop-Startzeit (us seit CPU-Start)
+  unsigned long lastClockMicros;
+  unsigned long lastStartMicros;
+  unsigned long lastRestMicros;
+
+  unsigned long loopEndMicros;          // Loop-Endezeit (us seit CPU-Start)
+  unsigned long clockCycleMicros;       // Abstand zwischen zwei clock ticks
+  unsigned long mainStartMicros;        // Zählerstand bei Programmstart
+
+  unsigned long backgroundMaxMicros;    // Maximale Zeit außerhalb loop()
+  unsigned long backgroundMinMicros;    // Minimale Zeit außerhalb loop()
+  unsigned long backgroundAvgMicros;    // Mittlere Zeit außerhal loop() {32}
+  unsigned long backgroundSumMicros;    // Summe für Mittelwertberechnung
+
+  unsigned long loopMaxMicros;          // Maximale Zeit innerhalb loop()
+  unsigned long loopMinMicros;          // Minimale Zeit innerhalb loop()
+  unsigned long loopAvgMicros;          // Mittlere Zeit innerhalb loop()
+  unsigned long loopSumMicros;          // Summe für Mittelwertberechnung
+
+  unsigned long loopCounter;            // Anzahl der loop()-Durchläufe
+
+  unsigned int  loopScreening[LoopScreeningGrades];
+
+  int           calcAvgCounter;         // Zähler für die Mittelwertbildung
+  bool          firstLoop;              // Spezielle Kennzeichnung erste loop()
+  bool          taskHappened;           // Kennzeichnung: Es lief ein LoopTask
+
+  TimerTask     timerTaskList[NrOfTimerTasks];  // Steuerung der zyklischen
+                                                // Tasks (Timer-Ersatz in loop())
+  OnceTask      onceTaskList[NrOfOnceTasks];
+  bool          toggleTaskList[NrOfToggleTasks];
+
+  int           year;               // Betriebsstundenzähler gesamt
+  int           day;
+  int           hour;
+  int           min;
+  int           sec;
+  int           msec;
+  bool          toggleMilli;
+
+  int           dtYear;             // Zeit / Uhr
+  int           dtMonth;
+  int           dtDay;
+  int           dtHour;
+  int           dtMin;
+  int           dtSec;
+  int           dtmSec;
+  int           febLen;
+  char          dateTimeStr[30];
+
+  unsigned int  periodMicros;           // Zeit zwischen zwei loop-Aufrufen
+  unsigned int  periodMinMicros;
+  unsigned int  periodMaxMicros;
+  unsigned int  periodAvgMicros;
+  unsigned int  periodSumMicros;
+
+  bool          periodFailAlarm;        // periodMicros > Millisekunde
+  unsigned int  periodFailCount;        // Anzahl der Überschreitungen
+
+  unsigned long measureTimeSet;         // Mikrosekunden-Offset Zeitmessung
+
+  unsigned long measureRuntime;         // Laufzeit seit Start in Sekunden
+
+private:
+  // -------------------------------------------------------------------------
+  // Lokale Funktionen
+  // -------------------------------------------------------------------------
+  //
+  void initTasks();
+  void initStatistics();
+  void initClock();
+  unsigned long locMicros();
+#ifdef smnESP8266
+  div_t locDiv(int numer, int denom);
+#endif
+
+public:
+  // -------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // -------------------------------------------------------------------------
+  //
+  LoopCheck();
+
+  // -------------------------------------------------------------------------
+  // Anwenderfunktionen
+  // -------------------------------------------------------------------------
+  //
+  void begin();     // Diese Funktion muss am Anfang der Schleife aufgerufen
+                    // werden.
+
+  unsigned int done();  // Diese Funktion kann vor dem Aufruf von end()
+                        // genutzt werden und liefert die Laufzeit bis dahin
+
+  void end();       // Diese Funktion muss am Ende der Schleife aufgerufen
+                    // werden.
+
+  bool timerMicro(int taskIdx, unsigned long repeatTime, unsigned int repetitions);
+  bool timerMicro(int taskIdx, unsigned long repeatTime, unsigned int repetitions, unsigned long delay);
+  // Diese Funktion muss als Bedingung (if) aufgerufen werden, um den
+  // nachfolgenden Block {} mit der Wiederholzeit <repeatTime> auszuführen
+  // Für jede Taskschleife muss ein anderer Index <taskIdx> aus dem Bereich
+  // 0 <= taskIdx < MaxNrOfLoopTasks angegeben werden.
+  // Mit <repetitions> wird angegeben, wie oft der Durchlauf überhaupt erfolgt.
+  // Der Wert 0 gibt an, dass der Task für immer läuft
+
+  bool timerMilli(int taskIdx, unsigned long repeatTime, unsigned int repetitions);
+  bool timerMilli(int taskIdx, unsigned long repeatTime, unsigned int repetitions, unsigned long delay);
+
+  bool once(int taskIdx);
+  // Diese Funktion liefert nur einmal den Wert <true>
+
+  bool once(int taskIdx, unsigned int nrOfLoops);
+  // Diese Funktion liefert nur einmal den Wert <true>
+  // nach Ablauf von nrOfLoops Aufrufen
+
+  bool onceDelayed(int taskIdx, unsigned long delay);
+  // Diese Funktion liefert nur einmal den Wert <true>
+  // nach Ablauf von <delay> Mikrosekunden
+
+  bool toggle(int taskIdx);
+  // Diese Funktion liefert abwechselnd die Werte <true> oder <false>
+
+  unsigned long timerCycle(int taskIdx);
+  // Rückgabe des aktuellen Timerablaufes (startet ab 0).
+
+  bool timerCycleMod(int taskIdx, int modulo);
+  // Liefert alle <modulo> Timerabläufe den Wert <true>
+
+  unsigned long tick(int taskIdx);
+  // Rückgabe des aktuellen Zählwertes in Mikrosekunden
+
+  unsigned long operationTime(OpHourMeter *opHourMeter);
+  // Die Zeit ab Start der CPU
+
+  unsigned long getStatistics(LoopStatistics *statistics);
+  // Statistik über Ablaufzeiten
+
+  void resetStatistics();
+  // Rücksetzen der Statistikdaten
+
+  bool setDateTime(const char *dtStr);
+  // Setzen der Uhr über standardisierten String
+
+  bool setDateTime(lcDateTime dt);
+  // Setzen der Uhr über lokal definierte Struktur
+
+  bool getDateTime(lcDateTime *dt);
+  // Abfragen der Uhr über lokal definierte Struktur
+
+  const char * refDateTime();
+  // Zeiger auf Datum/Uhrzeit holen
+
+  void startTimeMeasure();
+  // Zeitmessung starten
+
+  unsigned long getTimeMeasure();
+  // Zeitmesswert holen
+
+  unsigned long getRuntime();
+  // Laufzeit in Sekunden
+
+  void hexAsc(char * dest, byte val);
+  // Umwandlung byte in Hex-ASCII
+
+  // -------------------------------------------------------------------------
+  // Debug-Funtionen
+  // -------------------------------------------------------------------------
+  //
+
+#ifdef smnLoopCheckDebug
+  void dbgGetStatistics(char *buffer, int idxItem);
+#endif
+
+};
+
+//-----------------------------------------------------------------------------
+#endif
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/ReadMe.md b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/ReadMe.md
new file mode 100644
index 0000000000000000000000000000000000000000..7701d9d3347942f8c88807f2f8342bade47ace46
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/ReadMe.md
@@ -0,0 +1,20 @@
+# Tools for cyclic called procedures
+Arduino Sketches are build on two basic functions. 
+*void setup()* is called once when the CPU is reset and programmers place their initialisation code here.
+*void loop()* is called in an endless loop, i.e. a cyclic entered function. 
+But the cycle time is not determined, it depends on the speed of the CPU and the used resources.
+Many examples for Arduino use the function *delay(milliseconds)* to organise a kind of timing. 
+But this function is really freezing your program for the given number of milliseconds.
+Using a real timer is a good solution, but some CPUs have only less timers 
+and they sometimes are already used for some libraries.
+
+The tools presented with LoopCheck-library give You the features of (many) timers inside *loop()* 
+based on the Arduino-function *micros()* which is called with the macro SYSMICSEC, 
+defined in *LoopCheck.h*.
+
+You will find, that there is another file included: *environment.h*, which you can find here:
+https://github.com/RobertPatzke/homeautomation/blob/developer/libraries/environment/environment.h
+*environment.h* defines the IDE you are using, the CPU and specific development boards. 
+Code is in several parts conditional, depending on the definitions you make in *environment.h*.
+You will see, that this library is not fixed to Arduino, it may be used for any environment
+where cyclic called functions happen.
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..3af69246689b448266e74521f4ff1d792450456f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/LoopCheck/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "LoopCheck",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/MidiNotes/MidiNotes.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/MidiNotes/MidiNotes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec91464f7411b1f25f33b3b536faf3b8dc1e8dcd
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/MidiNotes/MidiNotes.cpp
@@ -0,0 +1,405 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   Midi.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   27. November 2021
+//
+// Der Inhalt dieser Datei sind Festlegungen für steuerbare Midi-Controller.
+//
+//
+
+#include "MidiNotes.h"
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+//
+
+void MidiNotes::begin(int inBpm, NoteDiv inRes, int inMidiCycle, IntrfBuf *inCRB)
+{
+  dword       stdNoteMicroTick;
+
+  crb = inCRB;                        // Zeiger auf Ringpuffer
+  midiCycle = inMidiCycle;            // Zuklus der ZM in Mikrosekunden
+  bpm = inBpm;                        // Beats Per Minute (Metronom)
+  stdNoteMicroTick = 60000000 / bpm;  // Viertelnotenlänge in Mikrosekunden
+  stdNoteCount = stdNoteMicroTick / inMidiCycle;  // "  in Zyklen der ZM
+  stdNoteTick = 60000 / bpm;          // Viertelnotenlänge in Millisekunden
+  minNoteTick = stdNoteTick / inRes;  // Zu erwartende kürzeste Note (ms)
+
+  typeList[nti0].length   = 8 * stdNoteCount;
+  setNoteType(nti0);
+
+  typeList[nti1].length   = 4 * stdNoteCount;
+  setNoteType(nti1);
+
+  typeList[nti2p].length  = 3 * stdNoteCount;
+  setNoteType(nti2p);
+
+  typeList[nti2].length   = 2 * stdNoteCount;
+  setNoteType(nti2);
+
+  typeList[nti4p].length  = stdNoteCount + stdNoteCount / 2;
+  setNoteType(nti4p);
+
+  // Standard-Note = Viertelnote (
+  typeList[nti4].length   = stdNoteCount;
+  setNoteType(nti4);
+
+  typeList[nti8].length   = stdNoteCount / 2;
+  setNoteType(nti8);
+
+  typeList[nti8p].length  = stdNoteCount / 2 + stdNoteCount / 4;
+  setNoteType(nti8p);
+
+  typeList[nti16].length  = stdNoteCount / 4;
+  setNoteType(nti16);
+
+  typeList[nti16p].length = stdNoteCount / 4 + stdNoteCount / 8;
+  setNoteType(nti16p);
+
+  typeList[nti32].length  = stdNoteCount / 8;
+  setNoteType(nti32);
+
+  typeList[nti32p].length = stdNoteCount / 8 + stdNoteCount / 16;
+  setNoteType(nti32p);
+
+  typeList[nti64].length  = stdNoteCount / 16;
+  setNoteType(nti64);
+
+  typeList[nti64p].length = stdNoteCount / 16 + stdNoteCount / 32;
+  setNoteType(nti64p);
+
+  opMode = momIdle;
+  setChannel(1);
+  stopRun = false;
+  stoppedRun = false;
+  next(smInit);
+}
+
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+//
+void MidiNotes::setNoteType(NoteTypeIdx nt)
+{
+  NoteTypePtr typePtr;
+
+  typePtr = &typeList[nt];
+  typePtr->attack   = 0;
+  typePtr->decay    = 0;
+  typePtr->sustain  = typePtr->length;
+  typePtr->release  = 0;
+  typePtr->pause    = (typePtr->length * 20) / 100;
+
+  typePtr->deltaAttack    = 0;
+  typePtr->deltaDecay     = 0;
+  typePtr->percentSustain = 70;
+  typePtr->deltaRelease   = 0;
+}
+
+
+void MidiNotes::setNoteType(NoteTypeIdx nt, byte pAttL, byte pDecL, byte pSusL, byte pRelL,
+                            byte pPauL, byte dAtt, byte dDec, byte pSusV, byte dRel)
+{
+  NoteTypePtr typePtr;
+
+  typePtr = &typeList[nt];
+  typePtr->attack   = (typePtr->length * pAttL) / 100;
+  typePtr->decay    = (typePtr->length * pDecL) / 100;
+  typePtr->sustain  = (typePtr->length * pSusL) / 100;
+  typePtr->release  = (typePtr->length * pRelL) / 100;
+  typePtr->pause    = (typePtr->length * pPauL) / 100;
+
+  typePtr->deltaAttack    = dAtt;
+  typePtr->deltaDecay     = dDec;
+  typePtr->percentSustain = pSusV;
+  typePtr->deltaRelease   = dRel;
+}
+
+int MidiNotes::addChordNote(NoteTypeIdx nti, byte val, byte vel)
+{
+  NotePtr notePtr;
+  int     i;
+
+  for(i = 0; i < MaxNrNoteSim; i++)
+  {
+    notePtr = &chord[i];
+    if(notePtr->mode == NoteModeEmpty)
+    {
+      notePtr->mode     = NoteModeRun;
+      notePtr->typeIdx  = nti;
+      notePtr->value    = val;
+      notePtr->veloc    = vel;
+      break;
+    }
+  }
+  return(i);
+}
+
+void MidiNotes::setChannel(int chnVal)
+{
+  if(chnVal < 1) chnVal = 1;
+  if(chnVal > 16) chnVal = 16;
+  chn = chnVal - 1;
+}
+
+// ----------------------------------------------------------------------------
+// Betrieb
+// ----------------------------------------------------------------------------
+//
+void MidiNotes::setOpMode(MidiOpMode mom)
+{
+  opMode = mom;
+}
+
+
+void MidiNotes::setChordNote(int idx, NoteTypeIdx nti, int val, int vel)
+{
+  if(idx < 0) return;
+  if(idx >= MaxNrNoteSim) return;
+
+  if(nti >= 0 && nti < ntiNr)
+    newNote[idx].typeIdx = nti;
+
+  if(val >= 0 && val <= 127)
+    newNote[idx].value = val;
+
+  if(vel >= 0 && vel <= 127)
+    newNote[idx].veloc = vel;
+
+  newNote[idx].newVal = true;
+}
+
+
+// ----------------------------------------------------------------------------
+// Steuerung, Zustandsmaschine
+// ----------------------------------------------------------------------------
+//
+
+void MidiNotes::stop()
+{
+  stopRun = true;
+}
+
+void MidiNotes::resume()
+{
+  stopRun = false;
+  stoppedRun = false;
+}
+
+void MidiNotes::run()
+{
+  runCounter++;
+  if(cycleCnt > 0) cycleCnt--;
+
+  if(nextState != NULL)
+    (this->*nextState)();
+}
+
+void MidiNotes::smInit()
+{
+  next(smIdle);
+}
+
+void MidiNotes::smIdle()
+{
+  switch(opMode)
+  {
+    case momIdle:
+      break;
+
+    case momSequence:
+      next(smNoteOn);
+      break;
+
+    case momRunDelta:
+      break;
+  }
+}
+
+void MidiNotes::smNoteOn()
+{
+  int   i, j, tIdx;
+  bool  doAttack;
+  dword attack, sustain;
+
+  if(stopRun || stoppedRun)         // Unterbrechen/Stoppen des Ablaufs
+  {                                 // vor dem Einschalten einer Note
+    stoppedRun = true;
+    return;
+  }
+
+  if(crb == NULL)                   // Ohne Ausgabepuffer in Wartezustand
+  {
+    next(smIdle);
+    return;
+  }
+
+  doAttack = false;                 // Voreinstellung kein Aufklingen
+
+  // Auslesen der Noten aus dem Akkordspeicher
+  //
+  j = 0;
+  for(i = 0; i < MaxNrNoteSim; i++)
+  {
+    notePtr = &chord[i];
+
+    if(i == 0)  // erste Note
+    {
+      if(notePtr->mode == NoteModeEmpty)  // Wenn die erste Note leer ist
+      {                                   // dann in den Wartezustand
+        next(smIdle);
+        return;
+      }
+      noteSeq[j++] = 0x90 | chn;          // ansonsten startet die Notenfolge **
+    }
+    else        // weitere Noten
+    {
+      if(notePtr->mode == NoteModeEmpty)  // bei leerer Note Schleife beendet
+        break;
+    }
+
+    // Die Noten im Akkordspeicher können durch aktuelle Noten
+    // ersetzt werden.
+
+    if(newNote[i].newVal) // wenn neue Note vorliegt
+    {
+      newNote[i].newVal = false;                  // neue Note quittieren
+      notePtr->typeIdx = newNote[i].typeIdx;      // und Inhalte im
+      notePtr->value = newNote[i].value;          // Akkordspeicher
+      notePtr->veloc = newNote[i].veloc;          // überschreiben
+    }
+
+    noteSeq[j++] = notePtr->value;        // Notenwert in Sequenz eintragen   **
+
+    // Daten für die Note aus der Typenliste holen
+    //
+    tIdx = notePtr->typeIdx;
+    typePtr = &typeList[tIdx];
+    notePtr->cntAttack  = typePtr->attack;    // Aufklingzeit in Zähler
+    notePtr->cntDecay   = typePtr->decay;     // Abklingzeit in Zähler
+    notePtr->cntSustain = typePtr->sustain;   // Klingzeit in Zähler
+    notePtr->cntRelease = typePtr->release;   // Ausklingzeit in Zähler
+    notePtr->cntPause   = typePtr->pause;     // Pausenzeit in Zähler
+
+    if(notePtr->cntAttack != 0)   // Wenn ein Attack-Wert gegeben ist
+    {
+      doAttack = true;            // dann attack markieren
+      attack =                    // und den Wert auf den erste Schritt setzen
+          (typePtr->deltaAttack * notePtr->veloc) / 100;
+      if(attack > 127) attack = 127;
+      noteSeq[j++] = attack;              // Lautstärke in Sequenz eintragen  **
+    }
+    else  // ohne Attack-Wert geht es hier gleich in Sustain weiter
+    {
+      sustain = (typePtr->percentSustain * notePtr->veloc) / 100;
+      if(sustain > 127) sustain = 127;
+      noteSeq[j++] = sustain;             // Lautstärke in Sequenz eintragen  **
+    }
+  }
+
+  crb->putSeq(noteSeq, j);                // Sequenz an Puffer übergeben   *****
+
+  if(doAttack)
+    next(smAttack);
+  else
+    next(smSustain);
+}
+
+void MidiNotes::smAttack()
+{
+
+}
+
+void MidiNotes::smDecay()
+{
+
+}
+
+// TODO
+// Es können noch nicht Noten unterschiedlicher Länge in einem Akkord
+// verarbeitet werden. Bei mehreren eingetragenen Noten würde die
+// kürzeste Note den Ablauf bestimmen.
+
+void MidiNotes::smSustain()
+{
+  int   i;
+  bool  sustFin;
+
+  sustFin = false;
+  for(i = 0; i < MaxNrNoteSim; i++)
+  {
+    notePtr = &chord[i];
+    if(notePtr->mode == NoteModeEmpty)
+      break;
+
+    if(notePtr->cntSustain > 0)     // Die Sustain-Zeit in diesem Zustand verweilen
+      notePtr->cntSustain--;
+    else
+      sustFin = true;
+  }
+
+  if(sustFin)
+    next(smNoteOff);
+}
+
+void MidiNotes::smRelease()
+{
+
+}
+
+void MidiNotes::smNoteOff()
+{
+  int   i,j;
+
+  j = 0;
+  for(i = 0; i < MaxNrNoteSim; i++)   // Alle Noten im Akkord bearbeiten
+  {
+    notePtr = &chord[i];
+    if(notePtr->mode == NoteModeEmpty)
+      break;
+
+    if(i == 0)
+    {
+      noteSeq[j++] = 0x80 | chn;      // Erste Note bestimmt den Befehl AUS    **
+      absPause = notePtr->cntPause;
+    }
+
+    noteSeq[j++] = notePtr->value;    //Erste und weitere Noten liefern Liste  **
+    noteSeq[j++] = 0;
+  }
+
+  crb->putSeq(noteSeq, j);            // Sequenz an Puffer übergeben   *****
+
+  next(smPause);
+}
+
+void MidiNotes::smPause()
+{
+  if(absPause > 0)
+  {
+    absPause--;
+    return;
+  }
+
+  next(smNoteOn);
+}
+
+// ----------------------------------------------------------------------------
+// Debugging
+// ----------------------------------------------------------------------------
+//
+
+
+
+
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/MidiNotes/MidiNotes.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/MidiNotes/MidiNotes.h
new file mode 100644
index 0000000000000000000000000000000000000000..0f09fccd7d1a19c3c9171b0cf96c8320f5ad0b44
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/MidiNotes/MidiNotes.h
@@ -0,0 +1,226 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   MidiNotes.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   27. November 2021
+//
+// Der Inhalt dieser Datei sind Festlegungen für steuerbare Midi-Controller
+//
+
+#ifndef MidiNotes_h
+#define MidiNotes_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+#include "ComRingBuf.h"
+
+#define MaxNrNoteSim    4
+#define MaxMidiSeq      (2 * MaxNrNoteSim + 1)
+
+// Definierte Noten
+//
+#define SchlossC    60
+#define Kammerton   69
+
+typedef enum  _NoteDiv
+{
+  nd4   = 1,
+  nd8   = 2,
+  nd16  = 4,
+  nd32  = 8,
+  nd64  = 16
+} NoteDiv;
+
+typedef enum  _MidiOpMode
+{
+  momIdle,
+  momSequence,
+  momRunDelta
+} MidiOpMode;
+
+
+// ----------------------------------------------------------------------------
+//                            M i d i N o t e s
+// ----------------------------------------------------------------------------
+//
+class MidiNotes
+{
+#define next(x) nextState = &MidiNotes::x
+
+public:
+  // -------------------------------------------------------------------------
+  // Öffentliche Datentypen
+  // -------------------------------------------------------------------------
+  //
+  typedef enum _NoteTypeIdx
+  {
+    nti0  = 0,
+    nti1,
+    nti2p,
+    nti2,
+    nti4p,
+    nti4,
+    nti8p,
+    nti8,
+    nti16p,
+    nti16,
+    nti32p,
+    nti32,
+    nti64p,
+    nti64,
+    ntiNr
+  } NoteTypeIdx;
+
+
+private:
+  // -------------------------------------------------------------------------
+  // Private Datentypen
+  // -------------------------------------------------------------------------
+  //
+  typedef void (MidiNotes::*cbVector)(void);
+
+  typedef struct _NoteType
+  {
+    dword   length;
+    dword   attack;
+    dword   decay;
+    dword   sustain;
+    dword   release;
+    dword   pause;
+    byte    deltaAttack;
+    byte    deltaDecay;
+    byte    percentSustain;
+    byte    deltaRelease;
+  } NoteType, *NoteTypePtr;
+
+  typedef struct  _Note
+  {
+    byte      mode;
+    byte      typeIdx;
+    byte      value;
+    byte      veloc;
+    int       state;
+    dword     cntAttack;
+    dword     cntDecay;
+    dword     cntSustain;
+    dword     cntRelease;
+    dword     cntPause;
+  } Note, *NotePtr;
+
+  typedef struct _NewNote
+  {
+    bool      newVal;
+    byte      typeIdx;
+    byte      value;
+    byte      veloc;
+  }NewNote;
+
+#define NoteModeEmpty     0x00
+#define NoteModeRun       0x01
+#define NoteModeDoChange  0x02
+
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  IntrfBuf    *crb;
+  cbVector    nextState;
+
+  MidiOpMode  opMode;
+
+  dword     runCounter;
+  dword     cycleCnt;
+
+  dword     midiCycle;      // Zustandstakt in Mikrosekunden
+  dword     minNoteTick;    // minimale Notendauer in Millisekunden
+  dword     bpm;            // Beats per Minute (Metronom)
+  dword     stdNoteTick;    // Dauer einer Viertelnote in Millisekunden
+  dword     stdNoteCount;   // Viertelnote in Zyklen der Zustandsmaschine
+
+  Note      chord[MaxNrNoteSim];  // Liste der simultanen Noten (Akkord)
+  NoteType  typeList[ntiNr];      // Liste der Notentypen
+  byte      chn;                  // Aktueller Kanal
+  byte      noteSeq[MaxMidiSeq];  // Lokaler Telegrammaufbau
+
+  NotePtr     notePtr;      // Temporäre Notendaten
+  NoteTypePtr typePtr;      // Temporärer Notentyp
+
+  dword     absPause;       // Pause für den zyklischen Ablauf
+  NewNote   newNote[MaxNrNoteSim];  // Übergabe neuer Noten
+
+  bool      stopRun;           // Anhalten der Midi-Schleife
+  bool      stoppedRun;        // Midi-Schleife angehalten
+
+
+  // --------------------------------------------------------------------------
+  // Lokale Funktionen
+  // --------------------------------------------------------------------------
+  //
+
+  // Zustandsmaschine
+  // -----------------------------
+  void smInit();
+  void smIdle();
+
+  void smNoteOn();
+  void smAttack();
+  void smDecay();
+  void smSustain();
+  void smRelease();
+  void smNoteOff();
+  void smPause();
+
+
+  // --------------------------------------------------------------------------
+  // Inline-Funktionen
+  // --------------------------------------------------------------------------
+  //
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+  void begin(int inBpm, NoteDiv inRes, int inMidiCycle, IntrfBuf *inCRB);
+
+
+  // --------------------------------------------------------------------------
+  // Konfiguration
+  // --------------------------------------------------------------------------
+  //
+  void  setNoteType(NoteTypeIdx nt);
+
+  void  setNoteType(NoteTypeIdx nt, byte pAttL, byte pDecL, byte pSusL, byte pRelL,
+                    byte dAtt, byte dDec, byte pSusV, byte dRel, byte pPauL);
+
+  int   addChordNote(NoteTypeIdx nti, byte val, byte vel);
+
+  void  setChannel(int chnVal);
+
+  // --------------------------------------------------------------------------
+  // Betrieb
+  // --------------------------------------------------------------------------
+  //
+  void setOpMode(MidiOpMode mom);
+  void setChordNote(int idx, NoteTypeIdx nti, int val, int vel);
+
+  // --------------------------------------------------------------------------
+  // Steuerung, Zustandsmaschine
+  // --------------------------------------------------------------------------
+  //
+  void run();
+  void stop();
+  void resume();
+
+  // --------------------------------------------------------------------------
+  // Debugging
+  // --------------------------------------------------------------------------
+  //
+
+};
+
+
+// ----------------------------------------------------------------------------
+#endif // MidiNotes_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/MidiNotes/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/MidiNotes/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..a95d68926746af5b6e20d30d2a29ea5b513110ad
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/MidiNotes/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "MidiNotes",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/Monitor/Monitor.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/Monitor/Monitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c30d24b20011e8d22623c261a295ccfb42fe1ea
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/Monitor/Monitor.cpp
@@ -0,0 +1,1165 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   Monitor.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   15. Mai 2021
+//
+// Der Monitor dient zum direkten Zugriff auf die Ressourcen eines
+// Mikrocontrollers über die serielle Schnittstelle.
+// ACHTUNG!
+// Er ist nicht für die Anwendung des "Serial Monitor" aus der Arduino-IDE
+// bzw. aus Eclipse/Sloeber gedacht, sondern für ein typisches "Terminal".
+// Verwendet wurde bei der Entwicklung unter Linux das GtkTerm.
+//
+
+#include "Monitor.h"
+
+//-----------------------------------------------------------------------------
+// Initialisierungen
+//-----------------------------------------------------------------------------
+
+void Monitor::init(int inMode, int inCpu, LoopCheck *inLcPtr, IntrfTw *inTwPtr)
+{
+  mode          = inMode;
+  cpu           = inCpu;
+  wrIdx         = 0;
+  rdIdx         = 0;
+  blkOut        = false;
+  blkIn         = false;
+  inIdx         = 0;
+  info          = NULL;
+  readOffsAddr  = 0;
+  doReadReg     = false;
+  extraIn       = false;
+  lcPtr         = inLcPtr;
+  twiPtr        = inTwPtr;
+  nrOfChnChar   = '@';
+
+#ifdef smnNANOBLE33
+
+  microTicValPtr  = (dword *) 0x40009548;
+  microTicCapPtr  = (dword *) 0x40009048;
+
+#endif
+
+  nextState =
+      &Monitor::waitEnter;
+}
+
+
+Monitor::Monitor(int inMode, int inCpu)
+{
+  init(inMode, inCpu, NULL, NULL);
+}
+
+Monitor::Monitor(int inMode, int inCpu, LoopCheck *inLcPtr)
+{
+  init(inMode, inCpu, inLcPtr, NULL);
+}
+
+Monitor::Monitor(int inMode, int inCpu, LoopCheck *inLcPtr, IntrfTw *inTwiPtr)
+{
+  init(inMode, inCpu, inLcPtr, inTwiPtr);
+}
+
+//-----------------------------------------------------------------------------
+// Konfiguration, Hilfsfunktionen
+//-----------------------------------------------------------------------------
+//
+int Monitor::putBuf(char c)
+{
+  if(blkIn) return(-1);
+
+  int free = rdIdx - wrIdx - 1;
+  if(free < 0) free += BufSize;
+  if(free < 1) return(0);
+  buffer[wrIdx++] = c;
+  if(wrIdx == BufSize)
+    wrIdx = 0;
+  return(1);
+}
+
+int Monitor::putBuf(char *txt)
+{
+  if(blkIn) return(-1);
+
+  int free = rdIdx - wrIdx - 1;
+  int size = strlen(txt);
+  if(free < 0) free += BufSize;
+  if(free < size) return(0);
+  for(int i = 0; i < size; i++)
+  {
+  buffer[wrIdx++] = txt[i];
+  if(wrIdx == BufSize)
+    wrIdx = 0;
+  }
+  return(size);
+}
+
+char Monitor::getBuf()
+{
+  int num = wrIdx - rdIdx;
+  if(num == 0) return('\0');
+  char c = buffer[rdIdx++];
+  if(rdIdx == BufSize)
+    rdIdx = 0;
+  return(c);
+}
+
+void Monitor::clrBuf()
+{
+  wrIdx = 0;
+  rdIdx = 0;
+}
+
+void Monitor::sendConfig()
+{
+  int           nrChn   = nrOfChnChar & 0x3F;
+  int           bufIdx  = 0;
+  CfgMeasChnPtr cfgPtr;
+
+  // Visualisierungskanäle (Anzahl) anfordern
+  outChar[bufIdx++] = '&';
+  outChar[bufIdx++] = '@';    // Kanalnummer
+  outChar[bufIdx++] = '@';    // Typ
+  outChar[bufIdx++] = nrOfChnChar;
+  outChar[bufIdx++] = '$';
+
+  for(int i = 0; i < nrChn; i++)
+  {
+    cfgPtr = &cfgChnArr[i];
+    outChar[bufIdx++] = '&';
+    outChar[bufIdx++] = (i+1) | 0x40;
+    outChar[bufIdx++] = cfgPtr->type;
+    hexWord(&outChar[bufIdx], cfgPtr->maxVal);
+    bufIdx += 4;
+    hexWord(&outChar[bufIdx], cfgPtr->minVal);
+    bufIdx += 4;
+    if(cfgPtr->name != NULL)
+    {
+      bufIdx += cpyStr(&outChar[bufIdx], cfgPtr->name);
+    }
+    outChar[bufIdx++] = '$';
+  }
+  outChar[bufIdx] = '\0';
+  out(outChar);
+}
+
+//-----------------------------------------------------------------------------
+// Lokale Abläufe
+//-----------------------------------------------------------------------------
+//
+
+volatile dword calcTest1, calcTest2, calcTest3;
+
+void Monitor::waitEnter()
+{
+  char  c;
+
+  busy = false;
+
+  if(!keyHit()) return;
+  c = keyIn();
+  if(c != '\r' && c != '\n')
+  {
+    lastKeyIn = c;
+    return;
+  }
+
+  busy = true;
+
+  blkIn   = true;
+  blkOut  = true;
+  GoPrm
+}
+
+void doSomeCode()
+{
+  for(int i = 0; i < 500; i++)
+  {
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+  }
+}
+
+volatile dword micTime;
+
+void Monitor::getKey()
+{
+  char  cin,c1,c0;
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  if(mode & modeEcho)
+    out(cin);
+
+  c0 = c1 = '\0';
+
+  if(inIdx == 0)
+    c0 = cin;
+  else if(inIdx == 1)
+  {
+    c0 = inChar[0];
+    c1 = cin;
+  }
+  else if(inIdx == 2)
+  {
+    c0 = inChar[0];
+    c1 = inChar[1];
+  }
+
+  switch(c0)
+  {
+    case '\r':
+      out("\r\n");
+      blkIn   = false;
+      blkOut  = false;
+      GoWt
+      break;
+
+    case 'c':
+    case 'C':
+      if(inIdx == 0)
+      {
+        inChar[inIdx] = cin;
+        inIdx++;
+      }
+      else if(inIdx == 1)
+      {
+
+        if(cin >= '0' && cin <= '9')
+        {
+          inIdx = 0;
+          out('=');
+          int cIdx = cin - 0x30;
+          if(cFlag[cIdx])
+          {
+            cFlag[cIdx] = false;
+            out('0');
+          }
+          else
+          {
+            cFlag[cIdx] = true;
+            out('1');
+          }
+          GoPrm
+        }
+
+        else if(cin == 'f' || cin == 'F')
+        {
+          inChar[inIdx] = cin;
+          inIdx++;
+        }
+      }
+
+      else if(inIdx == 2)
+      {
+        inIdx = 0;
+        if(cin == 'g' || cin == 'G')
+        {
+          sendConfig();
+          GoPrm
+        }
+      }
+      else
+        GoPrm
+      break;
+
+    case 'i':
+    case 'I':
+      if(inIdx == 0)
+      {
+        inChar[inIdx] = cin;
+        inIdx++;
+      }
+      else if(inIdx == 1)
+      {
+        inIdx = 0;
+        out(' ');
+        if(cin == 'a' || cin == 'A')
+          nextState = &Monitor::getTwiAdr;
+        else if(cin == 'l' || cin == 'L')
+          nextState = &Monitor::readTwiList;
+        else if(cin == 'r' || cin == 'R')
+          nextState = &Monitor::readTwiByte;
+        else if(cin == 'w' || cin == 'W')
+          nextState = &Monitor::writeTwiByte;
+      }
+      break;
+
+    case 'r':
+    case 'R':
+      if(inIdx == 0)
+      {
+        inChar[inIdx] = cin;
+        inIdx++;
+      }
+      else if(inIdx == 1)
+      {
+        inIdx = 0;
+        out(' ');
+        if(cin == 'o' || cin == 'O')
+          nextState = &Monitor::getRdOffsAdr;
+        else if(cin == 'r' || cin == 'R')
+          nextState = &Monitor::readRegVal;
+      }
+      break;
+
+    // ------------------------------------------------------------------------
+    case 't':     //                 Zeitmessungen
+    case 'T':     //
+    // ------------------------------------------------------------------------
+      if(inIdx == 0)
+      {
+        inChar[inIdx] = cin;
+        inIdx++;
+      }
+      else if(inIdx == 1)
+      {
+        inIdx = 0;
+        nextState = &Monitor::getTiming;
+        if(cin == 'l' || cin == 'L')
+        {
+          cmdMode1 = 'L';
+        }
+        else if(cin == 'b' || cin == 'B')
+        {
+          cmdMode1 = 'B';
+        }
+        else if(cin == 'c' || cin == 'C')
+        {
+          cmdMode1 = 'C';
+        }
+#ifdef smnNANOBLE33
+        else if(cin == 'p' || cin == 'P')
+        {
+          micTime = micsecs();
+          doSomeCode();
+          micTime = (micsecs() - micTime - 11) / 10;
+          out(' ');
+          out(micTime);
+          GoPrm
+        }
+#endif
+        else if(cin == 'r' || cin == 'R')
+        {
+          if(lcPtr != NULL)
+          {
+            lcPtr->resetStatistics();
+            out(' ');
+          }
+          GoPrm
+        }
+        else if(cin == 't' || cin == 'T')
+        {
+          dword micTime = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          micTime = (micros() - micTime) / 20;
+          out(' ');
+          out(micTime);
+          GoPrm
+        }
+        else
+        {
+          GoPrm
+        }
+      }
+      break;
+
+    case 'V':
+    case 'v':
+      out(' ');
+      nextState = &Monitor::version;
+      break;
+
+  }
+}
+
+void Monitor::prompt()
+{
+  if(mode & modeNl)
+    out('\n');
+
+  out("\rM>");
+  GoInp
+}
+
+void Monitor::version()
+{
+  out("Monitor: Version 0.1, May 16, 2021");
+  GoPrm
+}
+
+void Monitor::getRdOffsAdr()
+{
+  char  cin;
+  dword val;
+  int   valIdx;
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  readOffsAddr = 0;
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx < 16)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    valIdx = 0;
+    inIdx--;
+    while(inIdx >= 0)
+    {
+      val = inChar[inIdx];
+      readOffsAddr |= val << valIdx * 4;
+      inIdx--;
+      valIdx++;
+    }
+
+    // TEST
+    //out(" = ");
+    //out(readOffsAddr);
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::readRegVal()
+{
+  char  cin;
+  dword val,adr;
+  int   valIdx;
+
+  dword *regPtr;
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  adr = 0;
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx < 16)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    valIdx = 0;
+    inIdx--;
+    while(inIdx >= 0)
+    {
+      val = inChar[inIdx];
+      adr |= val << valIdx * 4;
+      inIdx--;
+      valIdx++;
+    }
+
+    regPtr = (dword *) (readOffsAddr + adr);
+    val = *regPtr;
+
+    out(": ");
+    hexDword(outChar, val);
+    out(outChar);
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::getTiming()
+{
+  LoopStatistics  lStat;
+  unsigned int    maxVal;
+  unsigned int    minVal;
+  unsigned int    avgVal;
+  char  cin;
+
+  if(lcPtr == NULL)
+  {
+    outl("Kein LoopCheck.");
+    GoPrm
+    return;
+  }
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  if(mode & modeEcho)
+    out(cin);
+
+  if(cin == 'r' || cin == 'R')
+  {
+    out(' ');
+    lcPtr->getStatistics(&lStat);
+    if(cmdMode1 == 'L')
+    {
+      maxVal = lStat.loopMaxTime;
+      minVal = lStat.loopMinTime;
+      avgVal = lStat.loopAvgTime;
+    }
+    else if(cmdMode1 == 'B')
+    {
+      maxVal = lStat.bgMaxTime;
+      minVal = lStat.bgMinTime;
+      avgVal = lStat.bgAvgTime;
+    }
+    else if(cmdMode1 == 'C')
+    {
+      maxVal = lStat.maxPeriod;
+      minVal = lStat.minPeriod;
+      avgVal = lStat.avgPeriod;
+    }
+    else
+    {
+      maxVal = 0;
+      minVal = 0;
+      avgVal = 0;
+    }
+
+    out(maxVal); out("/"); out(minVal); out("/"); out(avgVal); out("\r");
+    GoPrm
+  }
+  else if(cin == 'm' || cin == 'M')
+  {
+    lcPtr->resetStatistics();
+    lcPtr->startTimeMeasure();
+    nextState = &Monitor::getLoopMeasure;
+  }
+
+}
+
+void Monitor::getLoopMeasure()
+{
+  LoopStatistics  lStat;
+  unsigned int    maxVal;
+  unsigned int    minVal;
+  unsigned int    avgVal;
+
+  if(lcPtr->getTimeMeasure() < 1000000)
+    return;
+
+  out(' ');
+  lcPtr->getStatistics(&lStat);
+  if(cmdMode1 == 'L')
+  {
+    maxVal = lStat.loopMaxTime;
+    minVal = lStat.loopMinTime;
+    avgVal = lStat.loopAvgTime;
+  }
+  else if(cmdMode1 == 'B')
+  {
+    maxVal = lStat.bgMaxTime;
+    minVal = lStat.bgMinTime;
+    avgVal = lStat.bgAvgTime;
+  }
+  else if(cmdMode1 == 'C')
+  {
+    maxVal = lStat.maxPeriod;
+    minVal = lStat.minPeriod;
+    avgVal = lStat.avgPeriod;
+  }
+  else
+  {
+    maxVal = 0;
+    minVal = 0;
+    avgVal = 0;
+  }
+
+  out(maxVal); out("/"); out(minVal); out("/"); out(avgVal); out("\r");
+  GoPrm
+}
+
+
+void Monitor::getTwiAdr()
+{
+  char  cin;
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  twiAdr = 0;
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx < 2)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    twiAdr = (inChar[0] << 4) | inChar[1];
+
+    out(" = ");
+    out(twiAdr);
+
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::readTwiList()
+{
+  char  cin;
+  int   reg;
+  int   anz;
+
+  char  tmpOut[3];
+
+  TwiStatus twiStatus;
+
+  if(twiPtr == NULL)
+  {
+    out("no Twi");
+    inIdx = 0;
+    GoPrm
+  }
+
+  if(!keyHit()) return;
+  cin = keyIn();
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx == 1)
+      out(" ");
+
+    if(inIdx < 4)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    reg = (inChar[0] << 4) | inChar[1];
+    anz = (inChar[2] << 4) | inChar[3];
+
+    twiByteSeq.len = anz;
+    twiByteSeq.valueRef = byteArray;
+
+    twiStatus = twiPtr->readByteRegSeq(twiAdr, reg, &twiByteSeq);
+
+    out(" [");
+    out((int) twiStatus);
+    out("] ");
+
+    if((int) twiStatus == 128)
+    {
+      for(int i = 0; i < anz; i++)
+      {
+        hexByte(tmpOut, byteArray[i]);
+        out(tmpOut);
+        if(i != (anz-1)) out(':');
+      }
+    }
+
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::readTwiByte()
+{
+  char  cin;
+  int   reg;
+  byte  val;
+
+  if(twiPtr == NULL)
+  {
+    out("no Twi");
+    inIdx = 0;
+    GoPrm
+  }
+
+  if(!keyHit()) return;
+  cin = keyIn();
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx < 2)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    reg = (inChar[0] << 4) | inChar[1];
+
+    val = twiPtr->readByteReg(twiAdr, reg);
+
+    out(" = ");
+    binByte(outChar, val);
+    out(outChar);
+
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::writeTwiByte()
+{
+  char  cin;
+  int   reg;
+  int   val;
+
+  TwiStatus twiStatus;
+
+  if(twiPtr == NULL)
+  {
+    out("no Twi");
+    inIdx = 0;
+    GoPrm
+  }
+
+  if(!keyHit()) return;
+  cin = keyIn();
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx == 1)
+      out(" ");
+
+    if(inIdx < 4)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    reg = (inChar[0] << 4) | inChar[1];
+    val = (inChar[2] << 4) | inChar[3];
+
+    twiStatus = twiPtr->writeByteReg(twiAdr, reg, val);
+
+    out(" : ");
+    out((int) twiStatus);
+
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Lokale Schnittstelle
+//-----------------------------------------------------------------------------
+//
+void Monitor::print(char c, int eol)
+{
+  putBuf(c);
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+void Monitor::print(char *txt, int eol)
+{
+  if(txt != NULL)
+    putBuf(txt);
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+void Monitor::print(byte *hex, int nr, char fill, int eol)
+{
+  if(hex == NULL) return;
+
+  for(int i = 0; i < nr; i++)
+  {
+    hexByte(tmpChar,hex[i]);
+    tmpChar[2] = fill;
+    tmpChar[3] = '\0';
+    putBuf(tmpChar);
+  }
+
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+void Monitor::print(unsigned int iVal, int eol)
+{
+  char  iBuf[16];
+
+  itoa(iVal, iBuf, 10);
+  putBuf(iBuf);
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+void Monitor::prints(int iVal, int eol)
+{
+  char  iBuf[16];
+
+  itoa(iVal, iBuf, 10);
+  putBuf(iBuf);
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+//-----------------------------------------------------------------------------
+// Datenaufbereitung
+//-----------------------------------------------------------------------------
+//
+void Monitor::hexByte(char * dest, byte val)
+{
+  char cv;
+
+  cv = val >> 4;
+  if(cv < 10)
+    cv += 0x30;
+  else
+    cv += 0x37;
+  dest[0] = cv;
+
+  cv = val & 0x0F;
+  if(cv < 10)
+    cv += 0x30;
+  else
+    cv += 0x37;
+  dest[1] = cv;
+
+  dest[2] = '\0';
+}
+
+void Monitor::binByte(char * dest, byte val)
+{
+  byte mask;
+
+  mask = 0x80;
+
+  for(int i = 0; i < 8; i++)
+  {
+    if((val & mask) != 0)
+      dest[i] = '1';
+    else
+      dest[i] = '0';
+    mask >>= 1;
+  }
+
+  dest[8] = '\0';
+}
+
+int   Monitor::cpyStr(char *dest, char *src)
+{
+  int   i = 0;
+
+  while((dest[i] = src[i]) != '\0') i++;
+  return(i);
+}
+
+void Monitor::binDword(char *dest, dword dwVal)
+{
+  int   idx = 0;
+  byte  bVal;
+
+  bVal = dwVal >> 24;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+  dest[idx++] = ' ';
+
+  bVal = dwVal >> 16;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+  dest[idx++] = ' ';
+
+  bVal = dwVal >> 8;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+  dest[idx++] = ' ';
+
+  bVal = dwVal;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+
+  dest[idx] = '\0';
+}
+
+void Monitor::hexDword(char *dest, dword dwVal)
+{
+  int   idx = 0;
+  byte  bVal;
+
+  bVal = dwVal >> 24;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  bVal = dwVal >> 16;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  bVal = dwVal >> 8;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  bVal = dwVal;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  dest[idx] = '\0';
+}
+
+void Monitor::binWord(char *dest, word wVal)
+{
+  int   idx = 0;
+  byte  bVal;
+
+  bVal = wVal >> 8;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+  dest[idx++] = ' ';
+
+  bVal = wVal;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+
+  dest[idx] = '\0';
+}
+
+void Monitor::hexWord(char *dest, word wVal)
+{
+  int   idx = 0;
+  byte  bVal;
+
+  bVal = wVal >> 8;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  bVal = wVal;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  dest[idx] = '\0';
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Anwenderschnittstelle
+//-----------------------------------------------------------------------------
+//
+
+void Monitor::run()
+{
+  char c;
+
+  if(!blkOut)
+  {
+    c = getBuf();
+    if(c != '\0')
+      smnSerial.print(c);
+  }
+  (this->*nextState)();
+}
+
+void Monitor::cprint(char c)
+{
+  print(c, 0);
+}
+
+void Monitor::cprintln(char c)
+{
+  print(c, eolCR | eolLF);
+}
+
+void Monitor::cprintcr(char c)
+{
+  print(c, eolCR);
+}
+
+void Monitor::print(char *txt)
+{
+  print(txt, 0);
+}
+
+void Monitor::println(char *txt)
+{
+  print(txt, eolCR | eolLF);
+}
+
+void Monitor::println()
+{
+  print((char *) NULL, eolCR | eolLF);
+}
+
+void Monitor::printcr(char *txt)
+{
+  print(txt, eolCR);
+}
+
+void Monitor::printcr()
+{
+  print((char *) NULL, eolCR);
+}
+
+void Monitor::print(unsigned int iVal)
+{
+  print(iVal, 0);
+}
+
+void Monitor::prints(int iVal)
+{
+  prints(iVal, 0);
+}
+
+void Monitor::println(unsigned int iVal)
+{
+  print(iVal, eolCR | eolLF);
+}
+
+void Monitor::printcr(unsigned int iVal)
+{
+  print(iVal, eolCR);
+}
+
+void Monitor::print(byte *iVal, int nr, char fill)
+{
+  print(iVal, nr, fill, 0);
+}
+
+void Monitor::printcr(byte *iVal, int nr, char fill)
+{
+  print(iVal, nr, fill, eolCR);
+}
+
+void Monitor::println(byte *iVal, int nr, char fill)
+{
+  print(iVal, nr, fill, eolCR | eolLF);
+}
+
+void Monitor::setInfo(char *txt)
+{
+  info = txt;
+}
+
+void Monitor::config(int inNrOfChn)
+{
+  if(inNrOfChn < 0) return;
+
+  if(inNrOfChn > MaxChn)
+    inNrOfChn = MaxChn;
+
+  nrOfChnChar = inNrOfChn | 0x40;
+}
+
+void Monitor::config(int inChn, char inType, word inMax, word inMin, char *inName)
+{
+  if(inChn < 1) return;
+
+  if(inChn > MaxChn)
+    inChn = MaxChn;
+
+  CfgMeasChnPtr chnPtr = &cfgChnArr[inChn-1];
+  chnPtr->maxVal = inMax;
+  chnPtr->minVal = inMin;
+  chnPtr->name = inName;
+  chnPtr->type = inType;
+}
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/Monitor/Monitor.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/Monitor/Monitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ee2bb11830c716703e5489655355c93a039d131
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/Monitor/Monitor.h
@@ -0,0 +1,211 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   Monitor.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   15. Mai 2021
+//
+// Der Monitor dient zum direkten Zugriff auf die Ressourcen eines
+// Mikrocontrollers über die serielle Schnittstelle.
+//
+
+#include  "Arduino.h"
+#include  "environment.h"
+#include  "arduinoDefs.h"
+#include  "LoopCheck.h"
+#include  "IntrfTw.h"
+
+#ifndef Monitor_h
+#define Monitor_h
+// ----------------------------------------------------------------------------
+
+#define keyHit()  smnSerial.available()
+#define keyIn()   smnSerial.read()
+#define out(x)    smnSerial.print(x)
+#define outl(x)   smnSerial.println(x)
+#define GoInp     nextState = &Monitor::getKey;
+#define GoPrm     nextState = &Monitor::prompt;
+#define GoWt      nextState = &Monitor::waitEnter;
+
+#define modeEcho  0x01
+#define modeNl    0x02
+
+#define eolCR     0x01
+#define eolLF     0x02
+#define eolNL     0x03
+
+#define BufSize   512
+#define MaxChn    32
+
+class Monitor
+{
+  // -------------------------------------------------------------------------
+  // class specific data types
+  // -------------------------------------------------------------------------
+  //
+  typedef void (Monitor::*StatePtr)(void);
+  typedef struct _ConfMeasChannel
+  {
+    word    maxVal;
+    word    minVal;
+    char    *name;
+    char    type;
+  } CfgMeasChn, *CfgMeasChnPtr;
+
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  int       cpu;
+  int       mode;
+
+#ifdef smnNANOBLE33
+  dword     *microTicValPtr;
+  dword     *microTicCapPtr;
+#endif
+
+  char      buffer[BufSize];
+  int       wrIdx;
+  int       rdIdx;
+  bool      blkOut;
+  bool      blkIn;
+
+  char      inChar[16];
+  char      outChar[128];
+  char      tmpChar[8];
+  int       inIdx;
+  bool      extraIn;
+
+  char      cmdMode1;
+  char      cmdMode2;
+
+  char      *info;
+
+  StatePtr  nextState;
+  LoopCheck *lcPtr;
+
+  IntrfTw     *twiPtr;
+  int         twiAdr;
+  TwiByteSeq  twiByteSeq;
+  byte        byteArray[32];
+
+  dword       readOffsAddr;
+  bool        doReadReg;
+
+  CfgMeasChn  cfgChnArr[MaxChn];
+  char        nrOfChnChar;
+
+  // --------------------------------------------------------------------------
+  // Lokale Funktionen
+  // --------------------------------------------------------------------------
+  //
+  void  init(int mode, int cpu);
+  void  init(int mode, int cpu, LoopCheck *inLcPtr);
+  void  init(int mode, int cpu, LoopCheck *inLcPtr, IntrfTw *inTwPtr);
+
+  void  waitEnter();
+  void  prompt();
+  void  getKey();
+  void  version();
+  void  getRdOffsAdr();
+  void  readRegVal();
+  void  getTiming();
+  void  getLoopMeasure();
+
+  void  getTwiAdr();
+  void  readTwiList();
+  void  readTwiByte();
+  void  writeTwiByte();
+
+  void  print(char c, int eol);
+  void  print(char *txt, int eol);
+  void  print(byte *hex, int nr, char fill, int eol);
+  void  print(unsigned int iVal, int eol);
+  void  prints(int iVal, int eol);
+
+#ifdef smnNANOBLE33
+
+  dword micsecs()
+  {
+    *microTicCapPtr = 1;
+    return(*microTicValPtr);
+  }
+
+#endif
+
+  // --------------------------------------------------------------------------
+  // Datenaufbereitung
+  // --------------------------------------------------------------------------
+  //
+  void hexByte(char *dest, byte val);
+  void binByte(char *dest, byte val);
+  void hexWord(char *dest, word val);
+  void binWord(char *dest, word val);
+  void hexDword(char *dest, dword val);
+  void binDword(char *dest, dword val);
+  int  cpyStr(char *dest, char *src);
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+
+  Monitor(int mode, int cpu);
+  Monitor(int mode, int cpu, LoopCheck *inLcPtr);
+  Monitor(int mode, int cpu, LoopCheck *inLcPtr, IntrfTw *inTwiPtr);
+
+  // --------------------------------------------------------------------------
+  // Konfiguration und Hilfsfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void  setInfo(char *txt);
+  int   putBuf(char c);
+  int   putBuf(char *txt);
+  char  getBuf();
+  void  clrBuf();
+  void  sendConfig();
+
+
+  // --------------------------------------------------------------------------
+  // Anwenderschnittstelle
+  // --------------------------------------------------------------------------
+  //
+
+  // Funktionen
+  //
+  void run();
+  void cprint(char c);
+  void print(char *txt);
+  void print(unsigned int iVal);
+  void prints(int iVal);
+  void print(byte *iVal, int nr, char fill);
+  void printcr();
+  void cprintcr(char c);
+  void printcr(char *txt);
+  void printcr(unsigned int iVal);
+  void printcr(byte *iVal, int nr, char fill);
+  void println();
+  void cprintln(char c);
+  void println(char *txt);
+  void println(unsigned int iVal);
+  void println(byte *iVal, int nr, char fill);
+
+  void config(int inNrOfChn);
+  void config(int inChn, char inType, word inMax, word inMin, char *inName);
+
+
+  // Zustände (Variablen)
+  //
+  bool  busy;
+  char  lastKeyIn;
+
+  // Steuerbits (Kommandobits)
+  //
+  bool  cFlag[10];
+  };
+
+// ----------------------------------------------------------------------------
+#endif // Monitor_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/Monitor/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/Monitor/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..a9b281138760d16aa71d51ecec1518e22188a30f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/Monitor/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "Monitor",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5a57198a5bb3b3c340ffa5a725f7f7c009725d9a
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.cpp
@@ -0,0 +1,875 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   SensorLSM9DS1.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#include "SensorLSM9DS1.h"
+#include <string.h>
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+
+SensorLSM9DS1::SensorLSM9DS1(IntrfTw *refI2C, int inRunCycle)
+{
+  TwiParams twiParams;
+
+  twPtr               = refI2C;
+  runState            = rsInit;
+  twiByteSeq.len      = 12;
+  twiByteSeq.valueRef = byteArray;
+  runCycle            = inRunCycle;
+
+  fullScaleA  = 4;
+  fullScaleG  = 2000;
+  fullScaleM  = 4;
+
+  newValueAG  = false;
+  newValueM   = false;
+
+  avgSetAG    = 0;
+  avgCntAG    = 0;
+  avgSetM     = 0;
+  avgCntM     = 0;
+
+  errorCntAdrNakAG    = 0;
+  errorCntDataNakAG   = 0;
+  errorCntOverAG      = 0;
+
+  errorCntAdrNakM     = 0;
+  errorCntDataNakM    = 0;
+  errorCntOverM       = 0;
+
+  timeOutTwiStatus    = 0;
+  timeOutTwiDataAG    = 0;
+  timeOutTwiDataM     = 0;
+
+  timeOutStatusAG     = 0;
+  toValueStatusAG     = 0;
+  timeOutStatusM      = 0;
+  toValueStatusM      = 0;
+
+  toCntTwiStatusAG  = 0;
+  toCntTwiStatusM   = 0;
+  toCntTwiDataAG    = 0;
+  toCntTwiDataM     = 0;
+  toCntStatusAG     = 0;
+  toCntStatusM      = 0;
+
+  sumA.x = sumA.y = sumA.z = sumG.x = sumG.y = sumG.z = 0;
+  waitCnt = 2;
+
+  refI2C->getParams(&twiParams);
+  switch(twiParams.speed)
+  {
+    case Twi100k:
+      twiCycle = 10;
+      break;
+
+    case Twi250k:
+      twiCycle = 4;
+      break;
+
+    case Twi400k:
+      twiCycle = 2;
+      break;
+  }
+
+  twiStatusCycle  = 40 * twiCycle;
+  twiDataCycleAG  = 160 * twiCycle;
+  twiDataCycleM   = 100 * twiCycle;
+
+  enableMeasAG  = false;
+  enableMeasM   = false;
+
+  runStateCntTotal = 0;
+}
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+//
+int SensorLSM9DS1::resetAG()
+{
+  twPtr->writeByteReg(AG_Adr, AG_Ctrl8, 0x05);
+
+  // Get ID
+  return(twPtr->readByteReg(AG_Adr, AG_Id));
+}
+
+int SensorLSM9DS1::resetM()
+{
+  twPtr->writeByteReg(M_Adr, M_Ctrl2, 0x0C);
+
+  // Get ID
+  return(twPtr->readByteReg(M_Adr, M_Id));
+}
+
+int SensorLSM9DS1::reset()
+{
+  int retv;
+
+  twPtr->writeByteReg(AG_Adr, AG_Ctrl8, 0x05);
+  twPtr->writeByteReg(M_Adr, M_Ctrl2, 0x0C);
+
+  retv = twPtr->readByteReg(AG_Adr, AG_Id);
+  retv += twPtr->readByteReg(M_Adr, M_Id);
+  return(retv);
+}
+
+void SensorLSM9DS1::setScanAG(byte scValueAG, byte scValueA, byte scValueG)
+{
+  twPtr->writeByteReg(AG_Adr, AG_Ctrl6, scValueAG | scValueA);
+  twPtr->writeByteReg(AG_Adr, AG_Ctrl1, scValueAG | scValueG);
+}
+
+void SensorLSM9DS1::setScanM(byte scValue1, byte scValue2, byte scValue3, byte scValue4)
+{
+  twPtr->writeByteReg(M_Adr, M_Ctrl1, scValue1);
+  twPtr->writeByteReg(M_Adr, M_Ctrl2, scValue2);
+  twPtr->writeByteReg(M_Adr, M_Ctrl3, scValue3);
+  twPtr->writeByteReg(M_Adr, M_Ctrl4, scValue4);
+}
+
+void SensorLSM9DS1::setTimeOutValues(FreqAG fAG, FreqM fM)
+{
+  int freqA = 1190, freqM = 40000;
+  int cycleA, cycleM;
+
+  enableMeasAG = true;
+
+  switch(fAG)
+  {
+    case FreqAG14_9:
+      freqA = 149;
+      break;
+
+    case FreqAG59_5:
+      freqA = 595;
+      break;
+
+    case FreqAG119:
+      freqA = 1190;
+      break;
+
+    case FreqAG238:
+      freqA = 2380;
+      break;
+
+    case FreqAG476:
+      freqA = 4760;
+      break;
+
+    case FreqAG952:
+      freqA = 9520;
+      break;
+
+    case FreqAG_OFF:
+      freqA = 1190;
+      enableMeasAG = false;
+      break;
+  }
+
+  cycleA = (freqA * runCycle) / 10;     // Zyklusfrequenz
+  toValueStatusAG = 1200000 / cycleA;   // Mikrosekunden + 20% Verlängerung
+
+  // Test
+  //toValueStatusAG += 2;
+
+  enableMeasM = true;
+
+  switch(fM)
+  {
+    case FreqM0_625:
+      freqM = 625;
+      break;
+
+    case FreqM1_25:
+      freqM = 1250;
+      break;
+
+    case FreqM2_5:
+      freqM = 2500;
+      break;
+
+    case FreqM5:
+      freqM = 5000;
+      break;
+
+    case FreqM10:
+      freqM = 10000;
+      break;
+
+    case FreqM20:
+      freqM = 20000;
+      break;
+
+    case FreqM40:
+      freqM = 40000;
+      break;
+
+    case FreqM80:
+      freqM = 80000;
+      break;
+
+    case FreqM_OFF:
+      freqM = 40000;
+      enableMeasM = false;
+      break;
+  }
+
+  cycleM = (freqM * runCycle) / 1000;   // Zyklusfrequenz
+  toValueStatusM = 1200000 / cycleM;    // Mikrosekunden + 20% Verlängerung
+
+  // Test
+  //toValueStatusM += 3;
+
+}
+
+void SensorLSM9DS1::begin(FreqAG freqAG, int avgAG, MaxA maxA, MaxG maxG, FreqM freqM, int avgM, MaxM maxM)
+{
+  setScanAG((byte) freqAG, (byte) maxA | A_LpAuto, (byte) maxG | G_LpHH);
+  setScanM((byte) freqM | Mxy_PmMed | M_TmpOn, (byte) maxM, M_Contin, Mz_PmMed);
+
+  setTimeOutValues(freqAG, freqM);
+
+  if(avgAG == 1)
+  {
+    avgSetAG = 0;
+    avgCntAG = 0;
+  }
+  else
+  {
+    avgSetAG = avgAG;
+    avgCntAG = avgAG;
+  }
+
+  if(avgM == 1)
+  {
+    avgSetM = 0;
+    avgCntM = 0;
+  }
+  else
+  {
+    avgSetM = avgM;
+    avgCntM = avgM;
+  }
+
+  delay(10);
+}
+
+void SensorLSM9DS1::begin()
+{
+  //reset();
+
+  delay(10);
+
+  setScanAG(AG_Odr119, A_Fs4g | A_LpAuto, G_Fs2000 | G_LpHH);
+  setScanM(M_Odr40 | Mxy_PmMed | M_TmpOn, M_Fs4G, M_Contin, Mz_PmMed);
+
+  avgSetAG  = 6;
+  avgCntAG  = 6;
+
+  avgSetM   = 0;
+  avgCntM   = 0;
+
+
+  delay(10);
+}
+
+// ----------------------------------------------------------------------------
+// Steuerfunktionen, gezielte Prozessorzugriffe und Hilfsfunktionen
+// ----------------------------------------------------------------------------
+//
+/*
+void SensorLSM9DS1::run0()
+{
+  switch(runState)
+  {
+    case rsInit:
+      runState = rsScanAGReq;
+      break;
+
+      // ------------ Accel & Gyro ------------
+
+    case rsScanAGReq:
+      twPtr->recByteReg(AG_Adr, AG_Status, &twiByte);
+      runState = rsScanAGChk;
+      break;
+
+    case rsScanAGChk:
+      if(twiByte.twiStatus != TwStFin)
+        break;
+
+      if((twiByte.value & 0x03) == 0)
+      {
+        waitCnt = 2;
+        runState = rsWaitAG;
+        break;
+      }
+
+      twiByteSeq.len = 12;
+      twPtr->recByteRegSeq(AG_Adr, G_Out, &twiByteSeq);
+      runState = rsFetchAG;
+      break;
+
+    case rsWaitAG:
+      if(waitCnt > 0)
+      {
+        waitCnt--;
+        break;
+      }
+      else
+      {
+        runState = rsScanAGReq;
+      }
+      break;
+
+    case rsFetchAG:
+      if(twiByte.twiStatus != TwStFin)
+        break;
+
+      for(int i = 0; i < 12; i++)
+        tmpDataAG.byteArray[i] = byteArray[i];
+
+      if(avgSetAG > 0)
+      {
+        sumA.x += (int) tmpDataAG.valueAG.A.x;
+        sumA.y += (int) tmpDataAG.valueAG.A.y;
+        sumA.z += (int) tmpDataAG.valueAG.A.z;
+        sumG.x += (int) tmpDataAG.valueAG.G.x;
+        sumG.y += (int) tmpDataAG.valueAG.G.y;
+        sumG.z += (int) tmpDataAG.valueAG.G.z;
+        avgCntAG--;
+
+        if(avgCntAG == 0)
+        {
+          rawDataAG.valueAG.A.x = short (sumA.x / avgSetAG);
+          rawDataAG.valueAG.A.y = short (sumA.y / avgSetAG);
+          rawDataAG.valueAG.A.z = short (sumA.z / avgSetAG);
+          rawDataAG.valueAG.G.x = short (sumG.x / avgSetAG);
+          rawDataAG.valueAG.G.y = short (sumG.y / avgSetAG);
+          rawDataAG.valueAG.G.z = short (sumG.z / avgSetAG);
+
+          sumA.x = sumA.y = sumA.z = sumG.x = sumG.y = sumG.z = 0;
+          avgCntAG = avgSetAG;
+
+          newValueAG = true;
+        }
+      }
+      else
+      {
+        rawDataAG.valueAG.A.x = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.A.y = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.A.z = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.G.x = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.G.y = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.G.z = tmpDataAG.valueAG.A.x;
+        newValueAG = true;
+      }
+
+      runState = rsScanAGReq;
+      break;
+  }
+}
+
+void SensorLSM9DS1::run1()
+{
+  switch(runState)
+  {
+    case rsInit:
+      runState = rsScanAGReq;
+      break;
+
+      // ------------ Accel & Gyro ------------
+
+    case rsScanAGReq:
+      twPtr->recByteReg(AG_Adr, AG_Status, &twiByte);
+      runState = rsScanAGChk;
+      break;
+
+    case rsScanAGChk:
+      if(twiByte.twiStatus != TwStFin)
+        break;
+
+      if((twiByte.value & 0x03) == 0)
+      {
+        waitCnt = 2;
+        runState = rsWaitAG;
+        break;
+      }
+
+      twiByteSeq.len = 12;
+      twPtr->recByteRegSeq(AG_Adr, G_Out, &twiByteSeq);
+      runState = rsFetchAG;
+      break;
+
+    case rsWaitAG:
+      if(waitCnt > 0)
+      {
+        waitCnt--;
+        break;
+      }
+      else
+      {
+        runState = rsScanAGReq;
+      }
+      break;
+
+    case rsFetchAG:
+      if(twiByteSeq.twiStatus != TwStFin)
+        break;
+
+      for(int i = 0; i < 12; i++)
+        rawDataAG.byteArray[i] = byteArray[i];
+
+      newValueAG = true;
+
+      runState = rsScanAGReq;
+      break;
+  }
+}
+
+*/
+
+void SensorLSM9DS1::stop()
+{
+  enableMeasAG = false;
+  enableMeasM = false;
+}
+
+void SensorLSM9DS1::resume()
+{
+  enableMeasAG = true;
+  enableMeasM = true;
+}
+
+void SensorLSM9DS1::run()
+{
+  runStateCntTotal++;
+
+  switch(runState)
+  {
+    // ------------------------------------------------------------------------
+    case rsInit:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsInit]++;
+      runState = rsScanAGReq;
+      timeOutStatusAG = toValueStatusAG;
+      timeOutStatusM  = toValueStatusM;
+      break;
+
+      // ------------ Accel & Gyro ------------
+
+    // ------------------------------------------------------------------------
+    case rsScanAGReq:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsScanAGReq]++;
+      if(!enableMeasAG)
+      {
+        runState = rsScanMReq;
+        break;
+      }
+
+      twPtr->recByteReg(AG_Adr, AG_Status, &twiByte);
+      timeOutTwiStatus = twiStatusCycle / runCycle + 1;
+      runState = rsScanAGChk;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsWaitAG:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsWaitAG]++;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsScanAGChk:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsScanAGChk]++;
+      if((twiByte.twiStatus != TwStFin) && ((twiByte.twiStatus & TwStError) == 0))
+      {
+        if(timeOutTwiStatus > 0)
+          timeOutTwiStatus--;
+        else
+        {
+          toCntTwiStatusAG++;
+          runState = rsScanAGReq;
+        }
+        break;
+      }
+
+      if((twiByte.twiStatus & TwStError) != 0)
+      {
+        if(twiByte.twiStatus == TwStAdrNak)
+          errorCntAdrNakAG++;
+        else if(twiByte.twiStatus == TwStDataNak)
+          errorCntDataNakAG++;
+        else
+          errorCntOverAG++;
+
+        runState = rsScanAGReq;
+        break;
+      }
+
+      if((twiByte.value & 0x03) == 0)
+      {
+        if(timeOutStatusAG > 0)
+          timeOutStatusAG--;
+        else
+        {
+          timeOutStatusAG = toValueStatusAG;
+          toCntStatusAG++;
+        }
+        runState = rsScanMReq;    // -> Magnet
+        break;
+      }
+
+      timeOutStatusAG = toValueStatusAG;
+      twiByteSeq.len = 12;
+      twPtr->recByteRegSeq(AG_Adr, G_Out, &twiByteSeq);
+      timeOutTwiDataAG = twiDataCycleAG / runCycle + 1;
+      runState = rsFetchAG;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsFetchAG:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsFetchAG]++;
+      if((twiByteSeq.twiStatus != TwStFin) && ((twiByte.twiStatus & TwStError) == 0))
+      {
+        if(timeOutTwiDataAG > 0)
+        {
+          timeOutTwiDataAG--;
+          break;
+        }
+      }
+
+      if(((twiByteSeq.twiStatus & TwStError) != 0) || (timeOutTwiDataAG == 0))
+      {
+        if(twiByteSeq.twiStatus == TwStAdrNak)
+          errorCntAdrNakAG++;
+        else if(twiByteSeq.twiStatus == TwStDataNak)
+          errorCntDataNakAG++;
+        else if(twiByteSeq.twiStatus == TwStOverrun)
+          errorCntOverAG++;
+        else
+          toCntTwiDataAG++;
+
+        twiByteSeq.len = 12;
+        twPtr->recByteRegSeq(AG_Adr, G_Out, &twiByteSeq);
+        timeOutTwiDataAG = twiDataCycleAG / runCycle + 1;
+        break;
+      }
+
+      for(int i = 0; i < 12; i++)
+        comDataAG.byteArray[i] = byteArray[i];
+
+      if(avgSetAG > 0)
+      {
+        sumA.x += comDataAG.valueAG.A.x;
+        sumA.y += comDataAG.valueAG.A.y;
+        sumA.z += comDataAG.valueAG.A.z;
+        sumG.x += comDataAG.valueAG.G.x;
+        sumG.y += comDataAG.valueAG.G.y;
+        sumG.z += comDataAG.valueAG.G.z;
+        avgCntAG--;
+
+        if(avgCntAG == 0)
+        {
+          rawDataAG.valueAG.A.x = sumA.x / avgSetAG;
+          rawDataAG.valueAG.A.y = sumA.y / avgSetAG;
+          rawDataAG.valueAG.A.z = sumA.z / avgSetAG;
+          rawDataAG.valueAG.G.x = sumG.x / avgSetAG;
+          rawDataAG.valueAG.G.y = sumG.y / avgSetAG;
+          rawDataAG.valueAG.G.z = sumG.z / avgSetAG;
+          sumA.x = sumA.y = sumA.z = sumG.x = sumG.y = sumG.z = 0;
+          avgCntAG = avgSetAG;
+          newValueAG = true;
+        }
+      }
+      else
+      {
+        rawDataAG.valueAG.A.x = comDataAG.valueAG.A.x;
+        rawDataAG.valueAG.A.y = comDataAG.valueAG.A.y;
+        rawDataAG.valueAG.A.z = comDataAG.valueAG.A.z;
+        rawDataAG.valueAG.G.x = comDataAG.valueAG.G.x;
+        rawDataAG.valueAG.G.y = comDataAG.valueAG.G.y;
+        rawDataAG.valueAG.G.z = comDataAG.valueAG.G.z;
+        newValueAG = true;
+      }
+
+      runState = rsScanAGReq;
+      break;
+
+      // ------------ Magnet ------------
+
+    // ------------------------------------------------------------------------
+    case rsScanMReq:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsScanMReq]++;
+      if(!enableMeasM)
+      {
+        runState = rsScanAGReq;
+        break;
+      }
+
+      twPtr->recByteReg(M_Adr, M_Status, &twiByte);
+      timeOutTwiStatus = twiStatusCycle / runCycle + 1;
+      runState = rsScanMChk;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsScanMChk:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsScanMChk]++;
+      if((twiByte.twiStatus != TwStFin) && ((twiByte.twiStatus & TwStError) == 0))
+      {
+        if(timeOutTwiStatus > 0)
+          timeOutTwiStatus--;
+        else
+        {
+          toCntTwiStatusM++;
+          runState = rsScanMReq;
+        }
+        break;
+      }
+
+      if((twiByte.twiStatus & TwStError) != 0)
+      {
+        if(twiByte.twiStatus == TwStAdrNak)
+          errorCntAdrNakM++;
+        else if(twiByte.twiStatus == TwStDataNak)
+          errorCntDataNakM++;
+        else
+          errorCntOverM++;
+
+        runState = rsScanAGReq;
+        break;
+      }
+
+      if((twiByte.value & 0x08) == 0)
+      {
+        if(timeOutStatusM > 0)
+          timeOutStatusM--;
+        else
+        {
+          timeOutStatusM = toValueStatusM;
+          toCntStatusM++;
+        }
+        runState = rsScanAGReq;    // -> Accel,Gyro
+        break;
+      }
+
+      timeOutStatusM = toValueStatusM;
+      twiByteSeq.len = 6;
+      twPtr->recByteRegSeq(M_Adr, M_Out, &twiByteSeq);
+      timeOutTwiDataM = twiDataCycleM / runCycle + 1;
+      runState = rsFetchM;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsFetchM:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsFetchM]++;
+      if((twiByteSeq.twiStatus != TwStFin) && ((twiByte.twiStatus & TwStError) == 0))
+      {
+        if(timeOutTwiDataM > 0)
+        {
+          timeOutTwiDataM--;
+          break;
+        }
+      }
+
+      if( ((twiByteSeq.twiStatus & TwStError) != 0) || (timeOutTwiDataM == 0) )
+      {
+        if(twiByteSeq.twiStatus == TwStAdrNak)
+          errorCntAdrNakM++;
+        else if(twiByteSeq.twiStatus == TwStDataNak)
+          errorCntDataNakM++;
+        else if(twiByteSeq.twiStatus == TwStOverrun)
+          errorCntOverM++;
+        else
+          toCntTwiDataM++;
+
+        twiByteSeq.len = 6;
+        twPtr->recByteRegSeq(AG_Adr, M_Out, &twiByteSeq);
+        timeOutTwiDataM = twiDataCycleM / runCycle + 1;
+        break;
+      }
+
+      for(int i = 0; i < 6; i++)
+        rawDataM.byteArray[i] = byteArray[i];
+
+      if(avgSetM > 0)
+      {
+        sumM.x += rawDataM.valueM.x;
+        sumM.y += rawDataM.valueM.y;
+        sumM.z += rawDataM.valueM.z;
+        avgCntM--;
+
+        if(avgCntM == 0)
+        {
+          rawDataM.valueM.x = sumM.x / avgSetM;
+          rawDataM.valueM.y = sumM.y / avgSetM;
+          rawDataM.valueM.z = sumM.z / avgSetM;
+          sumM.x = sumM.y = sumM.z = 0;
+          avgCntM = avgSetM;
+          newValueM = true;
+        }
+      }
+      else
+      {
+        newValueM = true;
+      }
+
+      runState = rsScanAGReq;
+      break;
+  }
+}
+
+void  SensorLSM9DS1::syncValuesM()
+{
+  newValueM = false;
+}
+
+bool  SensorLSM9DS1::getValuesM(RawDataMPtr rdptr)
+{
+  if(!newValueM) return(false);
+  for(int i = 0; i < 6; i++)
+    rdptr->byteArray[i] = rawDataM.byteArray[i];
+  newValueM = false;
+  return(true);
+}
+
+bool  SensorLSM9DS1::getValuesM(CalValuePtr calPtr)
+{
+  if(!newValueM) return(false);
+
+  calPtr->x = (float) fullScaleM * (float) rawDataM.valueM.x / (float) 32767;
+  calPtr->y = (float) fullScaleM * (float) rawDataM.valueM.y / (float) 32767;
+  calPtr->z = (float) fullScaleM * (float) rawDataM.valueM.z / (float) 32767;
+
+  newValueM = false;
+  return(true);
+}
+
+void  SensorLSM9DS1::syncValuesAG()
+{
+  newValueAG = false;
+}
+
+bool  SensorLSM9DS1::getValuesAG(RawDataAGPtr rdptr)
+{
+  if(!newValueAG) return(false);
+  for(int i = 0; i < 12; i++)
+    rdptr->byteArray[i] = rawDataAG.byteArray[i];
+  newValueAG = false;
+  return(true);
+}
+
+bool  SensorLSM9DS1::getValuesAG(CalValueAGPtr calPtr)
+{
+  if(!newValueAG) return(false);
+
+  calPtr->G.x = (float) fullScaleG * (float) rawDataAG.valueAG.G.x / (float) 32767;
+  calPtr->G.y = (float) fullScaleG * (float) rawDataAG.valueAG.G.y / (float) 32767;
+  calPtr->G.z = (float) fullScaleG * (float) rawDataAG.valueAG.G.z / (float) 32767;
+
+  calPtr->A.x = (float) fullScaleA * (float) rawDataAG.valueAG.A.x / (float) 32767;
+  calPtr->A.y = (float) fullScaleA * (float) rawDataAG.valueAG.A.y / (float) 32767;
+  calPtr->A.z = (float) fullScaleA * (float) rawDataAG.valueAG.A.z / (float) 32767;
+
+  newValueAG = false;
+  return(true);
+}
+
+bool  SensorLSM9DS1::getAvgValuesAG(CalValueAGPtr calPtr)
+{
+  if(!newValueAG) return(false);
+  newValueAG = false;
+
+  if(avgSetAG > 0)
+  {
+    sumA.x += rawDataAG.valueAG.A.x;
+    sumA.y += rawDataAG.valueAG.A.y;
+    sumA.z += rawDataAG.valueAG.A.z;
+    sumG.x += rawDataAG.valueAG.G.x;
+    sumG.y += rawDataAG.valueAG.G.y;
+    sumG.z += rawDataAG.valueAG.G.z;
+    avgCntAG--;
+
+    if(avgCntAG > 0) return(false);
+
+    calPtr->G.x = (float) fullScaleG * (float) (sumG.x / avgSetAG) / (float) 32767;
+    calPtr->G.y = (float) fullScaleG * (float) (sumG.y / avgSetAG) / (float) 32767;
+    calPtr->G.z = (float) fullScaleG * (float) (sumG.z / avgSetAG) / (float) 32767;
+
+    calPtr->A.x = (float) fullScaleA * (float) (sumA.x / avgSetAG) / (float) 32767;
+    calPtr->A.y = (float) fullScaleA * (float) (sumA.y / avgSetAG) / (float) 32767;
+    calPtr->A.z = (float) fullScaleA * (float) (sumA.z / avgSetAG) / (float) 32767;
+
+    avgCntAG = avgSetAG;
+    return(true);
+  }
+
+  calPtr->G.x = (float) fullScaleG * (float) rawDataAG.valueAG.G.x / (float) 32767;
+  calPtr->G.y = (float) fullScaleG * (float) rawDataAG.valueAG.G.y / (float) 32767;
+  calPtr->G.z = (float) fullScaleG * (float) rawDataAG.valueAG.G.z / (float) 32767;
+
+  calPtr->A.x = (float) fullScaleA * (float) rawDataAG.valueAG.A.x / (float) 32767;
+  calPtr->A.y = (float) fullScaleA * (float) rawDataAG.valueAG.A.y / (float) 32767;
+  calPtr->A.z = (float) fullScaleA * (float) rawDataAG.valueAG.A.z / (float) 32767;
+
+  return(true);
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// Ereignisbearbeitung und Interrupts
+// ----------------------------------------------------------------------------
+//
+
+// ----------------------------------------------------------------------------
+//                      D e b u g - H i l f e n
+// ----------------------------------------------------------------------------
+//
+dword SensorLSM9DS1::debGetDword(int code)
+{
+  dword retv;
+
+
+  switch(code)
+  {
+    case 1:
+      retv = toValueStatusAG;
+      break;
+
+    case 2:
+      retv = toValueStatusM;
+      break;
+
+    default:
+      retv = 0;
+      break;
+  }
+  return(retv);
+}
+
+
+dword SensorLSM9DS1::debGetRunState(int code)
+{
+  if(0 <= code < 9)
+    return(runStateCntArray[code]);
+  else
+    return(0);
+}
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.h
new file mode 100644
index 0000000000000000000000000000000000000000..63cb831c96688b30a85397927a14a52dcb6a15f2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.h
@@ -0,0 +1,363 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   SensorLSM9DS1.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef SENSORLSM9DS1_H
+#define SENSORLSM9DS1_H
+
+#include "Arduino.h"
+#include "arduinoDefs.h"
+#include "IntrfTw.h"
+
+// ----------------------------------------------------------------------------
+
+// ------------------------ Acceleration and Gyroscope -------
+#define AG_Adr    0x6B
+// ------------------------ Acceleration and Gyroscope -------
+#define AG_Id     0x0F
+#define AG_Ctrl1  0x10
+#define G_Out     0x18
+#define AG_Ctrl6  0x20
+#define AG_Ctrl8  0x22
+#define AG_Status 0x27
+
+#define AG_Rate(x)      (x << 5)
+#define AG_Odr14_9      0x20
+#define AG_Odr59_5      0x40
+#define AG_Odr119       0x60
+#define AG_Odr238       0x80
+#define AG_Odr476       0xA0
+#define AG_Odr952       0xC0
+
+typedef enum _FreqAG
+{
+  FreqAG_OFF  = 0xFF,
+  FreqAG14_9  = AG_Odr14_9,
+  FreqAG59_5  = AG_Odr59_5,
+  FreqAG119   = AG_Odr119,
+  FreqAG238   = AG_Odr238,
+  FreqAG476   = AG_Odr476,
+  FreqAG952   = AG_Odr952
+} FreqAG;
+
+#define AG_FullScale(x) (x << 3)
+#define A_Fs2g          0x00
+#define A_Fs4g          0x10
+#define A_Fs8g          0x18
+#define A_Fs16g         0x08
+#define G_Fs245         0x00
+#define G_Fs2000        0x18
+#define G_Fs500         0x08
+
+typedef enum _MaxA
+{
+  MaxAcc2g    = A_Fs2g,
+  MaxAcc4g    = A_Fs4g,
+  MaxAcc8g    = A_Fs8g,
+  MaxAcc16g   = A_Fs16g
+} MaxA;
+
+typedef enum _MaxG
+{
+  MaxGyro245dps   = G_Fs245,
+  MaxGyro500dps   = G_Fs500,
+  MaxGyro2000dps  = G_Fs2000
+} MaxG;
+
+#define AG_LowPass(x)   (x)
+#define A_LpAuto        0x00
+#define A_Lp50          0x07
+#define A_Lp105         0x06
+#define A_Lp211         0x05
+#define A_Lp408         0x04
+#define G_LpLL          0x00
+#define G_LpLH          0x01
+#define G_LpHL          0x02
+#define G_LpHH          0x03
+
+// ------------------------ Magnetic Field -------
+#define M_Adr     0x1E
+// ------------------------ Magnetic Field -------
+#define M_Id      0x0F
+#define M_Ctrl1   0x20
+#define M_Ctrl2   0x21
+#define M_Ctrl3   0x22
+#define M_Ctrl4   0x23
+#define M_Ctrl5   0x24
+#define M_Status  0x27
+#define M_Out     0x28
+
+// Control 1
+#define M_Rate(x)       (x << 2)
+#define M_Odr0_625      0x00
+#define M_Odr1_25       0x04
+#define M_Odr2_5        0x08
+#define M_Odr5          0x0C
+#define M_Odr10         0x10
+#define M_Odr20         0x14
+#define M_Odr40         0x18
+#define M_Odr80         0x1C
+
+typedef enum _FreqM
+{
+  FreqM_OFF   = 0xFF,
+  FreqM0_625  = M_Odr0_625,
+  FreqM1_25   = M_Odr1_25,
+  FreqM2_5    = M_Odr2_5,
+  FreqM5      = M_Odr5,
+  FreqM10     = M_Odr10,
+  FreqM20     = M_Odr20,
+  FreqM40     = M_Odr40,
+  FreqM80     = M_Odr80
+} FreqM;
+
+#define M_Temp(x)       (x << 7)
+#define M_TmpOn         0x80
+#define M_TmpOff        0x00
+
+#define Mxy_Power(x)    (x << 6)
+#define Mxy_PmLow       0x00
+#define Mxy_PmMed       0x20
+#define Mxy_PmHigh      0x40
+#define Mxy_PmUhigh     0x60
+
+// Control 2
+#define M_FullScale(x)  (x << 5)
+#define M_Fs4G          0x00
+#define M_Fs8G          0x20
+#define M_Fs12G         0x40
+#define M_Fs16G         0x60
+
+typedef enum _MaxM
+{
+  MaxMag4G      = M_Fs4G,
+  MaxMag8G      = M_Fs8G,
+  MaxMag12G     = M_Fs12G,
+  MaxMag16G     = M_Fs16G
+} MaxM;
+
+
+// Control 3
+#define M_OpMode(x)     (x)
+#define M_Contin        0x00
+#define M_Single        0x01
+#define M_Down          0x10
+
+// Control 4
+#define Mz_Power(x)    (x << 2)
+#define Mz_PmLow       0x00
+#define Mz_PmMed       0x04
+#define Mz_PmHigh      0x08
+#define Mz_PmUhigh     0x0C
+
+
+typedef enum _RunState
+{
+  rsInit,
+  rsScanAGReq,
+  rsWaitAG,
+  rsScanAGChk,
+  rsFetchAG,
+  rsScanMReq,
+  rsScanMChk,
+  rsFetchM
+} RunState;
+
+#define NrOfRunStates 8
+
+typedef struct _RawValue
+{
+  short int   x;
+  short int   y;
+  short int   z;
+} RawValue;
+
+typedef struct _SumValue
+{
+  int   x;
+  int   y;
+  int   z;
+} SumValue, *SumValuePtr;
+
+typedef struct _RawValueAG
+{
+  RawValue  G;
+  RawValue  A;
+} RawValueAG;
+
+typedef union _RawDataAG
+{
+  byte        byteArray[12];
+  RawValueAG  valueAG;
+} RawDataAG, *RawDataAGPtr;
+
+typedef union _RawDataM
+{
+  byte        byteArray[6];
+  RawValue    valueM;
+} RawDataM, *RawDataMPtr;
+
+typedef struct _CalValue
+{
+  float   x;
+  float   y;
+  float   z;
+} CalValue, *CalValuePtr;
+
+typedef struct _CalValueAG
+{
+  CalValue  G;
+  CalValue  A;
+} CalValueAG, *CalValueAGPtr;
+
+typedef struct _SensorErrors
+{
+
+} SensorErrors, *SensorErrorsPtr;
+
+class SensorLSM9DS1
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten und Funktionen
+  // --------------------------------------------------------------------------
+  //
+  IntrfTw     *twPtr;
+  TwiByte     twiByte;
+  TwiByteSeq  twiByteSeq;
+  byte        byteArray[12];
+
+  bool        enableMeasAG;
+  bool        newValueAG;
+  RawDataAG   rawDataAG;
+  RawDataAG   comDataAG;
+
+  bool        enableMeasM;
+  bool        newValueM;
+  RawDataM    rawDataM;
+
+  int         fullScaleA;
+  int         fullScaleG;
+  int         fullScaleM;
+
+  SumValue    sumA;
+  SumValue    sumG;
+  int         avgSetAG;
+  int         avgCntAG;
+
+  SumValue    sumM;
+  int         avgSetM;
+  int         avgCntM;
+
+  dword       timeOutTwiStatus;
+  dword       timeOutTwiDataAG;
+  dword       timeOutTwiDataM;
+
+  dword       timeOutStatusAG;
+  dword       toValueStatusAG;
+  dword       timeOutStatusM;
+  dword       toValueStatusM;
+
+  int         twiCycle;
+  int         twiStatusCycle;
+  int         twiDataCycleAG;
+  int         twiDataCycleM;
+
+  RunState    runState;
+  int         waitCnt;
+  int         runCycle;
+
+  void setTimeOutValues(FreqAG fAG, FreqM fM);
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen der Basis-Klasse
+  // --------------------------------------------------------------------------
+
+  SensorLSM9DS1(IntrfTw *refI2C, int inRunCycle);
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  int resetAG();
+  int resetM();
+  int reset();
+
+  void setScanAG(byte scValueAG, byte scValueA, byte scValueG);
+  // Messparameter für Accel und Gyro
+  // scValueAG = Abtastrate
+  // scValueA  = Vollausschlag und Tiefpass für Beschleunigung
+  // scValueB  = Vollausschlag und Tiefpass für Gyrometer
+
+  void setScanM(byte scValue1, byte scValue2, byte scValue3, byte scValue4);
+  // Messparameter für Magnetfeld
+  // scValue1 = Abtastrate, Temperaturkompensation und XY-Powermode
+  // scValue2 = Vollausschlag
+  // scValue3 = Betriebsart
+  // scValue4 = Z-Powermode
+
+
+  void begin(FreqAG freqAG, int avgAG, MaxA maxA, MaxG maxG, FreqM freqM, int avgM, MaxM maxM);
+  void begin();
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void run();
+  void run0();
+  void run1();
+  void stop();
+  void resume();
+
+  // --------------------------------------------------------------------------
+  // Datenaustausch
+  // --------------------------------------------------------------------------
+  //
+  dword       errorCntOverAG;
+  dword       errorCntAdrNakAG;
+  dword       errorCntDataNakAG;
+
+  dword       errorCntOverM;
+  dword       errorCntAdrNakM;
+  dword       errorCntDataNakM;
+
+  dword       toCntTwiStatusAG;
+  dword       toCntTwiStatusM;
+  dword       toCntTwiDataAG;
+  dword       toCntTwiDataM;
+  dword       toCntStatusAG;
+  dword       toCntStatusM;
+
+  void  syncValuesAG();
+  bool  getValuesAG(RawDataAGPtr rdptr);
+  bool  getValuesAG(CalValueAGPtr calPtr);
+  bool  getAvgValuesAG(CalValueAGPtr calPtr);
+  void  syncValuesM();
+  bool  getValuesM(RawDataMPtr rdptr);
+  bool  getValuesM(CalValuePtr calPtr);
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
+
+  // ----------------------------------------------------------------------------
+  //                      D e b u g - H i l f e n
+  // ----------------------------------------------------------------------------
+  //
+  dword runStateCntArray[NrOfRunStates];
+  dword runStateCntTotal;
+  dword debGetDword(int code);
+  dword debGetRunState(int code);
+
+};
+
+#endif // SENSORLSM9DS1_H
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SensorLSM9DS1/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SensorLSM9DS1/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..6432e5ccb8930ce40504aa4f03e463f2df00fac0
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SensorLSM9DS1/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "SensorLSM9DS1",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapComDue/SoaapComDue.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapComDue/SoaapComDue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b24e6f4f90c3ecc1588b5af5dde88b4b922e8ee7
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapComDue/SoaapComDue.cpp
@@ -0,0 +1,212 @@
+//-----------------------------------------------------------------------------
+// Thema:   Steuerung optischer und akustischer Ausgaben für Perfomer
+// Datei:   SoaapComDue.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   01.April 2022
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zum Zugriff auf den
+// SOAAP-Master über eine serielle Schnittstelle des Arduino DUE.
+//
+
+#include "SoaapComDue.h"
+
+#define next(x) nextState = &SoaapComDue::x
+
+// ----------------------------------------------------------------------------
+// Konstruktoren und Initialisierungen
+// ----------------------------------------------------------------------------
+//
+SoaapComDue::SoaapComDue(USARTClass *serial, SoaapMsg *soaMsg)
+{
+  pCom = serial;
+  pMsg = soaMsg;
+  nextState = &SoaapComDue::runInit;
+
+  nrBytesIn = 0;
+  serInIdx = 0;
+  serInChar = 0;
+  serInCount = 0;
+  slaveAdr = 0;
+  slaveArea = 0;
+  appId = (SoaapApId) 0;
+
+  measIdx = 0;
+  nrMeas = 0;
+  resMeas = 0;
+  slaveIdx = 0;
+  anyNewVal = false;
+}
+
+// --------------------------------------------------------------------------
+// lokale Methoden (Zustandsmaschine)
+// --------------------------------------------------------------------------
+//
+void SoaapComDue::runInit()
+{
+  next(runWaitMsg);
+}
+
+void SoaapComDue::runWaitMsg()
+{
+  nrBytesIn = pCom->available();
+  // Anzahl der über <serial> eingetroffenen Bytes (Zeichen)
+
+  if(nrBytesIn < 1) return;
+  // Beim nächsten Takt wieder in diesen Zustand, wenn kein Zeichen da
+
+  for(serInIdx = 0; serInIdx < nrBytesIn; serInIdx++)
+  {                               // Suchen nach Startzeichen
+    serInChar = pCom->read();
+    if(serInChar < 0x20) break;
+  }
+
+  if(serInIdx == nrBytesIn) return;
+  // Beim nächsten Takt wieder in diesen Zustand, wenn Startzeichen nicht dabei
+
+  slaveArea = serInChar & 0x1F;   // Bereich auskodieren
+
+  serInIdx = 0;     // Index neu setzen für Inhaltszuordnung
+  next(runHeader);
+  // Beim nächsten Takt zum Zustand <runHeader>
+
+}
+
+void SoaapComDue::runHeader()
+{
+    nrBytesIn = pCom->available();
+    // Anzahl der über Serial1 eingetroffenen Bytes (Zeichen)
+
+    if(nrBytesIn < 1) return;
+    // Beim nächsten Takt wieder in diesen Zustand, wenn kein Zeichen da
+
+    serInChar = pCom->read();
+    // einzelnes Zeichen lesen
+
+    if(serInIdx == 0)             // nach der Area folgt die Slaveadresse
+    {
+      slaveAdr = serInChar & 0x1F;               // 1 - 31
+      slaveIdx = slaveAdr;        // vorläufig lineare Adress/Index-Zuordnung
+      serInIdx++;
+      // Beim nächsten Takt wieder in diesen Zustand
+    }
+    else                     // und dann die Anwendungskennung
+    {
+      appId = (SoaapApId) serInChar;
+      measIdx = 0;                      // Index für Messwertunterscheidung
+      serInIdx = 0;                     // Index für Messwertaufbau
+      nrMeas = pMsg->measCnt(appId);   // Anzahl Messwerte im Telegramm
+      resMeas = pMsg->measRes(appId);  // Auflösung der Messwerte in Zeichen
+      next(runValues);
+      // Beim nächsten Takt zum Zustand <runValues>
+    }
+}
+
+void SoaapComDue::runValues()
+{
+  int i;
+
+  do
+  {
+    nrBytesIn = pCom->available();
+    // Anzahl der über Serial1 eingetroffenen Bytes (Zeichen)
+
+    if(nrBytesIn < 1) return;
+    // Beim nächsten Takt wieder in diesen Zustand, wenn kein Zeichen da
+
+    for(i = 0; i < nrBytesIn; i++)
+    {
+      tmpBuffer[serInIdx++] = pCom->read();
+      // einzelnes Zeichen lesen
+
+      if(serInIdx == resMeas) break;
+      // Alle Zeichen vom Messwert da, also raus
+    }
+
+    if(serInIdx < resMeas) return;
+    // Wenn noch nicht ale Zeichen vom Messwert erfasst, dann von vorn
+
+    slValList[slaveIdx].measList[measIdx++] = pMsg->asc2meas(tmpBuffer);
+    // Zeichenkette in Messwert wandeln und speichern
+
+    if(measIdx == nrMeas) break;
+    // Falls mehr als ein Telegramm eingetroffen ist
+    // muss hier ein Ausstieg erfolgen
+
+    serInIdx = 0;   // Nächste Zeichenfolge
+  }
+  while (pCom->available() > 0);
+  // Die Taktzeit der Zustandsmaschine ist größer, als die
+  // Übertragungszeit von einem Zeichen.
+  // Deshalb werden in einem Zustandstakt alle inzwischen eingetroffenen
+  // Zeichen bearbeitet.
+
+  if(measIdx < nrMeas) return;
+  // Im Zustand bleiben, bis alle Messwerte gewandelt sind
+
+  slValList[slaveIdx].newVal = true;
+  anyNewVal = true;
+
+  next(runWaitMsg);
+}
+
+// --------------------------------------------------------------------------
+// lokale Methoden (Hilfsfunktionen)
+// --------------------------------------------------------------------------
+//
+
+// Erster Slave (kleinste Adresse) mit Daten
+//
+int   SoaapComDue::getSlDataAvail()
+{
+  for(int i = 1; i <= ScdNrOfSlaves; i++)
+    if(slValList[i].newVal)
+      return(i);
+  return(0);
+}
+
+// ----------------------------------------------------------------------------
+// Anwenderschnittstelle (Funktionen/Methoden)
+// ----------------------------------------------------------------------------
+//
+
+// (zyklischer) Aufruf zum Ablauf
+//
+void SoaapComDue::run()
+{
+  if(nextState != NULL)
+    (this->*nextState)();
+}
+
+// Daten von irgendeinem Slave verfügbar
+//
+int   SoaapComDue::anyDataAvail()
+{
+  if(!anyNewVal) return(0);
+  else return(getSlDataAvail());
+}
+
+// Daten von bestimmtem Slave verfügbar
+//
+bool  SoaapComDue::slDataAvail(int slAdr)
+{
+  return(slValList[getSlIdxAdr(slAdr)].newVal);
+}
+
+// Daten von einem bestimmten Slave abholen
+//
+int   SoaapComDue::getData(int slAdr, pMeasValues pMeas)
+{
+  int slIdx = getSlIdxAdr(slAdr);
+  for(int i = 0; i < 8; i++)
+    pMeas->defShort[i] = slValList[slIdx].measList[i];
+  slValList[slIdx].newVal = false;
+  anyNewVal = false;
+  for(int i = 1; i <= ScdNrOfSlaves; i++)
+    if(slValList[i].newVal) anyNewVal = true;
+  return(0);
+}
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapComDue/SoaapComDue.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapComDue/SoaapComDue.h
new file mode 100644
index 0000000000000000000000000000000000000000..990faa3710733dedfd4819f254c11b8900f15d65
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapComDue/SoaapComDue.h
@@ -0,0 +1,132 @@
+//-----------------------------------------------------------------------------
+// Thema:   Steuerung optischer und akustischer Ausgaben für Perfomer
+// Datei:   SoaapComDue.h
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   01.April 2022
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zum Zugriff auf den
+// SOAAP-BLE-Master über eine serielle Schnittstelle des Arduino DUE.
+//
+
+#ifndef SoaapComDue_h
+#define SoaapComDue_h
+
+#define ScdNrOfSlaves     6
+
+#include "USARTClass.h"
+#include "SoaapMsg.h"
+
+#ifndef byte
+#define byte unsigned char
+#endif
+
+
+class SoaapComDue
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // --------------------------------------------------------------------------
+  //
+  SoaapComDue(USARTClass *serial, SoaapMsg *soaMsg);
+
+  // --------------------------------------------------------------------------
+  // öffentliche Datentypen
+  // --------------------------------------------------------------------------
+  //
+  typedef union
+  {
+    short   defShort[9];
+    short   maxShort[13];
+    float   maxFloat[6];
+  } MeasValues, *pMeasValues;
+
+private:
+  // --------------------------------------------------------------------------
+  // lokale Datentypen
+  // --------------------------------------------------------------------------
+  //
+
+  typedef void (SoaapComDue::*CbVector)(void);
+  typedef struct
+  {
+    int         slaveArea;
+    int         slaveAdr;
+    SoaapApId   apId;
+    bool        newVal;
+    short       measList[13];
+  } SlaveValues, *pSlaveValues;
+
+private:
+  // --------------------------------------------------------------------------
+  // lokale Variablen
+  // --------------------------------------------------------------------------
+  //
+  USARTClass *pCom;
+  SoaapMsg   *pMsg;
+  CbVector    nextState;
+
+  int         nrBytesIn;          // Antahl aktuell empfangener Zeichen
+  int         serInCount;         // Zähler für empfangene Zeichen
+  int         serInIdx;           // Index für besonderes Zeichen
+  byte        serInChar;          // Einzelnes empfangenes Zeichen
+  int         slaveAdr;           // Adresse des Soaap-Slave
+  int         slaveArea;          // Quellennetzwerk-Info, Bereich, o.ä.
+  SoaapApId   appId;              // Anwendungskennung, Datentyp, o.ä.
+
+  int         measIdx;            // Index für den aktuellen Messwert
+  int         nrMeas;             // Anzahl der Messwerte im Telegramm
+  int         resMeas;            // Auflösung der Messwerte in Zeichen
+  bool        anyNewVal;          // Neuer Wert von beliebigem Slave
+
+  SlaveValues slValList[ScdNrOfSlaves + 1]; // Vorläufige Liste aller Messwerte
+  int         slaveIdx;           // Index für lokale Slaveverwaltung
+
+  byte        tmpBuffer[128];     // Zwischenspeicher für empfangene Zeichen
+
+  // --------------------------------------------------------------------------
+  // Inline-Methoden
+  // --------------------------------------------------------------------------
+  //
+
+  // Index von Slave best. Adresse für Datenliste
+  //
+  int  getSlIdxAdr(int slAdr)
+  {
+    // Zur Zeit sind Index und Slaveadresse identisch (1-6)
+    // Das wir später bei freier Zuordnung angepasst
+    return(slAdr);
+  }
+
+  // --------------------------------------------------------------------------
+  // lokale Methoden (Zustandsmaschine)
+  // --------------------------------------------------------------------------
+  //
+  void runInit();
+  void runWaitMsg();
+  void runHeader();
+  void runValues();
+
+  // --------------------------------------------------------------------------
+  // lokale Methoden (Hilfsfunktionen)
+  // --------------------------------------------------------------------------
+  //
+  int   getSlDataAvail();
+
+public:
+  // --------------------------------------------------------------------------
+  // Anwenderschnittstelle (Funktionen)
+  // --------------------------------------------------------------------------
+  //
+  void run();                     // (zyklischer) Aufruf zum Ablauf
+  int   anyDataAvail();           // Daten von irgendeinem Slave verfügbar
+  bool  slDataAvail(int slAdr);   // Daten von bestimmtem Slave verfügbar
+  int   getData(int slAdr, pMeasValues pMeas);
+  // Daten von einem bestimmten Slave abholen
+
+};
+
+#endif // SoaapComDue_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapComDue/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapComDue/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..d2cf1518adba3b9cb3a57d0eca8963fbceca345c
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapComDue/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "SoaapComDue",
+    "version": "0.0.0+20220804174235"
+  }
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapMsg/SoaapMsg.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapMsg/SoaapMsg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f3f29704b3b1d5e02528071b0527804940435bd
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapMsg/SoaapMsg.cpp
@@ -0,0 +1,159 @@
+//-----------------------------------------------------------------------------
+// Thema:   Steuerung optischer und akustischer Ausgaben für Perfomer
+// Datei:   SoaapMsg.h
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   18. März 2022
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Generierung
+// von Meldungen und Telegrammen, die im Rahmen des SOAAP-Projektes
+// eingesetzt werden.
+//
+
+#include "SoaapMsg.h"
+
+// ----------------------------------------------------------------------------
+// Konstruktoren und Initialisierungen
+// ----------------------------------------------------------------------------
+//
+SoaapMsg::SoaapMsg()
+{
+
+}
+
+// ----------------------------------------------------------------------------
+// Anwenderschnittstelle (Funktionen)
+// ----------------------------------------------------------------------------
+//
+
+// Erstellen eines ASCII-Telegramms zum Übertragen der Messwerte
+//
+int   SoaapMsg::getMsgA(int area, int slvNr, SoaapApId appId, char *dest, byte *meas)
+{
+  int   msgIdx = 0;
+  int   measIdx;
+  int   measLen;
+  byte  measByte;
+  char  measChar;
+
+  dest[msgIdx++]  = (char) (area | 0x10);
+  dest[msgIdx++]  = (char) (slvNr | 0x60);
+  dest[msgIdx++]  = (char) (appId);
+
+  switch(appId)
+  {
+    case saiDefaultMeas:
+      measLen = 18;
+      break;
+
+    case saiDefaultMeasCtrl:
+      measLen = 18;
+      break;
+
+   case saiMaximalMeas:
+      measLen = 26;
+      break;
+  }
+
+  for(measIdx = 0; measIdx < measLen; measIdx++)
+  {
+    measByte = meas[measIdx];
+
+    // Erst das niederwertige Nibble als Hex-Ascii eintragen
+    //
+    measChar = (measByte & 0x0F) | 0x30;
+    if (measChar > 0x39) measChar += 7;
+    dest[msgIdx++] = measChar;
+
+    // dann das höherwertige Nibble
+    //
+    measChar = (measByte >> 4) | 0x30;
+    if (measChar > 0x39) measChar += 7;
+    dest[msgIdx++] = measChar;
+  }
+
+  if(appId == saiDefaultMeasCtrl)
+  {
+    measByte = meas[20];
+
+    // Erst das niederwertige Nibble als Hex-Ascii eintragen
+    //
+    measChar = (measByte & 0x0F) | 0x30;
+    if (measChar > 0x39) measChar += 7;
+    dest[msgIdx++] = measChar;
+
+    // dann das höherwertige Nibble
+    //
+    measChar = (measByte >> 4) | 0x30;
+    if (measChar > 0x39) measChar += 7;
+    dest[msgIdx++] = measChar;
+  }
+
+  dest[msgIdx] = '\0';
+  return(msgIdx);
+}
+
+// Umwandeln eines Messwert aus ASCII-Telegramm in Integer
+//
+short  SoaapMsg::asc2meas(byte *ascList)
+{
+  unsigned short retv;
+
+  retv = getVal(ascList[0]);
+  retv += getVal(ascList[1]) << 4;
+  retv += getVal(ascList[2]) << 8;
+  retv += getVal(ascList[3]) << 12;
+
+  return((short) retv);
+}
+
+// Auflösung der Messwerte in Zeichen (Bytes)
+//
+int   SoaapMsg::measRes(SoaapApId appId)
+{
+  int retv = 0;
+
+  switch(appId)
+  {
+    case saiDefaultMeas:
+      retv = 4;
+      break;
+
+    case saiDefaultMeasCtrl:
+      retv = 4;
+      break;
+
+    case saiMaximalMeas:
+      retv = 4;
+      break;
+  }
+
+  return(retv);
+}
+
+// Anzahl der Messwerte im Telegramm
+//
+int   SoaapMsg::measCnt(SoaapApId appId)
+{
+  int retv = 0;
+
+  switch(appId)
+  {
+    case saiDefaultMeas:
+      retv = 9;
+      break;
+
+    case saiDefaultMeasCtrl:
+      retv = 9;
+      break;
+
+    case saiMaximalMeas:
+      retv = 13;
+      break;
+  }
+
+  return(retv);
+}
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapMsg/SoaapMsg.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapMsg/SoaapMsg.h
new file mode 100644
index 0000000000000000000000000000000000000000..20df5732381c353181e02ce74cf3cf193789c5a0
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapMsg/SoaapMsg.h
@@ -0,0 +1,73 @@
+//-----------------------------------------------------------------------------
+// Thema:   Steuerung optischer und akustischer Ausgaben für Perfomer
+// Datei:   SoaapMsg.h
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   18. März 2022
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Generierung
+// von Meldungen und Telegrammen, die im Rahmen des SOAAP-Projektes
+// eingesetzt werden.
+//
+
+#ifndef SoaapMsg_h
+#define SoaapMsg_h
+
+#include "arduinoDefs.h"
+
+typedef enum
+{
+  saiDefaultMeas = 0x68,
+  saiMaximalMeas = 0x69,
+  saiDefaultMeasCtrl = 0x6A
+} SoaapApId;
+
+class SoaapMsg
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // --------------------------------------------------------------------------
+  //
+  SoaapMsg();
+
+private:
+  // --------------------------------------------------------------------------
+  // lokale Variablen
+  // --------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Inline-Methoden
+  // --------------------------------------------------------------------------
+  //
+  int getVal(char hexAsc)
+  {
+    if(hexAsc < 0x39) return(hexAsc - 0x30);
+    else return(hexAsc - 0x37);
+  }
+
+
+public:
+  // --------------------------------------------------------------------------
+  // Anwenderschnittstelle (Funktionen)
+  // --------------------------------------------------------------------------
+  //
+
+  int   getMsgA(int area, int slvNr, SoaapApId appId, char *dest, byte *meas);
+  // Erstellen eines ASCII-Telegramms zum Übertragen der Messwerte
+
+  short asc2meas(byte *ascList);
+  // Umwandeln eines Messwert aus ASCII-Telegramm in Integer
+
+  int   measRes(SoaapApId appId);
+  // Auflösung der Messwerte in Zeichen (Bytes)
+
+  int   measCnt(SoaapApId appId);
+  // Anzahl der Messwerte
+
+};
+
+#endif // SoaapMsg_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapMsg/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapMsg/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..86be2b961f0f6f6dae95ed22fadc55f7a1c58826
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/SoaapMsg/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "SoaapMsg",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/StateMachine/StateMachine.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/StateMachine/StateMachine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c1f78d3b83eabbc30463d78e693b470e345e140
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/StateMachine/StateMachine.cpp
@@ -0,0 +1,480 @@
+// ---------------------------------------------------------------------------
+// File:        StateMachine.cpp
+// Editors:     Robert Patzke,
+// Start:       07. February 2018
+// Last change: 22. February 2021
+// URI/URL:     www.mfp-portal.de, homeautomation.x-api.de
+// Licence:     Creative Commons CC-BY-SA
+// ---------------------------------------------------------------------------
+//
+
+#include "StateMachine.h"
+
+// ---------------------------------------------------------------------------
+// Constructors and initialisations
+// ---------------------------------------------------------------------------
+//
+
+int  StateMachine::StateMachine_InstCounter;
+
+StateMachine::StateMachine(){;} // @suppress("Class members should be properly initialized")
+
+StateMachine::StateMachine(StatePtr firstState, StatePtr anyState, int cycle)
+{
+  begin(firstState, anyState, cycle);
+}
+
+StateMachine::StateMachine(StatePtr firstState, StatePtr anyState, int cycle, MicsecFuPtr micsecFu)
+{
+  begin(firstState, anyState, cycle, micsecFu);
+}
+
+void StateMachine::begin(StatePtr firstState, StatePtr anyState, int cycle)
+{
+  begin(firstState, anyState, cycle, NULL);
+}
+
+void StateMachine::begin(StatePtr firstState, StatePtr anyState, int cycle, MicsecFuPtr micsecFu)
+{
+  nextState     = firstState;
+  doAlways      = anyState;
+  cycleTime     = cycle;
+  frequency     = 1000 / cycle;
+  delay         = 0;
+  delaySet      = 0;
+  repeatDelay   = false;
+  userStatus    = 0;
+
+  StateMachine_InstCounter++;
+  instNumber    = StateMachine_InstCounter;
+  micsFuPtr     = micsecFu;
+}
+
+// ---------------------------------------------------------------------------
+// run      State enter function, has to be cyclic called
+// ---------------------------------------------------------------------------
+//
+void StateMachine::run()
+{
+  unsigned long startMics = 0, diffMics;
+
+  runCounter++;
+
+  if(timeOutCounter > 0)
+    timeOutCounter--;
+
+  if(timeMeasureOn)
+    timeMeasureCounter++;
+
+  if(doAlways != NULL)
+    doAlways();
+
+  if(delay > 0)
+  {
+    delay--;
+    return;
+  }
+
+  if(repeatDelay)
+    delay = delaySet;
+
+  if(useProgList)
+  {
+    if(progIndex == progEndIdx)
+    {
+      if(loopProgList)
+      {
+        progIndex = 0;
+        nextState = progList[progIndex];
+        progIndex++;
+      }
+      else
+      {
+        useProgList = false;
+        nextState = finProgState;
+      }
+    }
+    else
+    {
+      nextState = progList[progIndex];
+      progIndex++;
+    }
+  }
+
+  if(nextState != NULL)
+  {
+    if(micsFuPtr != NULL)
+      startMics = micsFuPtr();
+
+    nextState();
+
+    if(micsFuPtr != NULL)
+    {
+      diffMics = micsFuPtr() - startMics;
+      curStateRuntime = diffMics;
+
+      if(diffMics > maxStateRuntime[0])
+      {
+        maxStateRuntime[0]  = diffMics;
+        maxRuntimeNumber[0] = curStateNumber;
+      }
+      else if(diffMics > maxStateRuntime[1])
+      {
+        if(curStateNumber != maxRuntimeNumber[0])
+        {
+          maxStateRuntime[1]  = diffMics;
+          maxRuntimeNumber[1] = curStateNumber;
+        }
+      }
+      else if(diffMics > maxStateRuntime[2])
+      {
+        if(curStateNumber != maxRuntimeNumber[1])
+        {
+          maxStateRuntime[2]  = diffMics;
+          maxRuntimeNumber[2] = curStateNumber;
+        }
+      }
+      else if(diffMics > maxStateRuntime[3])
+      {
+        if(curStateNumber != maxRuntimeNumber[2])
+        {
+          maxStateRuntime[3]  = diffMics;
+          maxRuntimeNumber[3] = curStateNumber;
+        }
+      }
+    }
+  }
+  else
+    noStateCounter++;
+
+}
+
+// ---------------------------------------------------------------------------
+// service functions/methods for manipulating the state machine
+// ---------------------------------------------------------------------------
+//
+
+// checking a state for staying (not enter new state)
+//
+bool StateMachine::stayHere()
+{
+  if(repeatState > 0)
+  {
+    repeatState--;
+    if(repeatState == 0)
+    {
+      repeatDelay = false;
+    }
+    return(true);
+  }
+
+  firstEnterToggle = true;
+  return(false);
+}
+
+// setting delay before next state
+//
+void StateMachine::setDelay(int delayTime)
+{
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+}
+
+// setting internal speed of the state machine
+// can only be slower than the calling frequency
+//
+void StateMachine::setSpeed(int freq)
+{
+  delaySet      = delay = frequency / freq;
+  repeatDelay   = true;
+}
+
+// setting future state to be called by run
+//
+void StateMachine::enter()
+{
+  if(stayHere()) return;
+
+  pastState = nextState;
+  nextState = futureState;
+}
+
+// setting next state to be called by run
+//
+void StateMachine::enter(StatePtr next)
+{
+  if(stayHere()) return;
+
+  pastState = nextState;
+  nextState = next;
+}
+
+// setting next state with delay (before)
+//
+void StateMachine::enter(StatePtr next, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState = nextState;
+  nextState = next;
+}
+
+// setting next state with repetition
+//
+void StateMachine::enterRep(StatePtr next, int count)
+{
+  if(stayHere()) return;
+
+  repeatState   = count;
+  pastState     = nextState;
+  nextState     = next;
+}
+
+// setting next state with repetition and delay
+//
+void StateMachine::enterRep(StatePtr next, int count, int delayTime)
+{
+  if(stayHere()) return;
+
+  delaySet = delay = (delayTime * frequency) / 1000;
+  repeatDelay = true;
+
+  repeatState   = count;
+  pastState     = nextState;
+  nextState     = next;
+}
+
+// setting state and state after
+//
+void StateMachine::enterVia(StatePtr next, StatePtr then)
+{
+  if(stayHere()) return;
+
+  pastState     = nextState;
+  nextState     = next;
+  futureState   = then;
+}
+
+// calling state
+//
+void StateMachine::call(StatePtr next)
+{
+  if(stayHere()) return;
+
+  pastState     = nextState;
+  futureState   = nextState;
+  nextState     = next;
+}
+
+// setting state and state after with delay
+//
+void StateMachine::enterVia(StatePtr next, StatePtr after, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState     = nextState;
+  nextState     = next;
+  futureState   = after;
+}
+
+// calling state
+//
+void StateMachine::call(StatePtr next, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState     = nextState;
+  futureState   = nextState;
+  nextState     = next;
+}
+
+
+// setting state to state list (program)
+//
+void StateMachine::enterList(StatePtr fin)
+{
+  if(stayHere()) return;
+
+  pastState     = nextState;
+  useProgList   = true;
+  progIndex     = 0;
+  finProgState  = fin;
+}
+
+// setting state to state list (program)and delay
+//
+void StateMachine::enterList(StatePtr fin, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState     = nextState;
+  useProgList   = true;
+  progIndex     = 0;
+  finProgState  = fin;
+}
+
+// setting state to state list (program) at a position
+//
+void StateMachine::enterListAt(StatePtr fin, int index)
+{
+  if(stayHere()) return;
+
+  pastState     = nextState;
+  useProgList   = true;
+  progIndex     = index;
+  finProgState  = fin;
+}
+
+// setting state to state list (program)at a position and delay
+//
+void StateMachine::enterListAt(StatePtr fin, int index, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState     = nextState;
+  useProgList   = true;
+  progIndex     = index;
+  finProgState  = fin;
+}
+
+// detecting the first call of a state
+//
+bool StateMachine::firstEnter()
+{
+  if(!firstEnterToggle)
+    return(false);
+  firstEnterToggle = false;
+  return(true);
+}
+
+// reset first enter detector
+//
+void StateMachine::resetEnter()
+{
+  firstEnterToggle = true;
+}
+
+// counting local cycles
+//
+bool StateMachine::cycle(int cnt)
+{
+  if(callCycleCnt <= 0)
+  {
+    callCycleCnt = cnt;
+    return(true);
+  }
+  callCycleCnt--;
+  return(false);
+}
+//
+bool StateMachine::cycleSec()
+{
+  if(callCycleCnt <= 0)
+  {
+    callCycleCnt = frequency;
+    return(true);
+  }
+  callCycleCnt--;
+  return(false);
+}
+
+// Alternativly returning true and false
+//
+bool StateMachine::toggle()
+{
+  markToggle = !markToggle;
+  return(markToggle);
+}
+
+// Doing only once
+//
+bool StateMachine::oneShot()
+{
+  if(!markOneShot) return(false);
+
+  markOneShot = false;
+  return (true);
+}
+
+void StateMachine::setOneShot()
+{
+  markOneShot = true;
+}
+
+
+// Setable number of returning TRUE
+//
+void  StateMachine::setCondCounter(unsigned int condVal)
+{
+  condCounter = condVal;
+}
+
+bool  StateMachine::condOpen()
+{
+  if(condCounter == 0)
+    return(false);
+  condCounter--;
+  return(true);
+}
+
+// set the time-out value (milliseconds)
+//
+void StateMachine::setTimeOut(int toValue)
+{
+  timeOutCounter = (toValue * frequency) / 1000;
+}
+
+// check the time-out counter
+//
+bool StateMachine::timeOut()
+{
+  if(timeOutCounter > 0)
+    return(false);
+  return(true);
+}
+
+// start time measurement
+//
+void StateMachine::startTimeMeasure()
+{
+  timeMeasureCounter = 0;
+  timeMeasureOn = true;
+}
+
+int StateMachine::getTimeMeasure(bool stop)
+{
+  if(stop)
+    timeMeasureOn = false;
+  return(cycleTime * timeMeasureCounter);
+}
+
+unsigned long StateMachine::getExtTimeMeasure(bool stop)
+{
+  if(stop)
+    timeMeasureOn = false;
+  return(cycleTime * timeMeasureCounter);
+}
+
+// ---------------------------------------------------------------------------
+// Debug and statistic functions/methods
+// ---------------------------------------------------------------------------
+//
+int StateMachine::getDelay()
+{
+  return(delay);
+}
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/StateMachine/StateMachine.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/StateMachine/StateMachine.h
new file mode 100644
index 0000000000000000000000000000000000000000..b5a6ecea89a1a4a81795bf2992e52dd58bb350d2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/StateMachine/StateMachine.h
@@ -0,0 +1,171 @@
+// ---------------------------------------------------------------------------
+// File:        StateMachine.cpp
+// Editors:     Robert Patzke,
+// Start:       07. February 2018
+// Last change: 07. February 2018
+// URI/URL:     www.mfp-portal.de, homeautomation.x-api.de
+// Licence:     Creative Commons CC-BY-SA
+// ---------------------------------------------------------------------------
+//
+
+#include    "stdlib.h"
+
+
+#ifndef _StateMachine_h
+#define _StateMachine_h
+// ---------------------------------------------------------------------------
+
+#define NrOfSteps       32
+
+#define AUTBREAK(x,y)   { x.enter(y); return; }
+
+// ---------------------------------------------------------------------------
+// class StateMachine
+// ---------------------------------------------------------------------------
+//
+
+class StateMachine
+{
+  // -------------------------------------------------------------------------
+  // class specific data types
+  // -------------------------------------------------------------------------
+  //
+  typedef void (*StatePtr)(void);
+  typedef unsigned long (*MicsecFuPtr)(void);
+
+private:
+  // -------------------------------------------------------------------------
+  // local variables
+  // -------------------------------------------------------------------------
+  //
+  int       delay;              // Setting of delay for next state
+  int       delaySet;           // Setup value for repeated delays
+  bool      repeatDelay;        // If true, every state is delayed (speed set)
+  int       repeatState;        // Controlled repeating a state
+  bool      useVarState;        // breaking the fixed sequence of states by
+                                // using a variable state (in futureState)
+
+  bool        useProgList;            // control progList usage
+  bool        loopProgList;           // looping proglist
+  StatePtr    progList[NrOfSteps];    // dynamically created state run list
+  int         progIndex;              // Program counter (index to next state)
+  int         progEndIdx;             // Index to next empty progList entry
+  StatePtr    finProgState;           // State after using state list
+  MicsecFuPtr micsFuPtr;              // Pointer to micsec function
+
+  bool      firstEnterToggle;       // Is set to true when state changes
+  int       timeOutCounter;         // automatic decremented counter
+
+  bool            timeMeasureOn;          // control of the measurement counter
+  unsigned long   timeMeasureCounter;     // triggered automatic incremented counter
+
+  int       callCycleCnt;           // For cycles inside a state
+  bool      markToggle;             // For bit complements
+  bool      markOneShot;            // for doing only one time
+
+  unsigned int  condCounter;        // Counter for questionable conditions
+
+  // -------------------------------------------------------------------------
+  // local functions/methods
+  // -------------------------------------------------------------------------
+  //
+  bool stayHere();
+
+public:
+  // -------------------------------------------------------------------------
+  // public variables
+  // -------------------------------------------------------------------------
+  //
+  StatePtr  nextState;          // Pointer for indirect calling next state
+  StatePtr  pastState;          // Pointer of the past state
+  StatePtr  futureState;        // Pointer to a future state (see useVarState)
+  StatePtr  doAlways;           // Pointer to a always called state
+  int       cycleTime;          // Cycle time in milliseconds
+  int       frequency;          // Frequency in Hertz (1/s)
+  int       userStatus;         // A number presenting the visible state
+
+  // statistic information
+  //
+  static int   StateMachine_InstCounter;
+
+  unsigned int    noStateCounter;       // Counter for empty running of state machine
+  unsigned int    instNumber;           // Number of this instance
+  unsigned int    runCounter;           // Counter for running states
+  unsigned int    curStateNumber;       // Number of current state
+
+  unsigned long   curStateRuntime;      // run time of latest state
+  unsigned long   maxStateRuntime[4];   // Maximum run time of a state
+  unsigned long   maxRuntimeNumber[4];  // Number of the state of maximum runtime
+
+  // error and debug support
+  //
+  int   userError;
+
+  // -------------------------------------------------------------------------
+  // constructors and initialisations
+  // -------------------------------------------------------------------------
+  //
+  StateMachine();
+  StateMachine(StatePtr firstState, StatePtr anyState, int cycle);
+  void begin(StatePtr firstState, StatePtr anyState, int cycle);
+  StateMachine(StatePtr firstState, StatePtr anyState, int cycle, MicsecFuPtr micsecFu);
+  void begin(StatePtr firstState, StatePtr anyState, int cycle, MicsecFuPtr micsecFu);
+
+  // -------------------------------------------------------------------------
+  // user functions
+  // -------------------------------------------------------------------------
+  //
+  void      run();                                  // has to be cyclic called
+  void      setDelay(int delayTime);                // delay before next state
+  void      setSpeed(int freq);                     // internal run frequency
+
+  void      enter();                                // set next to future state
+  void      enter(StatePtr state);                  // set next state to run
+  void      enter(StatePtr state, int delayTime);   // ... delayed
+
+  void      enterRep(StatePtr state, int count);    // repeat next state
+  void      enterRep(StatePtr state, int count, int delayTime);
+
+  void      call(StatePtr state);                   // set next state and return
+  void      call(StatePtr state, int delayTime);    // ... delayed
+
+  void      enterVia(StatePtr next, StatePtr future);       // next and then
+  void      enterVia(StatePtr next, StatePtr future, int delayTime);
+
+  void      enterList(StatePtr fin);
+  void      enterList(StatePtr fin, int delayTime);
+
+  void      enterListAt(StatePtr fin, int index);
+  void      enterListAt(StatePtr fin, int index, int delayTime);
+
+  bool      firstEnter();       // true only, if the state is first entered
+  void      resetEnter();       // reset first enter mark
+  bool      cycle(int cnt);     // true only, if called <cnt> times
+  bool      cycleSec();         // true only, if a second passed
+  bool      toggle();           // alternating return true and false
+  bool      oneShot();          // only one time true for a call
+  void      setOneShot();       // preparing oneShot to be true
+
+  void      setTimeOut(int toValue);        // Set time-out counter
+  bool      timeOut();                      // Check time-out counter
+  void      startTimeMeasure();             // Start time measurement
+  int       getTimeMeasure(bool stop);      // Time in milliseconds
+
+  unsigned long getExtTimeMeasure(bool stop);     // Time in milliseconds
+
+  void      setCondCounter(unsigned int cntVal);  // Set condition counter
+  bool      condOpen();                           // Ask for open conditions
+
+  // -------------------------------------------------------------------------
+  // debug functions
+  // -------------------------------------------------------------------------
+  //
+  int       getDelay();
+
+};
+
+
+
+
+// ---------------------------------------------------------------------------
+#endif
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/StateMachine/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/StateMachine/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..4dbee447df0f4ef48684a8d78288826ff419108f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/StateMachine/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "StateMachine",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfBuf.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfBuf.h
new file mode 100644
index 0000000000000000000000000000000000000000..c2f41d77dacb2618fee37685820740222e70b8b3
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfBuf.h
@@ -0,0 +1,48 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfBuf.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   22. November 2021
+//
+// Eine Schnittstelle zu Puffern (speziell Ringpuffer für Kommunikation)
+//
+
+#ifndef IntrfBuf_h
+#define IntrfBuf_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+
+
+class IntrfBuf
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  virtual bool  getByteSnd(byte *dest);   // Byte aus Puffer zum Senden holen
+                                          // Rückgabe FALSE: Puffer leer
+
+  virtual void  putByteRec(byte b);       // Byte vom Empfang an Puffer geben
+
+  virtual int   putSeq(byte *msg, int n); // Bytefolge an Puffer übergeben
+
+};
+
+// ----------------------------------------------------------------------------
+#endif  // IntrfBuf_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfGpio.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfGpio.h
new file mode 100644
index 0000000000000000000000000000000000000000..d37fdf6765d077ac1bc20944080dc257f55e0a8a
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfGpio.h
@@ -0,0 +1,122 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfGpio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   04. April 2022
+//
+// Eine Schnittstelle zu den unterschiedlichen Ports in Mikrocontrollern
+//
+
+#ifndef IntrfGpio_h
+#define IntrfGpio_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+
+typedef enum _ifPortNumber
+{
+  ifPort0,
+  ifPort1,
+  ifPort2,
+  ifPort3,
+  ifPort4,
+  ifPort5,
+  ifPort6,
+  ifPort7,
+  ifPort8,
+  ifPort9
+} ifPortNumber;
+
+typedef enum
+{
+  GEnoError,
+  GEcdictPar
+} GpioError;
+
+typedef struct _GpioMask
+{
+  dword       port;
+  dword       pins;
+} GpioMask, *GpioMaskPtr;
+
+typedef struct _GpioExtMask
+{
+  dword         port;
+  dword         pins;
+  _GpioExtMask  *next;
+} GpioExtMask, *GpioExtMaskPtr;
+
+typedef struct _GpioRef
+{
+  dword     *ioPtr;
+  dword     pins;
+} GpioRef, *GpioRefPtr;
+
+typedef struct _GpioExtRef
+{
+  dword       *ioPtr;
+  dword       pins;
+  _GpioExtRef *next;
+} GpioExtRef, *GpioExtRefPtr;
+
+typedef struct _GpioExtVal
+{
+  dword       value;
+  _GpioExtVal *next;
+} GpioExtVal, *GpioExtValPtr;
+
+// Spezifikation der Schnittstellentreiber
+//
+#define IfDrvInput          0x0000
+#define IfDrvOutput         0x0001
+#define IfDrvStrongHigh     0x0002
+#define IfDrvStrongLow      0x0004
+#define IfDrvOpenDrain      0x0008
+#define IfDrvOpenSource     0x0010
+#define IfDrvPullUp         0x0020
+#define IfDrvPullDown       0x0040
+#define IfDrvPullStrong     0x0080
+
+typedef enum
+{
+  ArdD2D5,
+  ArdA0A3,
+  ArdA4A5,
+  ArdA0A5,
+  ArdA4A7,
+  ArdA0A7
+} ArdMask;
+
+class IntrfGpio
+{
+public:
+
+  //virtual ~IntrfGpio();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual GpioError config(int nr, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  virtual GpioError config(int nrFrom, int nrTo, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  virtual GpioError config(GpioExtMask mask, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  virtual GpioError configArd(ArdMask ardMask, unsigned int cnfBits);
+
+  // --------------------------------------------------------------------------
+  // Anwendungsfunktionen
+  // --------------------------------------------------------------------------
+  //
+  virtual void      read(GpioExtRefPtr refPtr, GpioExtValPtr valPtr);
+  virtual dword     readArd(ArdMask ardMask);
+
+  virtual void      write(GpioExtRefPtr refPtr, GpioExtValPtr valPtr);
+  virtual void      writeArd(ArdMask ardMask, dword value);
+  virtual void      set(GpioExtRefPtr refPtr);
+  virtual void      clr(GpioExtRefPtr refPtr);
+};
+
+// ----------------------------------------------------------------------------
+#endif //IntrfGpio_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfRadio.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfRadio.h
new file mode 100644
index 0000000000000000000000000000000000000000..470277ab4f365581507365d1f412a47683463662
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfRadio.h
@@ -0,0 +1,154 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfRadio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   9. Mai 2021
+//
+// Eine Schnittstelle zu den unterschiedlichen Transceivern in Mikrocontrollern
+// oder Boards mit Mikrocontrollern und Radio-Transceivern
+//
+
+#ifndef IntrfRadio_h
+#define IntrfRadio_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+#include "bleSpec.h"
+
+typedef struct _TxState
+{
+  unsigned int  prgLoopPrep;
+  unsigned int  evtLoopRampUp;
+  unsigned int  evtLoopTrans;
+  byte  *       txBufferPtr;
+} TxState, *TxStatePtr;
+
+typedef struct  _Channel
+{
+  int   idx;
+  int   freq;
+} Channel, *ChannelPtr;
+
+// Zustand des Datenempfangs (Bit)
+//
+#define RECSTAT_ADDRESS   0x0001
+#define RECSTAT_PAYLOAD   0x0002
+#define RECSTAT_END       0x0004
+#define RECSTAT_DISABLED  0x0008
+#define RECSTAT_CRCOK     0x0010
+
+// Modi für das Senden von Telegrammen
+//
+typedef enum _TxMode
+{
+  txmBase,      // Einzelne Sendung, Endezustand DISABLED
+  txmRepStart,  // Wiederholte Sendung Start, Endezustand END
+  txmRepCont,   // Wiederholte Sendung Fortsetzung, Endezustand END
+  txmRepEnd,    // Wiederholte Sendung Ende, Endezustand DISABLED
+  txmReadPrep,  // Einzelne Sendung mit Empfangsvorbereitung, Endezustand READY
+  txmRead,      // Einzelne Sendung und Empfang, Endezustand END
+  txmPoll,      // Einzelne Sendung und Empfang, Endezustand DISABLED
+  txmReadS,     // Einzelne sendung und Empfang mit Daten, Endezustand END
+  txmRespE,     // Empfang für spezifische Antwort (leeres Polling)
+  txmResp       // Empfang für spezifische Antwort (Datenübertragung)
+} TxMode;
+//
+#define NrOfTxModes   10
+
+// Protokollspezifische Adresseninhalte und Festlegungen
+//
+#define PollPduSize   8
+#define PollAdrSize   6
+
+// len = PduMem[1]
+#define BLE_LEN       pduMem[1]
+// Adr[1] = PduMem[3]
+#define BLE_ADR1      pduMem[3]
+
+#define SOAAP_NAK     0x40
+#define SOAAP_EADR    0x80
+
+// Modeabhängige Statistikdaten
+//
+typedef struct _TxStatistics
+{
+  TxMode      mode;
+  dword       interrupts;
+  dword       recs;
+  dword       sendings;
+  dword       aliens;
+  dword       wrongs;
+  dword       pollAcks;
+  dword       pollNaks;
+  dword       crcErrors;
+  dword       intErrors;
+  byte        memDumpRec[16];
+  byte        memDumpSnd[16];
+} TxStatistics, *TxStatisticsPtr;
+
+class IntrfRadio
+{
+public:
+  // Kanalfrequenzen (Offsets zur Basisfrequenz) und Whitening-Preset
+  // Die ersten 3 Kanäle sind Bewerbungskanäle.
+  // Daran anschließend sind die Kanäle grob nach Frequenz einsortiert.
+  // Diese Liste kann zur Laufzeit an Störungen angepasst werden und wird aufsteigend angewendet
+  //
+  Channel channelList[40] =
+  {
+      {37, 2} , {38,26} , {39,80} , { 1, 6} , { 3,10} , { 5,14} , { 7,18} , { 9,22} ,
+      {12,30} , {14,34} , {16,38} , {18,42} , {20,46} , {22,50} , {24,54} , {26,58} ,
+      {28,62} , {30,66} , {32,70} , {34,74} , {35,76} , { 2, 8} , { 4,12} , { 6,16} ,
+      { 8,20} , {33,72} , {31,68} , {13,32} , {15,36} , {17,40} , {19,44} , {21,48} ,
+      {23,52} , {25,56} , {27,60} , {29,64} , {11,28} , {10,24} , { 0, 4} , {36,78}
+  };
+
+  //virtual ~IntrfRadio();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual void  begin();
+  virtual void  setAccessAddress(dword addr);
+  virtual void  setPacketParms(blePduType type);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  virtual void  setChannel(int chnr);         // Schalten physikalischer Kanal
+  virtual int   sendSync(bcPduPtr inPduPtr, TxStatePtr refState);
+
+  virtual void  send(bcPduPtr inPduPtr, TxMode txMode);
+  virtual void  send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, bool newValues);
+  // Senden (und/oder Empfang) eines Telegramms in einem festgelegten Modus
+
+  virtual void  disable(TxMode txMode);       // Funk AUS für Betriebswechsel
+  virtual bool  disabled(TxMode txMode);      // Abfrage, ob ausgeschaltet
+  virtual void  cont(TxMode txMode);          // aktuellen Vorgang fortsetzen
+  virtual bool  fin(TxMode txMode, bool *err);  // Abfrage ob aktueller Vorgang beendet
+// virtual int   getRecData(bcPduPtr data, TxMode txMode, int max); // Lennard: Deaktiviert
+
+  virtual int   startRec();                   // Datenempfang starten
+  virtual int   contRec();                    // Datenempfang fortsetzen
+  virtual int   endRec();                     // Datenempfang beenden
+  virtual int   checkRec();                   // Zustand Datenempfang feststellen
+  virtual int   getRecData(bcPduPtr data, int max);  // Empfangene Daten lesen
+
+  virtual void  setPower(int DBm);            // Leistung des Senders in DBm
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  virtual int   getStatistics(TxStatisticsPtr dest);
+  virtual int   getState();                   // Chip-abhängiger Funk-Status
+
+};
+
+// ----------------------------------------------------------------------------
+#endif  // IntrfRadio_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfSerial.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfSerial.h
new file mode 100644
index 0000000000000000000000000000000000000000..909a810a3282ef0e1ee36e79286bd5c4df0bb929
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfSerial.h
@@ -0,0 +1,101 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfSerial.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   17. November 2021
+//
+// Eine Schnittstelle zu den seriellen Schnittstellen in Mikrocontrollern
+// oder Boards mit Mikrocontrollern und seriellen schnittstellen
+//
+
+#ifndef IntrfSerial_h
+#define IntrfSerial_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+#include "IntrfBuf.h"
+
+typedef enum _SerSpeed
+{
+  Baud1200,
+  Baud2400,
+  Baud4800,
+  Baud9600,
+  Baud14400,
+  Baud19200,
+  Baud28800,
+  Baud31250,
+  Baud38400,
+  Baud56000,
+  Baud57600,
+  Baud76800,
+  Baud115200,
+  Baud230400,
+  Baud250000,
+  Baud460800,
+  Baud921600,
+  Baud1Meg
+} SerSpeed;
+
+typedef enum _SerType
+{
+  stStd,      // Typischer Ausgang ca. 2 mA
+  stPow,      // Starker Ausgang ca. 10 mA
+  stCur       // Open Collector/Drain ca. 10 mA Stromschleife
+} SerType;
+
+typedef struct _SerParams
+{
+  int         inst;           // Nummer (Index) der Ser-Instanz
+  int         txdPort;        // Nummer (Index) des Port fuer TX
+  int         txdPin;         // Nummer (Index) des Pin fuer TX
+  int         rxdPort;        // Nummer (Index) des Port fuer RX
+  int         rxdPin;         // Nummer (Index) des Pin fuer RX
+  SerSpeed    speed;          // Bitrate (Baud)
+  SerType     type;           // Ausgang
+} SerParams, *SerParamsPtr;
+
+typedef enum _SerError
+{
+  SEnoError
+} SerError;
+
+
+class IntrfSerial
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual void  begin(SerParamsPtr serParPtr, IntrfBuf * bufferIf);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  virtual void resuSend();    // Fortsetzen des Interrupt-Sendebetriebs
+  virtual void startSend();   // Starten des Sendebetriebs
+  virtual void stopSend();    // Anhalten des Sendebetriebs
+
+  virtual void startRec();    // Starten des Empfangsbetriebs
+  virtual void stopRec();     // Anhalten des Empfangsbetriebs
+
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  virtual bool condSend(byte c);  // Bedingtes Senden eines Zeichens
+
+  virtual int   getLastError();   // Letzten Fehler lesen (Bits)
+  virtual int   getAnyError();    // Alle vorgekommenen Fehlerbits
+  virtual dword getErrCount();    // Anzahl der Fehler lesen
+
+};
+
+// ----------------------------------------------------------------------------
+#endif  // IntrfRadio_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfTimer.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfTimer.h
new file mode 100644
index 0000000000000000000000000000000000000000..2777f5ba7b80b1116baa9030c452037dc4507952
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfTimer.h
@@ -0,0 +1,55 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfTimer.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   29. Juni 2021
+//
+// Eine Schnittstelle zu den unterschiedlichen Timern in Mikrocontrollern
+//
+
+#ifndef IntrfTimer_h
+#define IntrfTimer_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+
+typedef enum _ifTimerNumber
+{
+  ifTimer0,
+  ifTimer1,
+  ifTimer2,
+  ifTimer3,
+  ifTimer4,
+  ifTimer5,
+  ifTimer6,
+  ifTimer7,
+  ifTimer8,
+  ifTimer9
+} ifTimerNumber;
+
+class IntrfTimer
+{
+public:
+
+  //virtual ~IntrfTimer();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual void  setMilli(ifTimerNumber timNr, int milliSec, int repeat);
+  //virtual void  setMilli(ifTimerNumber timNr, int milliSec, int repeat, dword ISR);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  virtual bool  milli();        // Abfrage des Timer, <true> wenn abgelaufen
+
+};
+
+// ----------------------------------------------------------------------------
+#endif //IntrfTimer_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfTw.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfTw.h
new file mode 100644
index 0000000000000000000000000000000000000000..f0d97b622e98f8f48ee8f066912caf1b4723bc89
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/IntrfTw.h
@@ -0,0 +1,125 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfTw.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   3. Juni 2021
+//
+// Eine Schnittstelle zu den unterschiedlichen I2C Schnittstellen
+// oder Boards mit geeigneten Mikrocontrollern
+//
+
+#ifndef IntrfTw_h
+#define IntrfTw_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+
+typedef enum _TwiDevType
+{
+  TwiMaster,
+  TwiSlave
+} TwiDevType;
+
+typedef enum _TwiSpeed
+{
+  Twi100k,      // Standard, sollte unterstützt werden
+  Twi250k,
+  Twi400k       // Schnell, sollte unterstützt werden
+} TwiSpeed;
+
+typedef struct _TwiParams
+{
+  int         inst;           // Nummer (Index) der Twi-Instanz
+  TwiDevType  type;           // Auswahl Master/Slave
+  int         clkPort;        // Nummer (Index) des Port fuer Takt
+  int         clkPin;         // Nummer (Index) des Pin fuer Takt
+  int         dataPort;       // Nummer (Index) des Port fuer Daten
+  int         dataPin;        // Nummer (Index) des Pin fuer Daten
+  TwiSpeed    speed;
+} TwiParams, *TwiParamsPtr;
+
+typedef enum _TwiError
+{
+  TEnoError
+} TwiError;
+
+typedef enum _TwiStatus
+{
+  TwStUnborn,
+  TwStRdReq,
+  TwStWrReq,
+  TwStSent,
+  TwStRecvd,
+  TwStFin     = 0x0080,
+  TwStError   = 0x0100,
+  TwStOverrun = 0x0101,
+  TwStAdrNak  = 0x0102,
+  TwStDataNak = 0x0104
+} TwiStatus;
+
+typedef struct _TwiByte
+{
+  TwiStatus   twiStatus;
+  byte        value;
+} TwiByte, *TwiBytePtr;
+
+typedef struct _TwiWord
+{
+  TwiStatus   twiStatus;
+  word        value;
+} TwiWord, *TwiWordPtr;
+
+typedef struct _TwiByteSeq
+{
+  TwiStatus   twiStatus;
+  int         len;
+  byte        *valueRef;
+} TwiByteSeq, *TwiByteSeqPtr;
+
+
+class IntrfTw
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // --------------------------------------------------------------------------
+  //
+  virtual TwiError begin(TwiParamsPtr inParPtr);
+
+  //virtual ~IntrfTw();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual void getParams(TwiParamsPtr parPtr);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Datenaustausch
+  // --------------------------------------------------------------------------
+  //
+  // asynchrone Kommunikation, Zustand in TwiByte.twiStatus
+  //
+  virtual TwiError sendByte(int adr, TwiBytePtr refByte);
+  virtual TwiError sendByteReg(int adr, int reg, TwiBytePtr refByte);
+  virtual TwiError recByteReg(int adr, int reg, TwiBytePtr refByte);
+  virtual TwiError recByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq);
+
+  // synchrone Kommunikation
+  //
+  virtual TwiStatus writeByteReg(int adr, int reg, byte value);
+  virtual int       readByteReg(int adr, int reg);
+  virtual TwiStatus readByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq);
+
+};
+
+// ----------------------------------------------------------------------------
+#endif  // IntrfTw_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/SoaapBleMaster.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/SoaapBleMaster.h
new file mode 100644
index 0000000000000000000000000000000000000000..98bd22eb99c0839cf9f5ad554dd116b21c0afd81
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/SoaapBleMaster.h
@@ -0,0 +1,63 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleMaster.h
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                        P o l l i n g - M a s t e r
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. November 2021
+// Letzte Bearbeitung: 15. März 2022
+//
+
+#ifndef SoaapBleMaster_h
+#define SoaapBleMaster_h
+
+// Vordefinitionen, Festlegungen zur Kompilierung
+//
+#define DebugTerminal
+// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden
+// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist
+
+//#define TEST001
+// Ausgaben an serielle schnittstelle zur Prüfung der ap-Zustandsmaschine
+
+#include  "LoopCheck.h"
+#include  "StateMachine.h"
+#include  "nRF52840Radio.h"
+#include  "BlePoll.h"
+#include  "ComRingBuf.h"
+#include  "nRF52840Ser.h"
+#include  "SoaapMsg.h"
+#include  "Monitor.h"
+
+// ----------------------------------------------------------------------------
+// Vorwärtsreferenzen
+// ----------------------------------------------------------------------------
+//
+void ctrlIdle();
+void ctrlInit();
+void sendCtrl();
+void checkCtrl();
+
+void apInit();
+void apWaitDE();
+void apWaitMeas();
+void apProcMeas();
+
+
+#ifdef DebugTerminal
+// ----------------------
+void smInit() ;
+void smCheckJobs() ;
+void smDebDword() ;
+void smCtrlPolling() ;
+void smWaitPolling() ;
+void smReadPollValues() ;
+void smCheckSer();
+// ----------------------
+#endif
+
+#endif /* SoaapBleMaster_h */
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/SoaapBleSlave.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/SoaapBleSlave.h
new file mode 100644
index 0000000000000000000000000000000000000000..f3ae7f7500126e35f19524b4188a3044d43dfaf4
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/SoaapBleSlave.h
@@ -0,0 +1,43 @@
+#ifndef SoaapBleSlave_h
+#define SoaapBleSlave_h
+
+#include  "LoopCheck.h"
+#include  "StateMachine.h"
+#include  "nRF52840Radio.h"
+#include  "BlePoll.h"
+#include  "ComRingBuf.h"
+#include  "nRF52840Ser.h"
+#include  "SoaapMsg.h"
+#include  "Monitor.h"
+#include "nRF52840Twi.h"
+#include "SensorLSM9DS1.h"
+#include "nRF52840Gpio.h"
+
+//#define SlaveACM1
+bool sendData(PlpType plpType, byte *dest);
+bool getValues(PlpType plpType, byte *dest);
+void smInit();
+void smCheckJobs();
+void smCheckSens();
+
+void smDebDword();
+void smCtrlPolling();
+void smWaitPolling();
+void smSensReset1();
+void smSensReset2();
+
+void smSensGetValues1();
+void smSensGetValues2();
+void smSensGetValues3();
+void smSensGetValues4();
+void smSensGetValues5();
+void smSensGetValues6();
+void smSensGetValues7();
+
+void smSensGetSoaapValues();
+void smSensDebugValues();
+
+void smSensGetErrors();
+void smSensGetTimeOuts();
+void smSensGetRunCounts();
+#endif
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/arduinoDefs.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/arduinoDefs.h
new file mode 100644
index 0000000000000000000000000000000000000000..4830c5d860683336800903c177b10c53fcb73736
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/arduinoDefs.h
@@ -0,0 +1,53 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Definitions instead Arduino
+// Datei:   arduinoDefs.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+// These definitions shall encapsulate the Arduino environment
+// The file should be included instead of Arduino.h for arbitrary environments
+//
+
+#ifndef _arduinoDefs_h
+#define _arduinoDefs_h
+
+// ---------------------------------------------------------------------------
+// Simple type definitions and settings
+// ---------------------------------------------------------------------------
+//
+#undef  byte
+#undef  word
+#undef  dword
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned long
+
+#ifdef smnLinGcc64
+
+#undef  byte
+#undef  word
+#undef  dword
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned int
+
+#endif
+
+// ---------------------------------------------------------------------------
+// Complex type definitions
+// ---------------------------------------------------------------------------
+// The following types are more complex definitions with Arduino.
+// But here simple types are used if possible, because we only care for the
+// environment that is needed by Social Manufacturing Network
+//
+
+#ifndef IPAddress
+  #define IPAddress   byte *
+#endif
+
+
+#endif  // _arduinoDefs_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/bleSpec.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/bleSpec.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4993a39fee05fa5162fc888acf0804e5fc59254
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/bleSpec.h
@@ -0,0 +1,86 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   bleSpec.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   8. Mai 2021
+//
+// Der Inhalt dieser Datei ist der Blootooth Spezifikation 5.2 entnommen
+// bzw. daran angelehnt.
+// Insbesondere dem Teil 6, Low Energy Controller
+//
+
+#ifndef bleSpec_h
+#define bleSpec_h
+// ----------------------------------------------------------------------------
+
+#ifndef octet
+typedef unsigned char octet;
+#endif
+
+#define VersionBTS  52
+#define TypeBTS     BLE
+
+// ----------------------------------------------------------------------------
+// Festlegungen für die Bewerbungskanäle (Advertizing Physical Channels)
+// ----------------------------------------------------------------------------
+
+// Basisfrequenz in MHz
+#define BaseFrequency   2400
+
+// Zugriffsadresse (Access Address)
+#define AdvAccAddr  0x8E89BED6
+
+// CRC-Polynom
+#define PolynomCRC  0x0100065B
+
+// CRC-Startwert
+#define AdvStartCRC 0x555555
+
+// Geräteadresse
+typedef octet  BD_ADR[6];
+
+// Telegrammtypen (PDU Types)
+#define ADV_IND           0x0
+#define ADV_DIRECT_IND    0x1
+#define ADV_NONCONN_IND   0x2
+#define SCAN_REQ          0x3
+#define SCAN_RSP          0x4
+#define CONNECT_IND       0x5
+#define ADV_SCAN_IND      0x6
+
+// Kennzeichnung Art der Geräteadresse (Device Address Mark, TxAdd = 1, random)
+#define DevAdrType  0x2
+
+// Telegrammkopf ohne Längenbyte
+#define HeadS0B     ((ADV_NONCONN_IND << 4) | DevAdrType)
+#define HeadS0BS    ((ADV_SCAN_IND << 4) | DevAdrType)
+
+// Datenstruktur für das zu sendende Telegramm
+// bei der Bewerbung (Advertising)
+//
+typedef struct _bcPdu         // Beacon - PDU
+{
+  byte  head;       // Header = PDU-Typ und Adresskennung (S0 bei nRF52840)
+  byte  len;        // Länge des Telegramms inkl. Adresse (LENGTH bei nRF52840)
+  byte  adr0;       // niedrigstwertiges Adressbyte (S1 bei nRF52840)
+  byte  adr1;       //
+  byte  adr2;       //      Das ist die Geräteadresse, die hier wahlfrei ist
+  byte  adr3;       //      Sie wird zur Identifikation des Gerätes verwendet
+  byte  adr4;       //
+  byte  adr5;       // höchstwertiges Addressbyte
+  byte  data[31];   // Nutzdaten (maximale Anzahl nach BLE-Spez.)
+} bcPdu, *bcPduPtr;
+
+// Telegrammtypen
+//
+typedef enum  _blePduType
+{
+  bptAdv,           // Standard-Bewerbungstelegramm
+  bptAux
+} blePduType;
+
+// ----------------------------------------------------------------------------
+#endif  // bleSpec_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/environment.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/environment.h
new file mode 100644
index 0000000000000000000000000000000000000000..311c3331bd39a97884ba12b85375b08a418813d0
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/environment.h
@@ -0,0 +1,126 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   environment.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef _environment_h
+#define _environment_h
+
+#ifdef  smnDEFBYBUILD
+
+// Alternative Festlegungen durch Settings in der Build-Umgebung der IDE
+// Das erspart die Verwaltung mehrerer/unterschiedlicher environment.h Dateien
+// in den Projekten
+//
+  #ifdef smnUBUNTU_ECLIPSE
+  // Meine Entwicklungs- und Testumgebung auf dem Notebook unter UBUNTU
+  // für Sketche, die auf dem PC laufen (u.a. zum Debuggen)
+
+    #define smnSimLinux
+    #define smnNotebook
+    #define smnLINUX
+    #define smnDebugLinuxConsole
+
+  #endif
+
+  #ifdef smnWIN32_VS
+  // Meine Entwicklungs- und Testumgebung auf dem Notebook unter Windows
+  // für Sketche, die auf dem PC laufen (u.a. zum Debuggen)
+
+    #define smnSimWindows
+    #define smnNotebook
+    #define smnWIN32
+    #define smnDebugWindowsConsole
+
+  #endif
+
+  #ifdef smnSLOELIN
+  // Mit Sloeber auf Ubuntu/Linux für Entwicklungen zum ESP32
+  //
+
+    #define smnDebugArduino
+    #define smnSloeber
+    #define smnESP32_DEV
+    #define smnESP32
+    #define smnSerial Serial
+  #endif
+
+  #ifdef smnSLOEDUE
+  // Mit Sloeber auf Ubuntu/Linux für Entwicklungen zum Arduino Due
+  //
+
+    #define smnDebugArduino
+    #define smnSloeber
+    #define smnArduinoDUE
+    #define smnArduinoShieldEth
+    #define smnSAM3X
+    #define smnSerial Serial
+  #endif
+
+  #ifdef smnNANOBLE33
+    #define smnDebugArduino
+    #define smnSloeber
+    #define smnArduinoNanoBLE33
+    #define smnNRF52840
+    #define smnSerial Serial
+  #endif
+
+  #ifdef smnSLOESAMD21
+    #define smnDebugArduino
+    #define smnSloeber
+    #define smnArduinoZeroSamD21
+    #define smnSAMD21G18
+    #define smnSD21MINI
+    #define smnSerial SerialUSB
+  #endif
+
+#else
+
+// Die Definitionen werden hier in den meisten Fällen grundsetzlich ausgewertet,
+// nicht über spezifische Werte.
+// Die Abfrage geschieht also mit #ifdef
+// Daraus folgt hier eine Liste der Möglichkeiten, die beliebig erweitert werden kann.
+// Die Auswahl erfolgt schließlich über aus- bzw. einkommentieren.
+//
+
+// Übergeordnete Festlegungen
+// ---------------------------------------------------------------------------
+//
+#define smnDebugArduino
+//#define smnDebugLinuxConsole
+//
+
+// IDE, Editor, etc.
+// ---------------------------------------------------------------------------
+//
+//#define smnSimLinux
+#define smnSloeber
+//#define smnArduinoIDE
+//#define smnPlatformIO
+
+// Hardware, Boards, etc.
+// ---------------------------------------------------------------------------
+//
+//#define smnNotebook
+//#define smnESP32_DEV
+#define smnNodeMCU10
+//#define smnArduinoDUE
+//#define smnArduinoShieldEth
+//#define smnArduinoShieldWiFi
+#define smnSerial Serial
+
+// Prozessoren, Microcontroller, Betriebssysteme, etc.
+// ---------------------------------------------------------------------------
+//
+//#define smnLINUX
+//#define smnESP32
+#define smnESP8266
+//#define smnSAM3X
+
+#endif  // smnDEFBYBUILD
+
+#endif  // _environment_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..9e3641f6fb0e38c5e74b3c3cee96651efbb2fdaa
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "environment",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/socManNetUser.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/socManNetUser.h
new file mode 100644
index 0000000000000000000000000000000000000000..4809a3b98de3da0b84f1f25ba7cda8af91bb2672
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/environment/socManNetUser.h
@@ -0,0 +1,315 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Broadcast Socket Interface
+// Datei:   socManNetUser.h
+// Editor:  Igor Farber, Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef _socManNetUser_h
+#define _socManNetUser_h
+
+#define smnMULTIBOARDS
+
+#define smnBOARD001
+//#define smnBOARD002
+//#define smnBOARD003
+//#define smnBOARD004
+//#define smnBOARD005
+//#define smnBOARD006
+
+
+
+#ifndef smnMyNet
+// ***************************************************************************
+// define smnMyNet in project properties (Arduino) with -DsmnMyNet
+// to use your own network definition file included at the end of this file
+
+
+//---------------------------------------------------------------------------//
+//-------------------------------------------------------------------------
+// MAC-Adresse des Ethernet-Shield
+//-------------------------------------------------------------------------
+#ifdef  smnMULTIBOARDS
+
+  #ifdef  smnBOARD001
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x1b
+    #define LOCAL_MAC_ADR_B5 0x84
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-1b-84"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD002
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x63
+    #define LOCAL_MAC_ADR_B5 0xb0
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-63-b0"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD003
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x5b
+    #define LOCAL_MAC_ADR_B5 0xe1
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-5b-e1"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD004
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x5b
+    #define LOCAL_MAC_ADR_B5 0x8f
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-62-d0"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD005
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x62
+    #define LOCAL_MAC_ADR_B5 0xd0
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-62-d0"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD006
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x62
+    #define LOCAL_MAC_ADR_B5 0xd0
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-62-d0"
+    // MAC-Adresse als String
+  #endif
+
+#else
+  #define LOCAL_MAC_ADR_B0 0x90
+  #define LOCAL_MAC_ADR_B1 0xa2
+  #define LOCAL_MAC_ADR_B2 0xda
+  #define LOCAL_MAC_ADR_B3 0x0f
+  #define LOCAL_MAC_ADR_B4 0x62
+  #define LOCAL_MAC_ADR_B5 0xd0
+  // MAC-Adresse
+
+  #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-62-d0"
+  // MAC-Adresse als String
+#endif
+
+#define LOCAL_PORT      4100
+// Portnummer lokal
+
+#define BROADCAST_PORT  4100
+// Portnummer Rundruf
+
+#define CONFIG_PORT     4001
+
+//-------------------------------------------------------------------------
+// Sub-Netz-Maske
+//-------------------------------------------------------------------------
+#define SUB_NET_MASK_B0 255
+#define SUB_NET_MASK_B1 255
+#define SUB_NET_MASK_B2 255
+#define SUB_NET_MASK_B3 0
+
+//----------------------------------------------------------------------------
+// IP-Adresse, ist auf das verwendete Netzwerk anzupassen (kein DHCP)
+//----------------------------------------------------------------------------
+
+// Das Netzwerk an sich
+#define LOCAL_IP_B0 192
+#define LOCAL_IP_B1 168
+#define LOCAL_IP_B2 99
+
+#define BROADCAST_IP_B0 192
+#define BROADCAST_IP_B1 168
+#define BROADCAST_IP_B2 99
+#define BROADCAST_IP_B3 255
+
+#ifdef smnMULTIBOARDS
+
+  #ifdef smnBOARD001
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 201
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.201"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD002
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 202
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.202"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD003
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 203
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.203"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD004
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 204
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.204"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD005
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 205
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.205"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD006
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 206
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.205"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+#else
+
+  // IP-Lokal
+  // ----------------------------------------------
+  //
+  #define LOCAL_IP_B3 205
+  #define LOCAL_IP_ADR_STR (char *) "192.168.99.205"
+
+  // IP-Broadcast
+  // ----------------------------------------------
+  //
+  #define BROADCAST_IP_B3 255
+  #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+#endif
+
+// IP-Gateway
+// ----------------------------------------------
+//
+#define GATEWAY_IP_B0 192
+#define GATEWAY_IP_B1 168
+#define GATEWAY_IP_B2 99
+#define GATEWAY_IP_B3 1
+
+
+/******************************************************************************
+ * Netzwerkname
+ * Passwort
+ */
+#define SMNSSID "MPZ-Labor"    //Netzwerk Name
+#define SMNPASS "MPZMPZMPZ"    //Netzwerk Passwort
+
+// IP-primaryDNS
+// ----------------------------------------------
+//
+#define PRIMDNS_IP_B0   8
+#define PRIMDNS_IP_B1   8
+#define PRIMDNS_IP_B2   8
+#define PRIMDNS_IP_B3   8
+
+// IP-secondaryDNS
+// ----------------------------------------------
+//
+#define SECDNS_IP_B0    8
+#define SECDNS_IP_B1    8
+#define SECDNS_IP_B2    4
+#define SECDNS_IP_B3    4
+
+#else
+// ***************************************************************************
+  #undef _socManNetUser_h
+  #include MyNetFile
+  // Define MyNetFile in Project-Properties with -DMyNetFile=\"xxxxx\"
+  // and xxxxx being your filename.
+  // Define also smnMyNet with -DsmnMyNet to enter this include directive
+
+#endif // smnMyNet
+// ***************************************************************************
+
+//---------------------------------------------------------------------------//
+#endif // _socManNetUser_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/main.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cc5c3622d1c730e194ae97c530e1f11bfdb2d4a1
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/main.cpp
@@ -0,0 +1,688 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleMaster.ino
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                        P o l l i n g - M a s t e r
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. November 2021
+// Letzte Bearbeitung: 4. Februar 2022
+//
+
+#include  "Arduino.h"
+#include  "SoaapBleMaster.h"
+
+// ----------------------------------------------------------------------------
+LoopCheck     lc;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse LoopCheck
+// Darüber wird das Zeitverhalten gesteuert (Software-Timer) und geprüft
+
+// ----------------------------------------------------------------------------
+nRF52840Radio bleCom;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse nRF52840Radio
+// Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und
+// Empfangen von BLE-Beacons angesprochen.
+
+
+#define bleCycleTime 250
+// ----------------------------------------------------------------------------
+BlePoll       blePoll((IntrfRadio *) &bleCom, micros);
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse BlePoll
+// Darüber werden das Polling des Masters als auch die Antworten der Slaves
+// gesteuert. Es können Geräte entwickelt werden, die nur Master oder Slave
+// sind und solche mit Doppelfunktion, wenn kein expliziter Master
+// eingesetzt und das Netzwerk über Spontan-Master quasi dezentral
+// betrieben werden soll.
+// ----- Parameter ------------------------------------------------------------
+// <&bleCom>    Die Klasse (vom angenommenen Typ IntrfRadio), die die Daten-
+//              übertragung abwickelt. Hier wird eine Instanz von nRF52840Radio
+//              angebunden. Für andere Hardware kann eine entsprechende Klasse
+//              verwendet werden, die von IntrfRadio abgeleitet wurde.
+// <micros>     Eine Funktion, die die verstrichene Zeit in Mikrosekunden gibt.
+//              Damit werden Zeiten (z.B. Time-Out) berechnet.
+//              Wird hier der Wert NULL übergeben, dann werden die Zeiten aus
+//              dem Aufrufzyklus (bleCycleTime) in Mikrosekunden berechnet,
+//              was hier einer Auflösung von 250 Mikrosekunden entspricht.
+
+#define NrOfSlavesToPoll  5
+// Die Anzahl der Slaves, die der Master aufrufen soll (Polling).
+// Es wird grundsätzlich mit der Adresse 1 begonnen und nach dem Aufruf die
+// Adresse inkrementiert, also immer die Slaves Adr = 1 bis
+// Adr = NrOfSlavesToPoll+1 aufgerufen.
+// ACHTUNG!
+// Diese Zahl muss kleiner/gleich der in BlePoll.h definierten maximalen
+// Anzahl der Slaves (MAXSLAVE) sein, weil die Ressourcen darüber statisch
+// festgelegt werden.
+
+SerParams     ttyParams;
+// ----------------------------------------------------------------------------
+nRF52840Ser   tty;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse nRF52840Ser (UART)
+// Darüber werden die seriellen Schnittstellen (UARTE0 und UARTE1) des
+// nRF52840 bedient.
+// Die Parameter werden in einer Struktur <SerParams> über die Funktion
+// <begin(...)> gesetzt.
+
+#define       sndBufSize  256
+byte          sndBuffer[sndBufSize];
+// ----------------------------------------------------------------------------
+ComRingBuf    crb;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse <ComRingBuf>
+// Damit wird ein Ringpuffer aufgebaut, der eine serielle Schnittstelle bedient.
+// Der Speicher muss extra eingerichtet und mit der Funktion
+//  <setWriteBuffer(sndBufSize, sndBuffer)> übergeben werden.
+// Die Klasse für die serielle Schnittstelle muss von <IntrfSerial> abgeleitet
+// sein, die Instanz wird mit der Funktion <begin(...)> übergeben.
+
+#define appCycleTime 500
+StateMachine  ap(apInit, NULL, appCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für die
+// Anwendung (App) von SOAAP eingesetzt wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Mikrosekunden
+
+
+// ----------------------------------------------------------------------------
+SoaapMsg  sMsg;
+// ----------------------------------------------------------------------------
+// Eine statische Instanz der Klasse <SoaapMsg>
+// Damit werden SOAAP-spezifische Meldungen/Telegramme generiert und ausgewertet
+// und SOAAP-spezifische Datentypen und Parameter definiert.
+
+#ifdef DebugTerminal
+// ----------------------------------------------------------------------------
+// Zum Debuggen und weitere Analysen der Programmumgebung und Funktionstests
+// Es ist ein (richtiges) Terminal erforderlich, mit dem einzelnen Zeichen
+// direkt abgeschickt und die eintreffenden direkt angezeigt werden.
+// ----------------------------------------------------------------------------
+#define smCycleTime 5
+StateMachine  sm(smInit, NULL, smCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für allgemeine
+// Steuerungen, Überwachungen und zum Debugging verwendet wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Millisekunden
+
+Monitor       mon(modeEcho | modeNl,0,&lc);
+// Eine statische Instanz (mit Konstruktordaten) der Klasse Monitor
+// Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert
+// Unter Linux werden hier GtkTerm (siehe Internet) und
+// ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt.
+// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeigent,
+// weil damit keine direkte Kommunikation (getipptes Zeichen sofort gesendet)
+// möglich ist.
+// ----- Parameter ------------------------------------------------------------
+// <mode Echo>  Alle eintreffenden Zeichen werden sofort zurückgesendet
+// <mode NL>    Vor der Ausgabe des Prompt (M>) erfolgt CR/LF
+// <0>          Für Speicherzugriffe wird von 32 Bit ARM ausgegangen
+// <&lc>        Für Zeitüberwachungen und entsprechende statisctische Daten
+//              greift die Monitor-Klasse auf die LoopCheck-Klasse zu
+// ----------------------------------------------------------------------------
+#endif
+
+
+// ============================================================================
+void setup()
+// ============================================================================
+{
+  bleCom.begin();           // Initialisierung der Datenübertragung
+  //bleCom.setPower(0x08);     // Maximale Sendeleistung bei nRF52840
+  // TEST
+  bleCom.setPower(0x0FC);   // Reduzierte Sendeleistung beim Schreibtisch-Test
+
+  blePoll.begin(BlePoll::ctMASTER, NrOfSlavesToPoll, BlePoll::atDevSOAAP, 10000);
+  // Initialisierung des Polling mit folgenden Parametern:
+  // <BlePoll::ctMASTER>    Es wird ein Master eingerichtet
+  // <NrOfSlavesToPoll>     Anzahl gepollter Slaves (s.o.)
+  // <BlePoll::atSOAAP>     Spezielle Anwendung SOAAP
+  // <10000>                INT-Watchdog-Timeout beim Lesen in Mikrosekunden
+
+  blePoll.setEmptyPollParams(2000, 500, 2000);
+  // Setzen der Parameter für das leere Polling zur Feststellung der
+  // vorhandenen Slaves und Aufbau einer Poll-Liste für den Datenaustausch
+  // ----- Parameter ----------------------------------------------------------
+  // <2000>   Anzahl der Poll-Durchläufe, solange kein Slave gefunden wird
+  // <500>    Anzahl weiterer Durchläufe, nachdem wenigstens ein Slave gefunden ist
+  // <2000>   Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden
+
+  for(int i = 1; i <= NrOfSlavesToPoll; i++)
+    blePoll.setDataPollParams(i, 1, 10, 1000);
+  // Setzen der Parameter beim Datenpolling, für Slaves individuell
+  // ----- Parameter ----------------------------------------------------------
+  // <i>      Adresse des Slave (1-..)
+  // <1>      Priorität beim Aufruf, 0 = immer bis max 65535 = sehr selten
+  // <10>     minimale Priorität bei automatischer Prioritätsreduzierung
+  //          im Fall von Störungen (Time-Out)
+  // <1000>   Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden
+
+#ifdef DebugTerminal
+  blePoll.stopEP();   // Das Polling muss extra gestartet werden
+#endif
+
+  // Initialisierung von serieller Schnittstelle und Ringpuffer
+  // --------------------------------------------------------------------------
+  ttyParams.inst    = 0;    // Instanzindex der Schnittstelle (0,1)
+  ttyParams.rxdPort = 1;    // Nummer des IO-Port mit RxD-Pin
+  ttyParams.rxdPin  = 10;   // Nummer des RxD-Pin am Port
+  ttyParams.txdPort = 1;    // Nummer des IO-Port mit TxD-Pin
+  ttyParams.txdPin  = 3;    // Nummer des TxD-Pin am Port
+  ttyParams.speed   = Baud115200;   // Enumerator für Bitrate
+  ttyParams.type    = stStd;        // Spannungsausgang
+
+  tty.begin(&ttyParams, (IntrfBuf *) &crb);
+  // Übergeben von Parametern und Referenz auf Ringpufferverwaltung
+  // für die Übergabe empfangener Zeichen
+
+  tty.startSend();    // Sendebetrieb aktivieren
+
+  crb.setWriteBuffer(sndBufSize, sndBuffer);
+  // Speicher an Ringpufferverwaltung übergeben
+
+  crb.begin((IntrfSerial *) &tty);
+  // Referenz auf Schnittstelle an Ringpufferverwaltung
+  // für die Übergabe zu sendender Zeichen
+}
+
+// ============================================================================
+void loop()
+// ============================================================================
+{
+  lc.begin();     // Muss am Anfang von LOOP aufgerufen werden
+  // --------------------------------------------------------------------------
+
+#ifdef DebugTerminal
+  mon.run();      // Der Monitor bekommt bei jedem Durchlauf die CPU
+#endif
+
+  // Alle 250 Mikrosekunden erfolgt der Aufruf des Ble-Polling
+  //
+  if(lc.timerMicro(lcTimer0, bleCycleTime, 0))
+    blePoll.run();
+  // ----- Parameter der Software-Timer ---------------------------------------
+  // <lcTimer0>   Id/Nummer des Timer, zur Zeit werden bis 10 Timer unterstützt
+  //              lcTimer0 bis lcTimer9 (einstellbar in LoopCheck.h)
+  // <bleCycleTime>   Ablaufzeit in Einheit des Timer-Typ (Micro/Milli)
+  //                  hier in Mikrosekunden (timerMicro)
+  // <0>          Anzahl der Wiederholungen, 0 = unbegrenzt
+
+  // Alle 500 Mikrosekunden erfolgt der Aufruf der Anwendung
+  //
+  if(lc.timerMicro(lcTimer1, appCycleTime, 0, 10000))
+    ap.run();
+
+
+#ifdef DebugTerminal
+  // Jede Sekunde erfolgt die Ausgabe einer Versionsmeldung
+  // das kann über c0 am Terminal abgeschaltet werden
+  //
+  if(lc.timerMilli(lcTimer2, 1000, 0))
+  {
+    if(!mon.cFlag[0])
+      mon.printcr((char *)"%@TestBleMaster (ttyACM0), Version 20220303");
+      smWaitPolling();
+  }
+  // Die Zeichen %@ am Anfang steuern die Ausgabe bei AndroidMonTerm in ein
+  // Textfeld (Label) statt auf das Terminal-Display
+
+  // Alle 5 Millisekunden erfolgt der Aufruf der Zustandsmaschine
+  //
+  if(lc.timerMilli(lcTimer3, smCycleTime, 0))
+  {
+    sm.run();
+  }
+#endif
+
+  // --------------------------------------------------------------------------
+  lc.end();       // Muss vor dem Ende von LOOP aufgerufen werden
+}
+
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e   S O A A P - A n w e n d u n g  (ap)
+// ****************************************************************************
+//
+byte  apTmpByteArray[256];              // Zwischenspeicher für Zeichenfolgen
+int   apNrOfMeasBytes;                  // Anzahl der empfangenen Messwertbytes
+int   apNrOfCtrlBytes;                  // Anzahl der empfangenen Steuerbytes inkl count und path
+byte  apMeasByteArray[32];              // Zwischenspeicher für Messwerte
+byte  apCtrlByteArray[32];              // Zwischenspeicher für Steuerbytes
+byte  apSlaveList[NrOfSlavesToPoll];    // Merker für gepollte Slaves
+int   apNrOfSlaves;                     // Aktuelle Anzahl von Slaves
+int   curListIdx;                       // Aktueller Index für Slaveliste
+int   area;                             // Area des aktuellen Slave
+int   sMsgLen;                          // Länge einer SOAAP-Meldung
+int   slNr;                             // Slave-Nummer (Adresse)
+int   txNr;                             // Anzahl versendeter Zeichen
+
+SoaapApId sAppId;                       // Anwendungs-Id aus Sicht SOAAP
+PlpType   pAppId;                       // Anwendungs-Id aus Polling-Sicht
+
+#ifdef TEST001
+char testMsgBuf[256];
+#endif
+// ----------------------------------------------------------------------------
+// Initialisierungen
+//
+void apInit()
+{
+#ifdef TEST001
+  crb.putLine("Initialisierung");
+#endif
+
+  // Eventuelle Initialisierung
+  ap.enter(apWaitDE);     // in nächsten Zustand schalten
+}
+
+// ----------------------------------------------------------------------------
+// Warten, bis Datenaustausch Master/Slave erfolgt
+//
+void apWaitDE()
+{
+  if(!blePoll.DataExchange)
+    return;   // Verbleiben in diesem Zustand bis Leerpolling beendet
+
+  apNrOfSlaves = blePoll.getSlaveList(apSlaveList, NrOfSlavesToPoll);
+  // Ermitteln der angeschlossenen Slaves
+
+#ifdef TEST001
+  crb.putStr("Slaveliste\r\n");
+#endif
+
+  ap.enter(apWaitMeas);
+}
+
+// ----------------------------------------------------------------------------
+// Warten auf neuen Messwert von einem Slave
+//
+void apWaitMeas()
+{
+  // Ermitteln, ob einer der Slaves einen Messwert hat
+  //
+  for(curListIdx = 0; curListIdx < apNrOfSlaves; curListIdx++)
+  {
+    slNr = apSlaveList[curListIdx];
+    if(blePoll.measAvail(slNr)) break;
+  }
+  if(curListIdx == apNrOfSlaves) return;
+  // Wenn kein Slave neue Messwerte hat,
+  // dann im nächsten Zustandstakt Abfrage wiederholen
+
+#ifdef TEST001
+  crb.putStr("Messwerte\r\n");
+#endif
+
+  // Slave (curListIdx) hat Messwerte übermittelt
+  // diese werden mit dem nächsten Takt verarbeitet
+  ap.enter(apProcMeas);
+}
+
+// ----------------------------------------------------------------------------
+// Verarbeiten der Daten vom Slave
+//
+void apProcMeas()
+{
+#ifdef TEST001
+  if(ap.firstEnter())
+  {
+    slNr = apSlaveList[curListIdx];
+    sprintf(testMsgBuf,"Slave-Nr = %d\r\n",slNr);
+    crb.putStr(testMsgBuf);
+  }
+  //ap.enter(apWaitMeas);
+  //return;
+#endif
+
+  // Parameter und Daten für die SOAAP-Meldung holen
+  //
+  slNr = apSlaveList[curListIdx];
+  area = blePoll.getArea(slNr);
+  pAppId = blePoll.getAppId(slNr);
+  apNrOfMeasBytes = blePoll.getMeas(slNr, apMeasByteArray);
+  apNrOfCtrlBytes = blePoll.getCtrlM(slNr, apCtrlByteArray);
+
+#ifdef TEST001
+  ap.enter(apWaitMeas);
+  return;
+#endif
+
+  // Abbildung des Polling-Telegramm-Typs auf die SOAAP-Anwendungs-Id
+  //
+  switch(pAppId)
+  {
+    case plptMeas9:
+      sAppId = saiDefaultMeas;
+      break;
+
+    case plptMeas13:
+      sAppId = saiMaximalMeas;
+      break;
+
+    case plptMeas9Ctrl4:
+      sAppId = saiDefaultMeasCtrl;
+      break;
+
+    default:
+      sAppId = saiDefaultMeas;
+      break;
+  }
+
+  // Konstruktion der SOAAP-Meldung
+  //
+  sMsgLen = sMsg.getMsgA(area, slNr, sAppId, (char *) apTmpByteArray, apMeasByteArray);
+
+  // Senden des Telegramm über serielle Schnittstelle
+  //
+  txNr = crb.putStr((char *) apTmpByteArray);
+
+  // Auf nächsten Messwert von einem Slave warten
+  //
+  ap.enter(apWaitMeas);
+}
+
+
+
+#ifdef DebugTerminal
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e   z u m   D e b u g g e n   (sm)
+// ****************************************************************************
+//
+dword   debDword;
+byte    tmpByteArray[256];
+
+
+void smInit()
+{
+  sm.enter(smCheckJobs);
+}
+
+// ----------------------------------------------------------------------------
+// Abfrage der Monitorschalter
+// ----------------------------------------------------------------------------
+//
+
+void smCheckJobs()
+{
+  if(mon.cFlag[1] && !mon.busy)
+    sm.enter(smDebDword);
+  else if(mon.cFlag[2] && !mon.busy)
+    sm.enter(smCtrlPolling);
+  else if(mon.cFlag[3] && !mon.busy)
+    sm.enter(smReadPollValues);
+  else if(mon.cFlag[4] && !mon.busy)
+    sm.enter(smCheckSer);
+}
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+void smDebDword()
+{
+  int idx;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "DebDword[");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn >= 0x30 && mon.lastKeyIn <= 0x39)
+  {
+    idx = mon.lastKeyIn & 0x0F;
+    mon.print(idx);
+    mon.print((char *) "]=");
+    debDword = blePoll.debGetDword(idx);
+    mon.println(debDword);
+    sm.resetEnter();
+  }
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[1] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Steuern des Polling-Prozesses
+// ----------------------------------------------------------------------------
+//
+
+TxStatistics txStatistics;
+
+void smCtrlPolling()
+{
+  dword   tmpDw;
+  short   tmpShort;
+  int     i;
+
+  PlpMeas6Ptr resPtr;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "polling ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  // --------------------------------------------------------------------------
+  if(mon.lastKeyIn == 'P' || mon.lastKeyIn == 'p')
+  {
+    if(blePoll.stoppedEP())
+    {
+      blePoll.resumeEP();
+      mon.println((char *) "fortgesetzt");
+      sm.resetEnter();
+    }
+    else
+    {
+    blePoll.stopEP();
+    sm.enter(smWaitPolling);
+    }
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'C' || mon.lastKeyIn == 'c')
+  {
+    blePoll.resetPollCounters();
+    mon.println((char *) "Zähler zurückgesetzt");
+    sm.resetEnter();
+  }
+
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'R' || mon.lastKeyIn == 'r')
+  {
+    mon.print((char *) "Radiopuffer = ");
+    bleCom.getPduMem(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'S' || mon.lastKeyIn == 's')
+  {
+    mon.print((char *) "Sendepuffer = ");
+    bleCom.getPduSent(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+    // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'K' || mon.lastKeyIn == 'k')
+  {
+    mon.print(slNr); mon.print((char *)"|");
+    for(int i= 0; i< apNrOfCtrlBytes; i++){
+      mon.print(apCtrlByteArray[i]);
+      mon.print((char *)" ");
+    }
+    mon.print((char *) "\n");
+    sm.resetEnter();
+  }
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'L' || mon.lastKeyIn == 'l')
+  {
+    mon.print((char *) "Slave-Liste: ");
+    int nrOfSlaves = blePoll.getSlaveList(tmpByteArray, 255);
+    mon.println(tmpByteArray, nrOfSlaves, ',');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'T' || mon.lastKeyIn == 't')
+  {
+    mon.print((char *) "TxStat [");
+    dword bleStat = blePoll.getStatistics(&txStatistics);
+    mon.print(bleStat);
+    mon.print((char *) "] ");
+    mon.print(txStatistics.mode); mon.cprint(' ');
+    mon.print(txStatistics.interrupts); mon.cprint(' ');
+    mon.print(txStatistics.recs); mon.cprint(' ');
+    mon.print(txStatistics.sendings); mon.cprint(' ');
+    mon.print(txStatistics.aliens); mon.cprint(' ');
+    mon.print(txStatistics.wrongs); mon.cprint(' ');
+    mon.print(txStatistics.pollAcks); mon.cprint(' ');
+    mon.print(txStatistics.pollNaks); mon.cprint(' ');
+    mon.print(txStatistics.crcErrors); mon.print("  s[ ");
+    mon.print(txStatistics.memDumpSnd,8,' '); mon.print("]  r[ ");
+    mon.print(txStatistics.memDumpRec,16,' '); mon.cprintln(']');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn >= '0' && mon.lastKeyIn <= '9')
+  {
+    int idx = mon.lastKeyIn & 0x0F;
+    SlavePtr slPtr = blePoll.getSlavePtr(idx);
+    PollStatePtr pPtr = blePoll.getPollPtr(slPtr->pIdx);
+
+    mon.print((char *) "Slave[");
+    mon.print(idx);
+    mon.print((char *) "] ");
+    mon.print(slPtr->cntTo); mon.cprint(' ');
+    mon.print(slPtr->cntNakEP); mon.cprint(' ');
+    mon.print(slPtr->cntAckDP); mon.cprint(' ');
+
+    if(slPtr->cntAckDP == 0)
+    {
+      if(slPtr->cntTo == 0)
+        tmpDw = slPtr->cntNakEP;
+      else
+        tmpDw = slPtr->cntNakEP / slPtr->cntTo;
+    }
+    else
+    {
+      if(slPtr->cntTo == 0)
+        tmpDw = slPtr->cntAckDP;
+      else
+        tmpDw = slPtr->cntAckDP / slPtr->cntTo;
+    }
+    mon.print(tmpDw); mon.cprint(' ');
+
+    resPtr = (PlpMeas6Ptr) &slPtr->result;
+
+    mon.print(slPtr->cntLostPdu); mon.cprint('|');
+    mon.print(slPtr->cntErrCrc); mon.cprint('|');
+    //mon.print(slPtr->result.measCnt); mon.cprint('|');
+    mon.print(resPtr->measCnt); mon.cprint('|');
+    mon.print(slPtr->cntLostMeas); mon.cprint(' ');
+
+    for(i = 0; i < 6; i++)
+    {
+      //tmpShort = (short) slPtr->result.meas[i];
+      tmpShort = (short) resPtr->meas[i];
+            mon.prints(tmpShort); mon.cprint(' ');
+    }
+    mon.print((char *) "  Poll[");
+    mon.print(slPtr->pIdx);
+    mon.print((char *) "] ");
+    mon.print(pPtr->status); mon.cprint(' ');
+    mon.println(pPtr->slIdx);
+    sm.resetEnter();
+  }
+
+
+
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[2] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+void smWaitPolling()
+{
+  if(!blePoll.stoppedEP()) return;
+
+  mon.println((char *) "angehalten");
+  sm.enter(smCtrlPolling);
+}
+
+// ----------------------------------------------------------------------------
+// Testen der seriellen Schnittstelle
+// ----------------------------------------------------------------------------
+//
+void smCheckSer()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "TestSer...");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[4] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+  else
+  {
+    crb.putChr(mon.lastKeyIn);
+    mon.cprint(mon.lastKeyIn);
+    mon.lastKeyIn = ':';
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+void smReadPollValues()
+{
+
+}
+
+#endif // DebugTerminal
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Gpio/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Gpio/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..a099c0c6f9c5ede5584dbf9ab24da0199b348548
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Gpio/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Gpio",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Gpio/nRF52840Gpio.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Gpio/nRF52840Gpio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..47a25ddebcff11a2d9ef003cf83ddf1be250d057
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Gpio/nRF52840Gpio.cpp
@@ -0,0 +1,353 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Gpio.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   29. Juni 2021
+//
+
+#include "nRF52840Gpio.h"
+
+  // --------------------------------------------------------------------------
+  // Konstruktoren
+  // --------------------------------------------------------------------------
+  //
+  nRF52840Gpio::nRF52840Gpio()
+  {
+    gpioPtr = NULL;
+  }
+
+
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+
+dword     nRF52840Gpio::getCnfValue(unsigned int cnfBits)
+{
+  dword tmpMask = 0;
+
+  if(cnfBits & IfDrvPullUp) tmpMask |= GpioPinCnf_PULL(GpioPullUp);
+  if(cnfBits & IfDrvPullDown) tmpMask |= GpioPinCnf_PULL(GpioPullDown);
+
+  if((cnfBits & IfDrvOutput))     // Ausgang **********************************
+  {
+    tmpMask |= GpioPinCnf_DIR;
+
+    if(cnfBits & IfDrvStrongHigh)       // StrongHigh = H1
+    {
+      if(cnfBits & IfDrvOpenSource)     // OpenSource = D0
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveD0H1);
+      else if(cnfBits & IfDrvStrongLow) // StrongLow = H0
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveH0H1);
+      else
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveS0H1);
+    }
+    else if(cnfBits & IfDrvStrongLow)   // StrongLow = H0
+    {
+      if(cnfBits & IfDrvOpenDrain)      // OpenDrain = D1
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveH0D1);
+      else
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveH0S1);
+    }
+    else
+    {
+      if(cnfBits & IfDrvOpenSource)     // OpenSource = D0
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveD0S1);
+      else if(cnfBits & IfDrvOpenDrain) // OpenDrain = D1
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveS0D1);
+      else
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveS0S1);
+    }
+  }
+  else                            // Eingang **********************************
+  {
+    tmpMask &= 0xFFFFFFFC;
+  }
+
+  return(tmpMask);
+}
+
+GpioError nRF52840Gpio::config(int nrFrom, int nrTo, unsigned int cnfBits, GpioExtRefPtr refPtr)
+{
+  GpioError retv = GEnoError;
+  int       portNum;
+  int       pinNum;
+  dword     tmpMask;
+  dword     cnfValue;
+
+  tmpMask = IfDrvOpenDrain | IfDrvOpenSource;
+  if((cnfBits & tmpMask) == tmpMask) return (GEcdictPar);
+
+  tmpMask = IfDrvPullDown | IfDrvPullUp;
+  if((cnfBits & tmpMask) == tmpMask) return (GEcdictPar);
+
+  cnfValue  = getCnfValue(cnfBits);
+  tmpMask   = 0;
+
+  // Bedienen des angegebenen Bereiches
+  //
+  for(int i = nrFrom; i <= nrTo; i++)
+  {
+    portNum = (i & 0x0E0) >> 5;
+    pinNum  =  i & 0x01F;
+
+    tmpMask |= (1 << i);
+
+    if(portNum == 0)
+      gpioPtr = NrfGpioPtr0;
+    else
+      gpioPtr = NrfGpioPtr1;
+
+      gpioPtr->PIN_CNF[pinNum] = cnfValue;
+  }
+
+  refPtr->ioPtr = (dword *) gpioPtr;
+  refPtr->pins  = tmpMask;
+
+  return(retv);
+}
+
+GpioError nRF52840Gpio::config(int nr, unsigned int cnfBits, GpioExtRefPtr refPtr)
+{
+  return(config(nr,nr,cnfBits, refPtr));
+}
+
+GpioError nRF52840Gpio::config(GpioExtMask mask, unsigned int cnfBits, GpioExtRefPtr refPtr)
+{
+  GpioError retv = GEnoError;
+  dword     cnfVal;
+
+  cnfVal = IfDrvOpenDrain | IfDrvOpenSource;
+  if((cnfBits & cnfVal) == cnfVal) return (GEcdictPar);
+
+  cnfVal = IfDrvPullDown | IfDrvPullUp;
+  if((cnfBits & cnfVal) == cnfVal) return (GEcdictPar);
+
+  cnfVal = getCnfValue(cnfBits);
+
+  // Bedienen des angegebenen Bereiches
+  //
+  dword chkMask = 1;
+
+  for(int i = 0; i < 32; i++)
+  {
+    if(mask.port == 0)
+      gpioPtr = NrfGpioPtr0;
+    else
+      gpioPtr = NrfGpioPtr1;
+
+    if(mask.pins & chkMask)
+      gpioPtr->PIN_CNF[i] = cnfVal;
+
+    chkMask <<= 1;
+  }
+
+  if(refPtr != NULL)
+  {
+    refPtr->ioPtr = (dword *) gpioPtr;
+    refPtr->pins  = mask.pins;
+  }
+
+  return(retv);
+}
+
+GpioError nRF52840Gpio::configArd(ArdMask ardMask, unsigned int cnfBits)
+{
+  GpioExtMask  ioMask;
+
+  switch(ardMask)
+  {
+    case ArdA0A3:
+      ioMask.port = 0;
+      ioMask.pins = ArdA0Mask | ArdA1Mask | ArdA2Mask | ArdA3Mask;
+      break;
+
+    case ArdA4A7:
+      ioMask.port = 0;
+      ioMask.pins = ArdA4Mask | ArdA5Mask | ArdA6Mask | ArdA7Mask;
+      break;
+
+    case ArdA0A7:
+      ioMask.port = 0;
+      ioMask.pins = ArdA0Mask | ArdA1Mask | ArdA2Mask | ArdA3Mask |
+                    ArdA4Mask | ArdA5Mask | ArdA6Mask | ArdA7Mask;
+      break;
+
+    case ArdD2D5:
+      ioMask.port = 1;
+      ioMask.pins = ArdD2Mask | ArdD3Mask | ArdD4Mask | ArdD5Mask;
+      break;
+  }
+
+  return config(ioMask, cnfBits, NULL);
+}
+
+
+
+  // --------------------------------------------------------------------------
+  // Anwendungsfunktionen
+  // --------------------------------------------------------------------------
+  //
+void      nRF52840Gpio::read(GpioExtRefPtr ioRefPtr, GpioExtValPtr valPtr)
+{
+  gpioPtr = (nrfGpioPtr) ioRefPtr->ioPtr;
+  valPtr->value = gpioPtr->IN;
+}
+
+dword     nRF52840Gpio::readArd(ArdMask ardMask)
+{
+  dword   inVal;
+  dword   retVal;
+
+  retVal = 0;
+
+  switch(ardMask)
+  {
+    case ArdA0A3:
+      inVal = NrfGpioPtr0->IN;
+      if(inVal & ArdA0Mask) retVal |= 0x01;
+      if(inVal & ArdA1Mask) retVal |= 0x02;
+      if(inVal & ArdA2Mask) retVal |= 0x04;
+      if(inVal & ArdA3Mask) retVal |= 0x08;
+      break;
+
+    case ArdA4A7:
+      inVal = NrfGpioPtr0->IN;
+      if(inVal & ArdA4Mask) retVal |= 0x01;
+      if(inVal & ArdA5Mask) retVal |= 0x02;
+      if(inVal & ArdA6Mask) retVal |= 0x04;
+      if(inVal & ArdA7Mask) retVal |= 0x08;
+      break;
+
+    case ArdA0A7:
+      inVal = NrfGpioPtr0->IN;
+      if(inVal & ArdA0Mask) retVal |= 0x01;
+      if(inVal & ArdA1Mask) retVal |= 0x02;
+      if(inVal & ArdA2Mask) retVal |= 0x04;
+      if(inVal & ArdA3Mask) retVal |= 0x08;
+      if(inVal & ArdA4Mask) retVal |= 0x10;
+      if(inVal & ArdA5Mask) retVal |= 0x20;
+      if(inVal & ArdA6Mask) retVal |= 0x40;
+      if(inVal & ArdA7Mask) retVal |= 0x80;
+      break;
+
+    case ArdD2D5:
+      inVal = NrfGpioPtr1->IN;
+      if(inVal & ArdD2Mask) retVal |= 0x01;
+      if(inVal & ArdD3Mask) retVal |= 0x02;
+      if(inVal & ArdD4Mask) retVal |= 0x04;
+      if(inVal & ArdD5Mask) retVal |= 0x08;
+      break;
+  }
+
+  return(retVal);
+}
+
+
+void      nRF52840Gpio::write(GpioExtRefPtr refPtr, GpioExtValPtr valPtr)
+{
+  ((nrfGpioPtr) refPtr->ioPtr)->OUTSET = valPtr->value & refPtr->pins;
+  ((nrfGpioPtr) refPtr->ioPtr)->OUTCLR = ~valPtr->value & refPtr->pins;
+  if(refPtr->next == NULL) return;
+  ((nrfGpioPtr) refPtr->next->ioPtr)->OUTSET = valPtr->next->value & refPtr->next->pins;
+  ((nrfGpioPtr) refPtr->next->ioPtr)->OUTCLR = ~valPtr->next->value & refPtr->next->pins;
+}
+
+void      nRF52840Gpio::set(GpioExtRefPtr refPtr)
+{
+  ((nrfGpioPtr) refPtr->ioPtr)->OUTSET = refPtr->pins;
+  if(refPtr->next == NULL) return;
+  ((nrfGpioPtr) refPtr->next->ioPtr)->OUTSET = refPtr->next->pins;
+}
+
+void      nRF52840Gpio::clr(GpioExtRefPtr refPtr)
+{
+  ((nrfGpioPtr) refPtr->ioPtr)->OUTCLR = refPtr->pins;
+  if(refPtr->next == NULL) return;
+  ((nrfGpioPtr) refPtr->next->ioPtr)->OUTCLR = refPtr->next->pins;
+}
+
+
+
+void      nRF52840Gpio::writeArd(ArdMask ardMask, dword value)
+{
+  dword   set0 = 0, set1 = 0;
+  dword   clr0 = 0, clr1 = 0;
+
+  switch(ardMask)
+  {
+    case ArdA0A3:
+      if(value & 0x01) set0 |= ArdA0Mask;
+      else clr0 |= ArdA0Mask;
+      if(value & 0x02) set0 |= ArdA1Mask;
+      else clr0 |= ArdA1Mask;
+      if(value & 0x04) set0 |= ArdA2Mask;
+      else clr0 |= ArdA2Mask;
+      if(value & 0x08) set0 |= ArdA3Mask;
+      else clr0 |= ArdA3Mask;
+
+      NrfGpioPtr0->OUTSET = set0;
+      NrfGpioPtr0->OUTCLR = clr0;
+      break;
+
+    case ArdA4A7:
+      if(value & 0x01) set0 |= ArdA4Mask;
+      else clr0 |= ArdA4Mask;
+      if(value & 0x02) set0 |= ArdA5Mask;
+      else clr0 |= ArdA5Mask;
+      if(value & 0x04) set0 |= ArdA6Mask;
+      else clr0 |= ArdA6Mask;
+      if(value & 0x08) set0 |= ArdA7Mask;
+      else clr0 |= ArdA7Mask;
+
+      NrfGpioPtr0->OUTSET = set0;
+      NrfGpioPtr0->OUTCLR = clr0;
+      break;
+
+    case ArdA0A7:
+      if(value & 0x01) set0 |= ArdA0Mask;
+      else clr0 |= ArdA0Mask;
+      if(value & 0x02) set0 |= ArdA1Mask;
+      else clr0 |= ArdA1Mask;
+      if(value & 0x04) set0 |= ArdA2Mask;
+      else clr0 |= ArdA2Mask;
+      if(value & 0x08) set0 |= ArdA3Mask;
+      else clr0 |= ArdA3Mask;
+      if(value & 0x01) set0 |= ArdA4Mask;
+      else clr0 |= ArdA4Mask;
+      if(value & 0x02) set0 |= ArdA5Mask;
+      else clr0 |= ArdA5Mask;
+      if(value & 0x04) set0 |= ArdA6Mask;
+      else clr0 |= ArdA6Mask;
+      if(value & 0x08) set0 |= ArdA7Mask;
+      else clr0 |= ArdA7Mask;
+
+      NrfGpioPtr0->OUTSET = set0;
+      NrfGpioPtr0->OUTCLR = clr0;
+      break;
+
+    case ArdD2D5:
+      if(value & 0x01) set1 |= ArdD2Mask;
+      else clr1 |= ArdD2Mask;
+      if(value & 0x02) set1 |= ArdD3Mask;
+      else clr1 |= ArdD3Mask;
+      if(value & 0x04) set1 |= ArdD4Mask;
+      else clr1 |= ArdD4Mask;
+      if(value & 0x08) set1 |= ArdD5Mask;
+      else clr1 |= ArdD5Mask;
+
+      NrfGpioPtr1->OUTSET = set1;
+      NrfGpioPtr1->OUTCLR = clr1;
+      break;
+  }
+}
+
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Gpio/nRF52840Gpio.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Gpio/nRF52840Gpio.h
new file mode 100644
index 0000000000000000000000000000000000000000..addf5ad533ddfecabd2c540824238c278a117998
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Gpio/nRF52840Gpio.h
@@ -0,0 +1,181 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Gpio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   29. Juni 2021
+//
+
+#ifndef NRF52840GPIO_H
+#define NRF52840GPIO_H
+
+#include "Arduino.h"
+#include "arduinoDefs.h"
+#include "IntrfGpio.h"
+
+#ifndef nrfGpioDef
+// ----------------------------------------------------------------------------
+typedef struct _nrfGpio
+{
+  volatile  dword Reserve01;                // 000
+  volatile  dword OUT;                      // 004
+  volatile  dword OUTSET;                   // 008
+  volatile  dword OUTCLR;                   // 00C
+  volatile  dword IN;                       // 010
+  volatile  dword DIR;                      // 014
+  volatile  dword DIRSET;                   // 018
+  volatile  dword DIRCLR;                   // 01C
+  volatile  dword LATCH;                    // 020
+  volatile  dword DETECTMODE;               // 024
+  volatile  dword Reserve02[118];           // 026
+  volatile  dword PIN_CNF[32];              // 200
+} nrfGpio, *nrfGpioPtr;
+
+#define NrfGpioBase   0x50000000
+#define NrfGpioBase0  0x50000500
+#define NrfGpioPtr0   ((nrfGpioPtr) NrfGpioBase0)
+#define NrfGpioBase1  0x50000800
+#define NrfGpioPtr1   ((nrfGpioPtr) NrfGpioBase1)
+
+#define GpioPinCnf_DIR        ((dword) 0x00000001)
+
+#define GpioPinCnf_INPUT      ((dword) 0x00000001 << 1)
+
+#define GpioPinCnf_PULL(x)    ((dword) x << 2)
+#define GpioPullDown          1
+#define GpioPullUp            3
+
+#define GpioPinCnf_DRIVE(x)   ((dword) x << 8)
+#define GpioDriveS0S1         0
+#define GpioDriveH0S1         1
+#define GpioDriveS0H1         2
+#define GpioDriveH0H1         3
+#define GpioDriveD0S1         4
+#define GpioDriveD0H1         5
+#define GpioDriveS0D1         6
+#define GpioDriveH0D1         7
+
+#define GpioPinCnf_SENSE(x)   ((dword) x << 16)
+#define GpioSenseHigh         2
+#define GpioSenseLow          3
+
+#define nrfGpioDef
+// ----------------------------------------------------------------------------
+#endif
+
+#define P0(x) (x)
+#define P1(x) (32+x)
+
+#ifdef smnNANOBLE33
+// ----------------------------------------------------------------------------
+#define ArdA0Bit    4
+#define ArdA1Bit    5
+#define ArdA2Bit    30
+#define ArdA3Bit    29
+#define ArdA4Bit    31
+#define ArdA5Bit    2
+#define ArdA6Bit    28
+#define ArdA7Bit    3
+
+#define ArdA0   P0(4)
+#define ArdA1   P0(5)
+#define ArdA2   P0(30)
+#define ArdA3   P0(29)
+#define ArdA4   P0(31)
+#define ArdA5   P0(2)
+#define ArdA6   P0(28)
+#define ArdA7   P0(3)
+
+#define ArdA0Mask   (1 << 4)
+#define ArdA1Mask   (1 << 5)
+#define ArdA2Mask   (1 << 30)
+#define ArdA3Mask   (1 << 29)
+#define ArdA4Mask   (1 << 31)
+#define ArdA5Mask   (1 << 2)
+#define ArdA6Mask   (1 << 28)
+#define ArdA7Mask   (1 << 3)
+
+
+#define ArdD2       P1(11)
+#define ArdD3       P1(12)
+#define ArdD4       P1(15)
+#define ArdD5       P1(13)
+#define ArdD6       P0(14)
+#define ArdD7       P0(23)
+#define ArdD8       P1(21)
+#define ArdD9       P0(27)
+#define ArdD10      P1(2)
+#define ArdD11      P1(1)
+#define ArdD12      P1(8)
+#define ArdD13      P0(13)
+
+#define ArdD2Mask   (1 << 11)
+#define ArdD3Mask   (1 << 12)
+#define ArdD4Mask   (1 << 15)
+#define ArdD5Mask   (1 << 13)
+#define ArdD6Mask   (1 << 14)
+#define ArdD7Mask   (1 << 23)
+#define ArdD8Mask   (1 << 21)
+#define ArdD9Mask   (1 << 27)
+#define ArdD10Mask  (1 << 2)
+#define ArdD11Mask  (1 << 1)
+#define ArdD12Mask  (1 << 8)
+#define ArdD13Mask  (1 << 13)
+
+// ----------------------------------------------------------------------------
+#endif
+
+class nRF52840Gpio : IntrfGpio
+{
+private:
+  // --------------------------------------------------------------------------
+  // lokale Variablen
+  // --------------------------------------------------------------------------
+  //
+  nrfGpioPtr  gpioPtr;
+
+public:
+  // --------------------------------------------------------------------------
+  // Konstruktoren
+  // --------------------------------------------------------------------------
+  //
+  nRF52840Gpio();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  dword     getCnfValue(unsigned int cnfBits);
+  GpioError config(int nr, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  GpioError config(int nrFrom, int nrTo, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  GpioError config(GpioExtMask mask, unsigned int cnfBits, GpioExtRefPtr refPtr);
+
+  GpioError configArd(ArdMask ardMask, unsigned int cnfBits);
+
+  // --------------------------------------------------------------------------
+  // Anwendungsfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void      read(GpioExtRefPtr ioRef, GpioExtValPtr valPtr);
+  dword     readArd(ArdMask ardMask);
+
+  void      write(GpioExtRefPtr refPtr, GpioExtValPtr valPtr);
+  void      writeArd(ArdMask ardMask, dword value);
+  void      set(GpioExtRefPtr refPtr);
+  void      clr(GpioExtRefPtr refPtr);
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Debugging und globale Variablen
+  // --------------------------------------------------------------------------
+  //
+
+};
+
+#endif //NRF52840GPIO_H
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Radio/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Radio/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..a18f8f0f08e3ee567cac8bd59e8774c14b3effe7
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Radio/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Radio",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Radio/nRF52840Radio.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Radio/nRF52840Radio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5639480f98f812bc2170a24674d34534dd95d5e6
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Radio/nRF52840Radio.cpp
@@ -0,0 +1,943 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Radio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#include "Arduino.h"
+#include "nRF52840Radio.h"
+#include <string.h>
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+
+nRF52840Radio::nRF52840Radio()
+{
+  NrfRadioPtr->TASKS_DISABLE;   // Sender/Empfänger abgeschaltet
+#ifdef nrfPowerDCDCEN
+  *nrfPowerDCDCEN = 1;
+#endif
+#ifdef nrfClockTASKS_HFCLKSTART
+  *nrfClockTASKS_HFCLKSTART = 1;
+#endif
+  NrfRadioPtr->POWER = 0;
+  NrfRadioPtr->POWER = 1;
+
+  irqCounter = 0;
+  trfMode = txmBase;
+  statisticPtr = NULL;
+  recMode = true;
+  pmPtr = (bcPduPtr) pduMem;
+  psPtr = (bcPduPtr) pduSentS;
+  pePtr = (bcPduPtr) pduSentE;
+  eadM = false;
+  nakM = false;
+  comFin = false;
+  comError = false;
+  newValues = false;
+
+  memset(statList,0,NrOfTxModes * sizeof(TxStatistics));
+}
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+
+// Allgemeine Vorbereitungen
+//
+void  nRF52840Radio::begin()
+{
+  instPtr0 = this;      // Verzweigung im statischen Bereich setzen
+
+  NrfRadioPtr->INTENCLR = 0xFFFFFFFF;   // Vorsichtshalber keine Interrupts
+
+  // Interruptvektor setzen
+  //
+  __NVIC_SetVector((IRQn_Type) 1, (dword) nRF52840Radio::irqHandler0);
+  __NVIC_SetPriority((IRQn_Type) 1, 1);
+  __NVIC_EnableIRQ((IRQn_Type) 1);
+}
+
+// Setzen der Zugriffsadresse
+//
+void  nRF52840Radio::setAccessAddress(dword addr)
+{
+  dword prefix = addr >> 24;
+  dword base = addr << 8;
+
+  cfgData.base0   = NrfRadioPtr->BASE0        = base;
+  cfgData.prefix0 = NrfRadioPtr->PREFIX0      = prefix;
+  cfgData.txAddr  = NrfRadioPtr->TXADDRESS    = 0;
+  cfgData.rxAddr  = NrfRadioPtr->RXADDRESSES  = 0x01;
+}
+
+// Telegrammparameter setzen
+//
+void  nRF52840Radio::setPacketParms(blePduType type)
+{
+  switch(type)
+  {
+    case bptAdv:
+      cfgData.pCnf0     = NrfRadioPtr->PCNF0        = PCNF0_LFLEN(8) | PCNF0_S0LEN(1) | PCNF0_S1LEN(0);
+      cfgData.pCnf1     = NrfRadioPtr->PCNF1        = PCNF1_MAXLEN(42) | PCNF1_BALEN(3) | PCNF1_WHITEEN(1);
+      cfgData.modeCnf0  = NrfRadioPtr->MODECNF0     = 1;
+      cfgData.crcCnf    = NrfRadioPtr->CRCCNF       = CRCCNF_LEN(3) | CRCCNF_SKIPADDR(1);
+      cfgData.crcPoly   = NrfRadioPtr->CRCPOLY      = PolynomCRC;
+      cfgData.crcInit   = NrfRadioPtr->CRCINIT      = AdvStartCRC;
+      cfgData.packetPtr = NrfRadioPtr->PACKETPTR    = (dword) pduMem;
+      cfgData.mode      = NrfRadioPtr->MODE         = 3;
+      cfgData.dacnf     = NrfRadioPtr->DACNF        = 0x0FF00;
+      break;
+
+    case bptAux:
+      break;
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// Steuerfunktionen und gezielte Prozessorzugriffe
+// ----------------------------------------------------------------------------
+
+// Schalten des Bewerbungskanals
+//
+void nRF52840Radio::setChannel(int nr)
+{
+  cfgData.frequency = NrfRadioPtr->FREQUENCY = channelList[nr].freq;
+  cfgData.whiteInit = NrfRadioPtr->DATAWHITEIV = channelList[nr].idx;
+}
+
+// ----------------------------------------------------------------------------
+//                      S e n d e n
+// ----------------------------------------------------------------------------
+
+// Einstellen der Sendeleistung
+//
+void  nRF52840Radio::setPower(int DBm)
+{
+  cfgData.txPower = NrfRadioPtr->TXPOWER = DBm;
+}
+// Senden eines Telegramms
+// Es wird davon ausgeganen, das der Radio-Zustand = DISABLED ist
+//
+int nRF52840Radio::sendSync(bcPduPtr inPduPtr, TxStatePtr refState)
+{
+  int   retv = 0;
+  NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+  NrfRadioPtr->EVENTS_READY = 0;
+  NrfRadioPtr->EVENTS_END = 0;
+  memcpy((void *)pduMem, (void *)inPduPtr, sizeof(bcPdu));  // Daten kopieren
+  if(refState != NULL)
+    refState->prgLoopPrep = retv = 3 + sizeof(bcPdu);
+  NrfRadioPtr->TASKS_TXEN = 1;                  // Starten des Anlaufes
+  while(NrfRadioPtr->EVENTS_READY != 1) retv++; // Warten bis angelaufen
+  if(refState != NULL)
+    refState->evtLoopRampUp = retv - 3;
+  NrfRadioPtr->TASKS_START = 1;                 // Starten des Sendevorgangs
+  while(NrfRadioPtr->EVENTS_END != 1) retv++;   // Warten bis gesendet
+  NrfRadioPtr->TASKS_DISABLE = 1;               // Sender abschalten
+  if(refState != NULL)
+  {
+    refState->evtLoopTrans = retv - refState->evtLoopRampUp;
+    refState->txBufferPtr = pduMem;
+  }
+  return(retv);
+}
+
+void  nRF52840Radio::send(bcPduPtr inPduPtr, TxMode txMode)
+{
+  send(inPduPtr, NULL, txMode, false);
+}
+
+void  nRF52840Radio::send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, bool inNewValues)
+{
+  NrfRadioPtr->INTENCLR         = 0xFFFFFFFF;
+  NrfRadioPtr->EVENTS_READY     = 0;
+  NrfRadioPtr->EVENTS_END       = 0;
+  NrfRadioPtr->EVENTS_DISABLED  = 0;
+  NrfRadioPtr->EVENTS_RXREADY   = 0;
+  NrfRadioPtr->EVENTS_TXREADY   = 0;
+  NrfRadioPtr->EVENTS_ADDRESS   = 0;
+
+  // TODO
+  // Das muss Alles noch einmal überarbeitet werden.
+  // Hier stecken zu viele Redundanzen drin, Altlast aus diversen Tests mit der Hardware
+
+  memcpy((void *)pduMem, (void *)inPduPtrE, sizeof(bcPdu));    // Daten in Funkpuffer kopieren
+
+  memcpy((void *)pduSentE, (void *)inPduPtrE, sizeof(bcPdu));  // Daten in extra Puffer kopieren
+  // Die übergebenen Daten werden in einen Extrapuffer kopiert zur Entkopplung für eventuelle
+  // lokale Modifikationen
+
+  if(inPduPtrS != NULL)                             // Falls Daten für eine Antwort gegeben sind
+    memcpy((void *)pduSentS, (void *)inPduPtrS, sizeof(bcPdu));// Daten in extra Puffer kopieren
+  // Die übergebenen Daten werden in einen Extrapuffer kopiert zur Entkopplung für eventuelle
+  // lokale Modifikationen
+
+  comFin    = false;
+  comError  = false;
+  newValues = inNewValues;
+
+  trfMode = txMode;
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+  statisticPtr = &statList[(int) txMode];
+  statisticPtr->mode = txMode;
+  memset(statisticPtr->memDumpRec,0,16);
+  memset(statisticPtr->memDumpSnd,0,16);
+#endif
+
+  switch(txMode)
+  {
+    case txmPoll:
+      recMode = false;
+      NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN | NrfScRXREADY_START;
+      NrfRadioPtr->INTENSET = NrfIntRXREADY;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmResp:
+    case txmRespE:
+      recMode = true;
+      NrfRadioPtr->SHORTS = NrfScREADY_START;
+      NrfRadioPtr->INTENSET = NrfIntEND;
+      NrfRadioPtr->TASKS_RXEN = 1;
+      break;
+
+    case txmBase:
+      NrfRadioPtr->SHORTS = NrfScREADY_START | NrfScEND_DISABLE;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmRepStart:
+      NrfRadioPtr->SHORTS = NrfScREADY_START;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmRepCont:
+      NrfRadioPtr->SHORTS = 0;
+      NrfRadioPtr->TASKS_START = 1;
+      break;
+
+    case txmRepEnd:
+      NrfRadioPtr->SHORTS = NrfScEND_DISABLE;
+      NrfRadioPtr->TASKS_START = 1;
+      break;
+
+    case txmReadPrep:
+      NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmReadS:
+      NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN | NrfScRXREADY_START;
+      NrfRadioPtr->INTENSET = NrfIntADDRESS;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmRead:
+      NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN | NrfScRXREADY_START;
+      NrfRadioPtr->INTENSET = NrfIntADDRESS | NrfIntEND;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+  }
+}
+
+void nRF52840Radio::disable(TxMode txMode)
+{
+  switch(txMode)
+   {
+     case txmBase:
+       break;
+
+     case txmRepStart:
+       break;
+
+     case txmRepCont:
+       break;
+
+     case txmRepEnd:
+       break;
+
+     case txmReadPrep:
+       break;
+
+     case txmRead:
+       NrfRadioPtr->TASKS_DISABLE = 1;
+       break;
+
+     case txmPoll:
+       NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+       NrfRadioPtr->EVENTS_DISABLED = 0;
+       NrfRadioPtr->TASKS_DISABLE = 1;
+       break;
+
+     case txmResp:
+     case txmRespE:
+       NrfRadioPtr->TASKS_DISABLE = 1;
+       break;
+   }
+  NrfRadioPtr->SHORTS = 0;
+}
+
+bool nRF52840Radio::disabled(TxMode txMode)
+{
+  bool retv = false;
+
+  switch(txMode)
+   {
+     case txmBase:
+       break;
+
+     case txmRepStart:
+       break;
+
+     case txmRepCont:
+       break;
+
+     case txmRepEnd:
+       break;
+
+     case txmReadPrep:
+       break;
+
+     case txmRead:
+     case txmPoll:
+       if(NrfRadioPtr->EVENTS_DISABLED == 1)
+       {
+         NrfRadioPtr->EVENTS_DISABLED = 0;
+         retv = true;
+       }
+       else
+       {
+         if(NrfRadioPtr->STATE == NrfStDISABLED)
+           retv = true;
+       }
+       break;
+
+     case txmResp:
+     case txmRespE:
+       if(NrfRadioPtr->EVENTS_DISABLED == 1)
+       {
+         NrfRadioPtr->EVENTS_DISABLED = 0;
+         retv = true;
+       }
+       else
+       {
+         if(NrfRadioPtr->STATE == NrfStDISABLED)
+           retv = true;
+       }
+       break;
+   }
+  return(retv);
+}
+
+bool nRF52840Radio::fin(TxMode txMode, bool *crcErr)
+{
+  bool retv = false;
+
+  *crcErr = comError;
+
+  switch(txMode)
+   {
+     case txmBase:
+       break;
+
+     case txmRepStart:
+       break;
+
+     case txmRepCont:
+       break;
+
+     case txmRepEnd:
+       break;
+
+     case txmReadPrep:
+       break;
+
+     case txmReadS:
+       retv = comFin;
+       break;
+
+     case txmRead:
+       /*
+       if(NrfRadioPtr->EVENTS_END == 1)
+       {
+         NrfRadioPtr->EVENTS_END = 0;
+         retv = true;
+       }
+       else
+       {
+         if(NrfRadioPtr->STATE == NrfStRXIDLE)
+           retv = true;
+       }
+       */
+       retv = comFin;
+       break;
+
+     case txmPoll:
+       retv = comFin;
+       break;
+
+     case txmResp:
+       retv = comFin;
+       break;
+
+     case txmRespE:
+       if(NrfRadioPtr->STATE == NrfStDISABLED && !recMode)
+         retv = true;
+       break;
+   }
+  return(retv);
+}
+
+void nRF52840Radio::cont(TxMode txMode)
+{
+  switch(txMode)
+   {
+     case txmBase:
+       break;
+
+     case txmRepStart:
+       break;
+
+     case txmRepCont:
+       break;
+
+     case txmRepEnd:
+       break;
+
+     case txmReadPrep:
+       break;
+
+     case txmRead:
+       comFin = false;
+       NrfRadioPtr->TASKS_START = 1;
+       break;
+   }
+}
+
+int   nRF52840Radio::getRecData(bcPduPtr data, TxMode txMode, int max)
+{
+  byte *bPtr = (byte *) data;
+  int retv = 0;
+
+  switch(txMode)
+  {
+    case txmResp:
+      data->head = pduSentE[0];
+      retv = data->len  = pduSentE[1];
+
+      for(int i = 2; i < (retv + 2); i++)
+      {
+        if(i == max) break;
+        bPtr[i] = pduSentE[i];
+      }
+
+      break;
+
+    case txmBase:
+      break;
+
+    case txmRepStart:
+      break;
+
+    case txmRepCont:
+      break;
+
+    case txmRepEnd:
+      break;
+
+    case txmReadPrep:
+      break;
+
+    case txmRead:
+      break;
+  }
+
+
+  return(retv);
+}
+
+
+
+// ----------------------------------------------------------------------------
+//                      E m p f a n g e n
+// ----------------------------------------------------------------------------
+
+// Starten des Datenempfangs
+//
+int nRF52840Radio::startRec()
+{
+  int   retv;
+  NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+  NrfRadioPtr->EVENTS_READY = 0;
+  NrfRadioPtr->EVENTS_END = 0;
+  NrfRadioPtr->EVENTS_ADDRESS = 0;
+  NrfRadioPtr->EVENTS_PAYLOAD = 0;
+  NrfRadioPtr->EVENTS_CRCOK = 0;
+  NrfRadioPtr->EVENTS_CRCERROR = 0;
+  NrfRadioPtr->TASKS_RXEN = 1;                  // Anlauf Empfänger starten
+  retv = 8;
+  while(NrfRadioPtr->EVENTS_READY != 1) retv++; // Warten bis angelaufen
+  NrfRadioPtr->TASKS_START = 1;                 // Starten des Empfangs
+  return(retv + 1);
+}
+
+// Fortsetzen des Datenempfangs
+//
+int nRF52840Radio::contRec()
+{
+  NrfRadioPtr->EVENTS_END = 0;
+  NrfRadioPtr->EVENTS_ADDRESS = 0;
+  NrfRadioPtr->EVENTS_PAYLOAD = 0;
+  NrfRadioPtr->EVENTS_CRCOK = 0;
+  NrfRadioPtr->EVENTS_CRCERROR = 0;
+  NrfRadioPtr->TASKS_START = 1;                 // Starten des Empfangs
+  return(6);
+}
+
+// Beenden des Datenempfangs
+//
+int nRF52840Radio::endRec()
+{
+  int   retv;
+  NrfRadioPtr->EVENTS_DISABLED = 0;
+  NrfRadioPtr->EVENTS_END = 0;
+  NrfRadioPtr->EVENTS_ADDRESS = 0;
+  NrfRadioPtr->EVENTS_PAYLOAD = 0;
+  NrfRadioPtr->EVENTS_CRCOK = 0;
+  NrfRadioPtr->EVENTS_CRCERROR = 0;
+  NrfRadioPtr->TASKS_DISABLE = 1;               // Anlauf Empfänger beenden
+  retv = 7;
+  while(NrfRadioPtr->EVENTS_DISABLED != 1) retv++; // Warten bis abgelaufen
+  return(retv);
+}
+
+// Empfangszustand abfragen
+//
+int nRF52840Radio::checkRec()
+{
+  int retv = 0;
+
+  if(NrfRadioPtr->EVENTS_ADDRESS != 0)
+    retv |= RECSTAT_ADDRESS;
+
+  if(NrfRadioPtr->EVENTS_PAYLOAD != 0)
+    retv |= RECSTAT_PAYLOAD;
+
+  if(NrfRadioPtr->EVENTS_END != 0)
+    retv |= RECSTAT_END;
+
+  if(NrfRadioPtr->CRCSTATUS != 0)
+    retv |= RECSTAT_CRCOK;
+
+  if(NrfRadioPtr->EVENTS_DISABLED != 0)
+    retv |= RECSTAT_DISABLED;
+
+  return(retv);
+}
+
+int   nRF52840Radio::getRecData(bcPduPtr data, int max)
+{
+  int retv;
+  byte *bPtr = (byte *) data;
+
+  data->head = pduMem[0];
+  retv = data->len  = pduMem[1];
+
+  for(int i = 2; i < (retv + 2); i++)
+  {
+    if(i == max) break;
+    bPtr[i] = pduMem[i];
+  }
+
+  return(retv);
+}
+
+// ----------------------------------------------------------------------------
+// Interruptverarbeitung
+// ----------------------------------------------------------------------------
+//
+
+nRF52840Radio *nRF52840Radio::instPtr0 = NULL;
+
+void nRF52840Radio::irqHandler0()
+{
+  if(instPtr0 == NULL) return;
+  instPtr0->irqCounter++;
+  instPtr0->irqHandler();
+}
+
+void nRF52840Radio::irqHandler()
+{
+  statisticPtr->interrupts++;
+
+  switch(trfMode)
+  {
+    // ------------------------------------------------------------------------
+    case txmRead:               // Empty Polling für Master
+    // ------------------------------------------------------------------------
+
+      if((NrfRadioPtr->STATE & 0x08) != 0)  // Noch im Sendemodus
+      { // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_ADDRESS == 1)  // AC-Adr gesendet
+        {
+          NrfRadioPtr->EVENTS_ADDRESS = 0;    // nur quittieren
+        }
+
+        if(NrfRadioPtr->EVENTS_END == 1)      // Senden fertig
+        {
+          NrfRadioPtr->EVENTS_END = 0;        // nur quittieren
+          statisticPtr->sendings++;
+          memcpy(statisticPtr->memDumpSnd,pduMem,8);
+        }
+      }
+      else                                  // im Empfangsmodus
+      { // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_ADDRESS == 1)  // AC-Adr empfangen
+        {
+          NrfRadioPtr->EVENTS_ADDRESS = 0;    // quittieren
+          NrfRadioPtr->SHORTS = 0;            // Direktverbindungen löschen
+        }
+
+        if(NrfRadioPtr->EVENTS_END == 1)      // Empfang fertig
+        {
+          NrfRadioPtr->EVENTS_END = 0;        // nur quittieren
+          comFin = true;
+          statisticPtr->recs++;
+          memcpy(statisticPtr->memDumpRec,pduMem,8);
+        }
+      }
+
+      break;
+
+    // ------------------------------------------------------------------------
+    case txmPoll:     // Empty Polling und Datenempfang für Master -> DISABLED
+    // ------------------------------------------------------------------------
+      if(NrfRadioPtr->EVENTS_RXREADY == 1)    // Empfang aktiviert
+      {
+        NrfRadioPtr->EVENTS_RXREADY = 0;      // Int quittieren
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+        statisticPtr->sendings++;
+        memcpy(statisticPtr->memDumpSnd,pduMem,8);
+#endif
+        NrfRadioPtr->EVENTS_DISABLED = 0;     // Neu erwartet, zurücksetzen
+        NrfRadioPtr->SHORTS = NrfScEND_DISABLE | NrfScRXREADY_START;
+        NrfRadioPtr->INTENSET = NrfIntDISABLED;
+        recMode = true;
+      }
+
+      if(NrfRadioPtr->EVENTS_DISABLED == 1)   // Empfang beendet
+      {
+        NrfRadioPtr->EVENTS_DISABLED = 0;     // Int quittieren
+        comFin = true;
+        if(NrfRadioPtr->CRCSTATUS == 0)
+          comError = true;
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+        statisticPtr->recs++;
+        if(comError) statisticPtr->crcErrors++;
+        memcpy(statisticPtr->memDumpRec,pduMem,16);
+        if(!recMode)
+        {
+          // Das darf nicht passieren, sonst neue Int-Verarbeitung erforderlich
+          statisticPtr->intErrors++;
+        }
+#endif
+      }
+      break;
+
+    // ------------------------------------------------------------------------
+    case txmReadS:              // Datenübertragung für Master (Slave->Master)
+    // ------------------------------------------------------------------------
+
+      if(NrfRadioPtr->EVENTS_ADDRESS == 1)    // AC-Adr gesendet
+      {
+        NrfRadioPtr->EVENTS_ADDRESS = 0;      // quittieren
+
+        if((NrfRadioPtr->STATE & 0x08) != 0)  // im Sendezustand
+          break;                              // nichts weiter
+        // --------------------------------------------------------------------
+        else                                  // Im Empfangszustand
+        {
+          NrfRadioPtr->SHORTS = NrfScEND_DISABLE; // automatisch abschalten
+          NrfRadioPtr->INTENCLR = 0xFFFFFFFF;     // und nur noch DISABLED
+          NrfRadioPtr->INTENSET = NrfIntDISABLED; // Interrupt freischalten
+        }
+      }
+
+      if(NrfRadioPtr->EVENTS_DISABLED == 1)   // Übertragung fertig
+      {
+        NrfRadioPtr->EVENTS_DISABLED = 0;     // quittieren
+        comFin = true;
+      }
+
+
+      break;
+
+    // ----------------------------------------------------------------------
+    case txmRespE:              // Empty Polling für Slave
+    // ----------------------------------------------------------------------
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_END == 1)        // Übertragung beendet
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_END = 0;          // Event quittieren
+
+          if(recMode)                           // im Empfangsmodus
+          { // ----------------------------------------------------------------
+            NrfRadioPtr->SHORTS = 0;            // keine direkte Kopplung mehr
+
+            statisticPtr->recs++;
+            memcpy(statisticPtr->memDumpRec,pduMem,8);
+
+            // ----------------------------------------------------------------
+            // Reaktion
+            // ----------------------------------------------------------------
+            //
+            if((pduSentE[5] == pduMem[5]) && (pduSentE[6] == pduMem[6]) && (pduSentE[7] == pduMem[7]))
+            {
+              // Die richtige Protokollumgebung (z.B. Soaap)
+              //
+              if(pduSentE[2] != pduMem[2])
+              {
+                // aber die falsche Adresse
+                // Datenempfang fortsetzen
+                statisticPtr->wrongs++;
+                NrfRadioPtr->TASKS_START = 1;
+              }
+              else
+              { // richtige Adresse, Antwort schicken
+                // ------------------------------------------------------------
+                statisticPtr->pollNaks++;
+
+                // zunächst alle Funk-Interrupts sperren
+                NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+
+                // Interrupt freigeben für "Abgeschaltet"
+                NrfRadioPtr->INTENSET = NrfIntDISABLED;
+
+                // Empfangsbetrieb abschalten
+                NrfRadioPtr->TASKS_DISABLE = 1;
+              }
+
+            }
+            else
+            {
+              // Fremde Umgebung (nicht akzeptierte PDU)
+              // Datenempfang fortsetzen
+              statisticPtr->aliens++;
+              NrfRadioPtr->TASKS_START = 1;
+            }
+          }
+          else                                      // im Sendemodus
+          { // ----------------------------------------------------------------
+
+
+          }
+        }
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_DISABLED == 1)       // ausgeschaltet
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_DISABLED = 0;         // quittieren
+
+          if(recMode)
+          {
+            // zunächst alle Funk-Interrupts sperren
+            NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+
+            // Interrupt freigeben für "Abgeschaltet"
+            NrfRadioPtr->INTENSET = NrfIntDISABLED;
+
+            // Kopplung automatisch starten und abschalten nach Ende
+            NrfRadioPtr->SHORTS = NrfScREADY_START | NrfScEND_DISABLE;
+
+            NrfRadioPtr->TASKS_TXEN = 1;             // Sender einschalten
+            recMode = false;
+
+            // Daten in Funkpuffer kopieren
+            memcpy((void *)pduMem, (void *)pduSentE, sizeof(bcPdu));
+          }
+          else
+          {
+            NrfRadioPtr->SHORTS = 0;
+            statisticPtr->sendings++;
+          }
+        }
+
+        break;
+
+      // ----------------------------------------------------------------------
+      case txmResp:               // Datenübertragung Slave
+      // ----------------------------------------------------------------------
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_END == 1)        // Übertragung beendet
+                                                // Polling-Daten empfangen
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_END = 0;          // Event quittieren
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+          statisticPtr->recs++;
+          memcpy(statisticPtr->memDumpRec,pduMem,8);
+#endif
+
+          if((pduSentE[5] != pduMem[5]) || (pduSentE[6] != pduMem[6]) || (pduSentE[7] != pduMem[7]))
+          {
+            // Das empfangene Telegramm gehört nicht zum eigenen Netzwerk
+            //
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+            statisticPtr->aliens++;
+#endif
+            NrfRadioPtr->SHORTS = 0;            // Keine Direktverbindungen
+            NrfRadioPtr->TASKS_START = 1;       // Datenempfang fortsetzen
+            break;
+          }
+
+          if((pduSentE[2] != pduMem[2]) || ((pduSentE[3] & 0x3F) != (pduMem[3] & 0x3F)))
+          {
+            // Das empfangene Telegramm ist für einen anderen Slave oder Bereich
+            //
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+            statisticPtr->wrongs++;
+#endif
+            NrfRadioPtr->SHORTS = 0;            // Keine Direktverbindungen
+            NrfRadioPtr->TASKS_START = 1;       // Datenempfang fortsetzen
+            break;
+            // TODO
+            // Hier wird das Protokoll noch erweitert zum Belauschen anderer Slaves
+          }
+
+          eadM = ((pduMem[3] & SOAAP_EADR) != 0); // Merker für Empfangspolling
+          nakM = ((pduMem[3] & SOAAP_NAK) != 0);  // Merker für NAK-Polling
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+          if(nakM)
+            statisticPtr->pollNaks++;
+          else
+            statisticPtr->pollAcks++;
+#endif
+          if(eadM)
+          {
+            // Empfangsaufforderung
+            // Eadr-Nak-Daten in Funkpuffer kopieren
+            //
+            memcpy((void *)pduMem, (void *)pduSentE, sizeof(bcPdu));
+          }
+          else
+          {
+            // Sendeaufforderung
+            // Polling-Steuerdaten in Empfangspuffer und
+            // Sadr-Ack-Daten in Funkpuffer kopieren
+            //
+            memcpy((void *)pduSentE, (void *)pduMem, sizeof(bcPdu));
+            memcpy((void *)pduMem, (void *)pduSentS, sizeof(bcPdu));
+          }
+
+          // Setzen der Direktverbinder auf vollständigen Durchlauf bis Ende der Sendung
+          // ACHTUNG! Freigegebene Interrupts treten auf, auch wenn sie zu einer
+          //          Direktverbindung gehören.
+          //
+          NrfRadioPtr->SHORTS = NrfScDISABLED_TXEN | NrfScREADY_START | NrfScEND_DISABLE;
+          NrfRadioPtr->EVENTS_READY = 0;        // Evt. hängendes Ereignis löschen
+          NrfRadioPtr->INTENSET = NrfIntREADY;  // Int zur Vorbereitung des Sendeabschlusses
+          NrfRadioPtr->TASKS_DISABLE = 1;       // Abschalten des Empfangsbetriebs
+          break;
+        }
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_READY == 1)      // Bereit zum Senden
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_READY = 0;        // Event quittieren
+
+          // Vorbereiten auf das Ende der Sendung mit Abschalten
+          // NrfScREADY_START | NrfScEND_DISABLE sind weiter wirksam
+          //
+          NrfRadioPtr->SHORTS = NrfScREADY_START | NrfScEND_DISABLE;
+          NrfRadioPtr->EVENTS_DISABLED = 0;       // Evt. hängendes Ereignis löschen
+          recMode = false;
+          NrfRadioPtr->INTENSET = NrfIntDISABLED; // Int zum Sendeabschluss
+          break;
+        }
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_DISABLED == 1)   // Sendevorgang beendet
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_DISABLED = 0;     // Event quittieren
+          comFin = true;
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+          statisticPtr->sendings++;
+          memcpy(statisticPtr->memDumpSnd,pduMem,16);
+#endif
+        }
+
+        break;
+
+  }
+}
+
+// --------------------------------------------------------------------------
+// Datenzugriffe
+// --------------------------------------------------------------------------
+//
+int   nRF52840Radio::getStatistics(TxStatisticsPtr dest)
+{
+  int retv = 0;
+
+  *dest = *statisticPtr;
+  return(retv);
+}
+
+int nRF52840Radio::getState()
+{
+  return(NrfRadioPtr->STATE);
+}
+
+// ----------------------------------------------------------------------------
+//                      D e b u g - H i l f e n
+// ----------------------------------------------------------------------------
+//
+int   nRF52840Radio::getPduMem(byte *dest, int start, int end)
+{
+  int i,j;
+
+  j = 0;
+
+  for(i = start; i < end; i++)
+  {
+    dest[j++] = pduMem[i];
+  }
+  return(j);
+}
+
+int   nRF52840Radio::getPduSent(byte *dest, int start, int end)
+{
+  int i,j;
+
+  j = 0;
+
+  for(i = start; i < end; i++)
+  {
+    dest[j++] = pduSentE[i];
+  }
+  return(j);
+}
+
+
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Radio/nRF52840Radio.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Radio/nRF52840Radio.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e61246043b8b3bd78928b3e33e31f81e180d011
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Radio/nRF52840Radio.h
@@ -0,0 +1,313 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Radio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef NRF52840RADIO_H
+#define NRF52840RADIO_H
+
+#include "arduinoDefs.h"
+#include "bleSpec.h"
+#include "IntrfRadio.h"
+
+#define nRF52840RadioDEB
+
+// ----------------------------------------------------------------------------
+
+typedef struct _NRF_RADIO_Type
+{
+  volatile  dword  TASKS_TXEN;
+  volatile  dword  TASKS_RXEN;
+  volatile  dword  TASKS_START;
+  volatile  dword  TASKS_STOP;
+  volatile  dword  TASKS_DISABLE;
+  volatile  dword  TASKS_RSSISTART;
+  volatile  dword  TASKS_RSSISTOP;
+  volatile  dword  TASKS_BCSTART;
+  volatile  dword  TASKS_BCSTOP;
+  volatile  dword  TASKS_EDSTART;
+  volatile  dword  TASKS_EDSTOP;
+  volatile  dword  TASKS_CCASTART;
+  volatile  dword  TASKS_CCASTOP;
+  volatile  dword  RESERVED0[51];
+  volatile  dword  EVENTS_READY;
+  volatile  dword  EVENTS_ADDRESS;
+  volatile  dword  EVENTS_PAYLOAD;
+  volatile  dword  EVENTS_END;
+  volatile  dword  EVENTS_DISABLED;
+  volatile  dword  EVENTS_DEVMATCH;
+  volatile  dword  EVENTS_DEVMISS;
+  volatile  dword  EVENTS_RSSIEND;
+  volatile  dword  RESERVED1[2];
+  volatile  dword  EVENTS_BCMATCH;
+  volatile  dword  RESERVED2;
+  volatile  dword  EVENTS_CRCOK;
+  volatile  dword  EVENTS_CRCERROR;
+  volatile  dword  EVENTS_FRAMESTART;
+  volatile  dword  EVENTS_EDEND;
+  volatile  dword  EVENTS_EDSTOPPED;
+  volatile  dword  EVENTS_CCAIDLE;
+  volatile  dword  EVENTS_CCABUSY;
+  volatile  dword  EVENTS_CCASTOPPED;
+  volatile  dword  EVENTS_RATEBOOST;
+  volatile  dword  EVENTS_TXREADY;
+  volatile  dword  EVENTS_RXREADY;
+  volatile  dword  EVENTS_MHRMATCH;
+  volatile  dword  RESERVED3[2];
+  volatile  dword  EVENTS_SYNC;
+  volatile  dword  EVENTS_PHYEND;
+  volatile  dword  RESERVED4[36];
+  volatile  dword  SHORTS;
+  volatile  dword  RESERVED5[64];
+  volatile  dword  INTENSET;
+  volatile  dword  INTENCLR;
+  volatile  dword  RESERVED6[61];
+  volatile  dword  CRCSTATUS;
+  volatile  dword  RESERVED7;
+  volatile  dword  RXMATCH;
+  volatile  dword  RXCRC;
+  volatile  dword  DAI;
+  volatile  dword  PDUSTAT;
+  volatile  dword  RESERVED8[59];
+  volatile  dword  PACKETPTR;
+  volatile  dword  FREQUENCY;
+  volatile  dword  TXPOWER;
+  volatile  dword  MODE;
+  volatile  dword  PCNF0;
+  volatile  dword  PCNF1;
+  volatile  dword  BASE0;
+  volatile  dword  BASE1;
+  volatile  dword  PREFIX0;
+  volatile  dword  PREFIX1;
+  volatile  dword  TXADDRESS;
+  volatile  dword  RXADDRESSES;
+  volatile  dword  CRCCNF;
+  volatile  dword  CRCPOLY;
+  volatile  dword  CRCINIT;
+  volatile  dword  RESERVED9;
+  volatile  dword  TIFS;
+  volatile  dword  RSSISAMPLE;
+  volatile  dword  RESERVED10;
+  volatile  dword  STATE;
+  volatile  dword  DATAWHITEIV;
+  volatile  dword  RESERVED11[2];
+  volatile  dword  BCC;
+  volatile  dword  RESERVED12[39];
+  volatile  dword  DAB[8];
+  volatile  dword  DAP[8];
+  volatile  dword  DACNF;
+  volatile  dword  MHRMATCHCONF;
+  volatile  dword  MHRMATCHMAS;
+  volatile  dword  RESERVED13;
+  volatile  dword  MODECNF0;
+  volatile  dword  RESERVED14[3];
+  volatile  dword  SFD;
+  volatile  dword  EDCNT;
+  volatile  dword  EDSAMPLE;
+  volatile  dword  CCACTRL;
+  volatile  dword  RESERVED15[611];
+  volatile  dword  POWER;
+} *nrfRadioPtr;
+
+
+
+#define NrfRadioBase    0x40001000
+#define NrfRadioPtr     ((nrfRadioPtr) NrfRadioBase)
+
+#ifndef NrfPowerBase
+#define NrfPowerBase    0x40000000
+#define nrfPowerDCDCEN  ((dword *) 0x40000578)
+#endif
+
+#ifndef NrfClockBase
+#define NrfClockBase    0x40000000
+#define nrfClockTASKS_HFCLKSTART  ((dword *) 0x40000000)
+#endif
+
+// Direktverbindungen (shortcuts) zwischen events und Tasks
+//
+#define NrfScREADY_START    0x00000001
+#define NrfScEND_DISABLE    0x00000002
+#define NrfScDISABLED_TXEN  0x00000004
+#define NrfScDISABLED_RXEN  0x00000008
+#define NrfScTXREADY_START  0x00040000
+#define NrfScRXREADY_START  0x00080000
+
+// Interrupts
+//
+#define NrfIntREADY         0x00000001
+#define NrfIntADDRESS       0x00000002
+#define NrfIntPAYLOAD       0x00000004
+#define NrfIntEND           0x00000008
+#define NrfIntDISABLED      0x00000010
+#define NrfIntRSSIEND       0x00000080
+#define NrfIntTXREADY       0x00200000
+#define NrfIntRXREADY       0x00400000
+
+// Zustände
+//
+#define NrfStDISABLED       0
+#define NrfStRXRU           1
+#define NrfStRXIDLE         2
+#define NrfStRX             3
+#define NrfStRXDISABLE      4
+#define NrfStTXRU           9
+#define NrfStTXIDLE         10
+#define NrfStTX             11
+#define NrfStTXDISABLE      12
+
+// Festlegungen für die Paketkonfigurationsregister
+//
+
+#define PCNF0_LFLEN(x)    x
+// Anzahl der Bits im Längenfeld (0-15)
+
+#define PCNF0_S0LEN(x)    (x << 8)
+// Länge des Header0 (S0) in Bytes (0 oder 1)
+
+#define PCNF0_S1LEN(x)    (x << 16)
+// Länge des S1-Feldes in Bit (0 bis 15)
+
+#define PCNF1_MAXLEN(x)   x
+// Maximale Telegrammlänge (0 bis 255)
+
+#define PCNF1_BALEN(x)    (x << 16)
+// Basislänge der Zugriffsadresse (Access Address, 2-4)
+
+#define PCNF1_WHITEEN(x)  (x << 25)
+// Whitening (Bitmischung) Ein/Aus (1/0)
+
+// Festlegungen für die CRC-Generierung
+//
+
+#define CRCCNF_LEN(x)     x
+// Anzahl der Bytes für CRC (0-3)
+
+#define CRCCNF_SKIPADDR(x)  (x << 8)
+// Zugriffsadresse (Access Address) nicht im CRC (1), im CRC (0)
+
+
+typedef struct _nrf52840Cfg
+{
+  dword   pCnf0;
+  dword   pCnf1;
+  dword   whiteInit;
+  dword   modeCnf0;
+  dword   crcPoly;
+  dword   crcInit;
+  dword   crcCnf;
+  dword   packetPtr;
+  dword   frequency;
+  dword   txPower;
+  dword   mode;
+  dword   dacnf;
+  dword   rxAddrEn;
+  dword   base0;
+  dword   prefix0;
+  dword   txAddr;
+  dword   rxAddr;
+
+}nrf52840Cfg, *nrf52840CfgPtr;
+
+// ----------------------------------------------------------------------------
+
+class nRF52840Radio : IntrfRadio
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  byte        pduMem[256];
+  byte        pduSentE[256];
+  byte        pduSentS[256];
+
+  bcPduPtr    pmPtr;
+  bcPduPtr    pePtr;
+  bcPduPtr    psPtr;
+
+  nrf52840Cfg cfgData;
+
+  bool        recMode;
+  bool        eadM;
+  bool        nakM;
+  bool        comFin;
+  bool        comError;
+  bool        newValues;
+
+  dword       irqCounter;
+  TxMode      trfMode;
+
+  TxStatistics    statList[NrOfTxModes];
+  TxStatisticsPtr statisticPtr;
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen der Basis-Klasse
+  // --------------------------------------------------------------------------
+
+  nRF52840Radio();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  void  begin();
+  void  setAccessAddress(dword addr); // Setzen der Zugriffsadresse
+  void  setPacketParms(blePduType type);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void  setChannel(int nr);           // Schalten physikalischer Kanal
+  int   sendSync(bcPduPtr inPduPtr, TxStatePtr refState);
+
+  void  send(bcPduPtr inPduPtr, TxMode txMode);
+  void  send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, bool newValues);
+  int   getRecData(bcPduPtr data, TxMode txMode, int max);  // Empfangene Daten lesen
+
+  void  disable(TxMode txMode);
+  bool  disabled(TxMode txMode);      // Abfrage, ob ausgeschaltet
+  void  cont(TxMode txMode);
+  bool  fin(TxMode txMode, bool *err);
+                                      // Senden eines Telegramms (und warten)
+  int   startRec();                   // Datenempfang starten
+  int   contRec();                    // Datenempfang fortsetzen
+  int   endRec();                     // Datenempfang beenden
+  int   checkRec();                   // Zustand Datenempfang feststellen
+  int   getRecData(bcPduPtr data, int max);  // Empfangene Daten lesen
+
+  void  setPower(int DBm);            // Leistung des Senders in DBm
+
+  void  readCheckCfg();               // Konfigurationsdaten auslesen
+
+  static  nRF52840Radio *instPtr0;
+  static  void irqHandler0();
+
+  void    irqHandler();
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  int   getStatistics(TxStatisticsPtr dest);
+  int   getState();
+
+  // ----------------------------------------------------------------------------
+  //                      D e b u g - H i l f e n
+  // ----------------------------------------------------------------------------
+  //
+  int   getPduMem(byte *dest, int start, int end);
+  int   getPduSent(byte *dest, int start, int end);
+
+
+};
+
+
+#endif // NRF52840RADIO_H
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Ser/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Ser/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..fa5d17537ce11418ad11ee8b2689c1ae0ba6a20b
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Ser/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Ser",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Ser/nRF52840Ser.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Ser/nRF52840Ser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..86b66bb6cd5ba3f8e3a58c8587d7df52eac240f5
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Ser/nRF52840Ser.cpp
@@ -0,0 +1,323 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Ser.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#include "nRF52840Ser.h"
+#include <string.h>
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+
+nRF52840Ser::nRF52840Ser()
+{
+  serPtr      = NULL;
+  instPtr0    = NULL;
+  irqCounter  = 0;
+  curIntEn    = 0;
+  curIRQ      = 0;
+  lastError   = 0;
+  cntError    = 0;
+}
+
+dword speedArr[18] =
+{
+    0x0004F000, 0x0009D000, 0x0013B000,
+    0x00275000, 0x003B0000, 0x004EA000,
+    0x0075F000, 0x00800000, 0x009D5000,
+    0x00E50000, 0x00EBF000, 0x013A9000,
+    0x01D7E000, 0x03AFB000, 0x04000000,
+    0x075F7000, 0x0EBED000, 0x10000000
+};
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+//
+void nRF52840Ser::begin(SerParamsPtr inParPtr, IntrfBuf *bufferIf)
+{
+  nrfGpioPtr  gpioPtr;
+  dword       regVal;
+
+  // Setzen des Peripheriezeigers anhand der Instanz
+  // und Initialisieren weiterer Variablen/Zeiger
+  //
+  serPtr = NrfSerPtr0;
+  clrAllEvents();
+  instPtr0  = this;
+  curIRQ    = 2;
+
+  // Interruptvektor setzen
+  //
+  __NVIC_SetVector((IRQn_Type) 2, (dword) nRF52840Ser::irqHandler0);
+  __NVIC_SetPriority((IRQn_Type) 2, 1);
+  __NVIC_EnableIRQ((IRQn_Type) 2);
+
+  // Alternative Peripherie (gleiche ID, also Alles) abschalten
+  //
+  serPtr->ENABLE = SerDisable;
+
+
+  // TxD
+  // -------------------------------------------------
+  //
+  // Pins zuweisen und initialisieren
+  //
+  if(inParPtr->txdPort == 1)
+  {
+    regVal = 32 + inParPtr->txdPin;
+    gpioPtr = NrfGpioPtr1;
+  }
+  else
+  {
+    regVal = inParPtr->txdPin;
+    gpioPtr = NrfGpioPtr0;
+  }
+
+
+  // Connect (hoechstwertiges Bit) beruecksichtigen
+  //
+  serPtr->PSEL_TXD = regVal | 0x7FFFFFC0;
+
+  // Zugewiesenen Pin als Ausgang schalten und Treibermodus setzen
+  // Laut Datenblatt ist das entsprechende Bit im Konfigurationsregister
+  // mit dem DIR-Register physikalisch verbunden
+  //
+  if(inParPtr->type == stStd)
+    regVal = GpioPinCnf_DRIVE(GpioDriveS0S1);
+  else if(inParPtr->type == stPow)
+    regVal = GpioPinCnf_DRIVE(GpioDriveH0H1);
+  else
+    regVal = GpioPinCnf_DRIVE(GpioDriveH0D1);
+
+  gpioPtr->PIN_CNF[inParPtr->txdPin] = regVal | GpioPinCnf_DIROUT;
+
+  // RXD
+  // -------------------------------------------------
+  //
+  if(inParPtr->rxdPort == 1)
+  {
+    regVal = 32 + inParPtr->rxdPin;
+    gpioPtr = NrfGpioPtr1;
+  }
+  else
+  {
+    regVal = inParPtr->rxdPin;
+    gpioPtr = NrfGpioPtr0;
+  }
+
+  // Connect (hoechstwertiges Bit) beruecksichtigen
+  //
+  serPtr->PSEL_RXD = regVal | 0x7FFFFFC0;
+
+  // Zugewiesenen Pin als Eingang schalten und Treibermodus setzen
+  // Laut Datenblatt ist das entsprechende Bit im Konfigurationsregister
+  // mit dem DIR-Register physikalisch verbunden
+  //
+  gpioPtr->PIN_CNF[inParPtr->rxdPin] = GpioPinCnf_PULL(GpioPullUp);
+
+  // Bitrate einstellen
+  //
+  regVal = speedArr[inParPtr->speed];
+  serPtr->BAUDRATE = regVal;
+  serPtr->SHORTS = 0;
+
+  // Interrupts freischalten
+  //
+  curIntEn = (SerInt_TXDRDY | SerInt_RXDRDY | SerInt_ERROR);
+  serPtr->INTENSET = curIntEn;
+
+  // Und bereit machen
+  //
+  serPtr->ENABLE = SerEnable;
+  txdFin = true;
+
+  bufIf = bufferIf;
+  delay(10);
+}
+
+
+// ----------------------------------------------------------------------------
+// Steuerfunktionen, gezielte Prozessorzugriffe und Hilfsfunktionen
+// ----------------------------------------------------------------------------
+//
+void nRF52840Ser::clrAllEvents()
+{
+  serPtr->EVENTS_RXDRDY     = 0;
+  serPtr->EVENTS_TXDRDY     = 0;
+  serPtr->EVENTS_ERROR      = 0;
+}
+
+// Fortsetzen des Interrupt-Sendebetriebs
+//
+void nRF52840Ser::resuSend()
+{
+  byte  td;
+
+  if(!txdFin) return;
+  if(bufIf == NULL) return;
+  if(!bufIf->getByteSnd(&td)) return;
+
+  txdFin = false;
+  serPtr->EVENTS_TXDRDY = 0;
+  serPtr->TXD = td;
+}
+
+// Starten des Sendebetriebs
+//
+void nRF52840Ser::startSend()
+{
+  serPtr->TASKS_STARTTX = 1;
+}
+
+// Anhalten des Sendebetriebs
+//
+void nRF52840Ser::stopSend()
+{
+  serPtr->TASKS_STOPTX = 1;
+}
+
+// Starten des Empfangsbetriebs
+//
+void nRF52840Ser::startRec()
+{
+  serPtr->TASKS_STARTRX = 1;
+}
+
+// Anhalten des Empfangsbetriebs
+//
+void nRF52840Ser::stopRec()
+{
+  serPtr->TASKS_STOPRX = 1;
+}
+
+
+// Bedingtes Ausgeben eines Zeichens
+//
+bool nRF52840Ser::condSend(byte c)
+{
+  if(!txdFin) return(false);
+
+  txdFin = false;
+  serPtr->EVENTS_TXDRDY = 0;
+  serPtr->TXD = c;
+  return(true);
+}
+
+// ----------------------------------------------------------------------------
+// Ereignisbearbeitung und Interrupts
+// ----------------------------------------------------------------------------
+//
+nRF52840Ser *nRF52840Ser::instPtr0 = NULL;
+
+void nRF52840Ser::irqHandler0()
+{
+  if(instPtr0 == NULL) return;
+  instPtr0->irqCounter++;
+  instPtr0->irqHandler();
+}
+
+
+  // --------------------------------------------------------------------------
+  // Interrupts (Ereignisbehandlung)
+  // --------------------------------------------------------------------------
+  //
+void nRF52840Ser::irqHandler()
+{
+  byte  b;
+
+  if(serPtr->EVENTS_TXDRDY != 0)
+  {
+    serPtr->EVENTS_TXDRDY = 0;
+    if(bufIf == NULL) return;
+
+    if(!bufIf->getByteSnd(&b))
+      txdFin = true;
+    else
+      serPtr->TXD = b;
+  }
+  else if(serPtr->EVENTS_RXDRDY != 0)
+  {
+    serPtr->EVENTS_RXDRDY = 0;
+    b = serPtr->RXD;
+    if(bufIf == NULL) return;
+    bufIf->putByteRec(b);
+  }
+  else if(serPtr->EVENTS_ERROR != 0)
+  {
+    serPtr->EVENTS_ERROR = 0;
+    cntError++;
+    lastError = serPtr->ERRORSRC;
+    anyError |= lastError;
+  }
+}
+
+// --------------------------------------------------------------------------
+// Datenzugriffe
+// --------------------------------------------------------------------------
+//
+// Letzten Fehler lesen (Bits)
+//
+int   nRF52840Ser::getLastError()
+{
+  return(lastError);
+}
+
+// Alle vorgekommenen Fehlerbits
+//
+int   nRF52840Ser::getAnyError()
+{
+  return(anyError);
+}
+
+// Anzahl der Fehler lesen
+//
+dword nRF52840Ser::getErrCount()
+{
+  return(cntError);
+}
+
+
+
+// ----------------------------------------------------------------------------
+//                      D e b u g - H i l f e n
+// ----------------------------------------------------------------------------
+//
+dword nRF52840Ser::getIrqCount()
+{
+  return(irqCounter);
+}
+
+void nRF52840Ser::resetIrqList()
+{
+  irqIdx = 0;
+  firstRead = true;
+
+  for(int i = 0; i < 8; i++)
+    irqList[i] = 0;
+}
+
+void nRF52840Ser::getIrqList(char *dest)
+{
+  int destIdx = 0;
+
+  for(int i = 0; i < 8; i++)
+  {
+    if(irqList[i] == 0) break;
+
+    dest[destIdx++] = ' ';
+    dest[destIdx++] = irqList[i] + 0x30;
+  }
+
+  dest[destIdx] = '\0';
+}
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Ser/nRF52840Ser.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Ser/nRF52840Ser.h
new file mode 100644
index 0000000000000000000000000000000000000000..37fcae4b19bc8ec15a2a83040f6f086d35e68efd
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Ser/nRF52840Ser.h
@@ -0,0 +1,234 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Ser.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef NRF52840SER_H
+#define NRF52840SER_H
+
+#include "Arduino.h"
+#include "arduinoDefs.h"
+#include "IntrfBuf.h"
+#include "IntrfSerial.h"
+
+// ----------------------------------------------------------------------------
+
+typedef struct _nrfSer
+{
+  volatile  dword  TASKS_STARTRX;           // 000
+  volatile  dword  TASKS_STOPRX;            // 004
+  volatile  dword  TASKS_STARTTX;           // 008
+  volatile  dword  TASKS_STOPTX;            // 00C
+  volatile  dword  Reserve01[3];            // 010
+  volatile  dword  TASKS_SUSPEND;           // 01C
+  volatile  dword  Reserve02[56];           // 020
+  volatile  dword  EVENTS_CTS;              // 100
+  volatile  dword  EVENTS_NCTS;             // 104
+  volatile  dword  EVENTS_RXDRDY;           // 108
+  volatile  dword  Reserve03[4];            // 10C
+  volatile  dword  EVENTS_TXDRDY;           // 11C
+  volatile  dword  Reserve04;               // 120
+  volatile  dword  EVENTS_ERROR;            // 124
+  volatile  dword  Reserve05[7];            // 128
+  volatile  dword  EVENTS_RXTO;             // 144
+  volatile  dword  Reserve06[46];           // 148
+  volatile  dword  SHORTS;                  // 200
+  volatile  dword  Reserve07[64];           // 204
+  volatile  dword  INTENSET;                // 304
+  volatile  dword  INTENCLR;                // 308
+  volatile  dword  Reserve08[93];           // 30C
+  volatile  dword  ERRORSRC;                // 480
+  volatile  dword  Reserve09[31];           // 484
+  volatile  dword  ENABLE;                  // 500
+  volatile  dword  Reserve10;               // 504
+  volatile  dword  PSEL_RTS;                // 508
+  volatile  dword  PSEL_TXD;                // 50C
+  volatile  dword  PSEL_CTS;                // 510
+  volatile  dword  PSEL_RXD;                // 514
+  volatile  dword  RXD;                     // 518
+  volatile  dword  TXD;                     // 51C
+  volatile  dword  Reserve11;               // 520
+  volatile  dword  BAUDRATE;                // 524
+  volatile  dword  Reserve12[17];           // 528
+  volatile  dword  CONFIG;                  // 56C
+} nrfSer, *nrfSerPtr;
+
+#define NrfSerBase0   0x40002000
+#define NrfSerPtr0    ((nrfSerPtr) NrfSerBase0)
+
+#ifndef nrfGpioDef
+
+typedef struct _nrfGpio
+{
+  volatile  dword Reserve01;                // 000
+  volatile  dword OUT;                      // 004
+  volatile  dword OUTSET;                   // 008
+  volatile  dword OUTCLR;                   // 00C
+  volatile  dword IN;                       // 010
+  volatile  dword DIR;                      // 014
+  volatile  dword DIRSET;                   // 018
+  volatile  dword DIRCLR;                   // 01C
+  volatile  dword LATCH;                    // 020
+  volatile  dword DETECTMODE;               // 024
+  volatile  dword Reserve02[118];           // 026
+  volatile  dword PIN_CNF[32];              // 200
+} nrfGpio, *nrfGpioPtr;
+
+#define NrfGpioBase   0x50000000
+#define NrfGpioBase0  0x50000500
+#define NrfGpioPtr0   ((nrfGpioPtr) NrfGpioBase0)
+#define NrfGpioBase1  0x50000800
+#define NrfGpioPtr1   ((nrfGpioPtr) NrfGpioBase1)
+
+#define GpioPinCnf_DIROUT     ((dword) 0x00000001)
+
+#define GpioPinCnf_DISBUF     ((dword) 0x00000002)
+
+#define GpioPinCnf_PULL(x)    ((dword) x << 2)
+#define GpioPullDown          1
+#define GpioPullUp            3
+
+#define GpioPinCnf_DRIVE(x)   ((dword) x << 8)
+#define GpioDriveS0S1         0
+#define GpioDriveH0S1         1
+#define GpioDriveS0H1         2
+#define GpioDriveH0H1         3
+#define GpioDriveD0S1         4
+#define GpioDriveD0H1         5
+#define GpioDriveS0D1         6
+#define GpioDriveH0D1         7
+
+#define GpioPinCnf_SENSE(x)   ((dword) x << 16)
+#define GpioSenseHigh         2
+#define GpioSenseLow          3
+
+#define nrfGpioDef
+#endif
+
+// Festlegungen für die Paketkonfigurationsregister
+//
+
+#define SerInt_RXDRDY     ((dword) 0x00000001 << 2)
+// Interrupt für Event RXDRDY
+
+#define SerInt_TXDRDY     ((dword) 0x00000001 << 7)
+// Interrupt für Event TXDRDY
+
+#define SerInt_ERROR      ((dword) 0x00000001 << 9)
+// Interrupt für Event ERROR
+
+
+#define SerEnable   4
+#define SerDisable  0
+
+// Bit-Masken fuer Kommunikationsbedingungen
+//
+#define BM_REC_NOT_COND 0x00
+// Keine Bedingungen beim Empfang
+#define BM_REC_END_CHR  0x01
+// Empfang Stoppen beim Eintreffen des vorgegebenen Zeichens
+#define BM_REC_RINGBUF  0x02
+// Receive characters in ring buffer
+#define BM_SND_RINGBUF  0x04
+// Transmit characters via ring buffer
+
+
+
+// ----------------------------------------------------------------------------
+
+class nRF52840Ser : IntrfSerial
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten und Funktionen
+  // --------------------------------------------------------------------------
+  //
+  nrfSerPtr     serPtr;
+  dword         irqCounter;
+
+  int           lastError;
+  int           anyError;
+  dword         cntError;
+
+  int           curIRQ;
+  dword         curIntEn;
+
+  IntrfBuf      *bufIf;
+  bool          txdFin;       // TRUE = Sendevorgang beendet
+
+  void clrAllEvents();
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen der Basis-Klasse
+  // --------------------------------------------------------------------------
+
+  nRF52840Ser();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  void begin(SerParamsPtr serParPtr, IntrfBuf *bufferIf);
+
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void resuSend();    // Fortsetzen des Interrupt-Sendebetriebs
+  void startSend();   // Starten des Sendebetriebs
+  void stopSend();    // Anhalten des Sendebetriebs
+
+  void startRec();    // Starten des Empfangsbetriebs
+  void stopRec();     // Anhalten des Empfangsbetriebs
+
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  bool condSend(byte c);  // Bedingtes Senden eines Zeichens
+
+  int   getLastError();   // Letzten Fehler lesen (Bits)
+  int   getAnyError();    // Alle vorgekommenen Fehlerbits
+  dword getErrCount();    // Anzahl der Fehler lesen
+
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
+  static  nRF52840Ser *instPtr0;
+  static  void irqHandler0();
+
+  void    irqHandler();
+
+  // --------------------------------------------------------------------------
+  // lokale Variablen
+  // --------------------------------------------------------------------------
+  //
+
+
+  // ----------------------------------------------------------------------------
+  //                      D e b u g - H i l f e n
+  // ----------------------------------------------------------------------------
+  //
+  int           irqIdx;
+  int           irqList[8];
+
+  byte          extraValue;
+  bool          firstRead;
+
+  dword   getIrqCount();
+  void    resetIrqList();
+  void    getIrqList(char *dest);
+
+};
+
+#endif // NRF52840SER_H
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Twi/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Twi/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..16ae3922cdc02214ba2709422d1f9acfa86d132d
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Twi/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Twi",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Twi/nRF52840Twi.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Twi/nRF52840Twi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..81fdb263721b902935a3a21f952b214796e8c9d5
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Twi/nRF52840Twi.cpp
@@ -0,0 +1,586 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Radio.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#include "nRF52840Twi.h"
+#include <string.h>
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+
+nRF52840Twi::nRF52840Twi()
+{
+  twiPtr      = NULL;
+  instPtr0    = NULL;
+  instPtr1    = NULL;
+  irqCounter  = 0;
+}
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+//
+TwiError nRF52840Twi::begin(TwiParamsPtr inParPtr)
+{
+  TwiError    retv;
+  nrfGpioPtr  gpioPtr;
+  dword       regVal;
+
+  retv = TEnoError;
+
+  params = *inParPtr;
+
+  // Setzen des Peripheriezeigers anhand der Instanz
+  // und Initialisieren weiterer Variablen/Zeiger
+  //
+  if(inParPtr->inst == 0)
+  {
+    twiPtr    = NrfTwiPtr0;
+    clrAllEvents();
+    instPtr0  = this;
+    curIRQ    = 3;
+
+    // Interruptvektor setzen
+    //
+    __NVIC_SetVector((IRQn_Type) 3, (dword) nRF52840Twi::irqHandler0);
+    __NVIC_SetPriority((IRQn_Type) 3, 1);
+    __NVIC_EnableIRQ((IRQn_Type) 3);
+  }
+  else
+  {
+    twiPtr    = NrfTwiPtr1;
+    clrAllEvents();
+    instPtr1  = this;
+    curIRQ    = 4;
+
+    // Interruptvektor setzen
+    //
+    __NVIC_SetVector((IRQn_Type) 4, (dword) nRF52840Twi::irqHandler1);
+    __NVIC_SetPriority((IRQn_Type) 4, 1);
+    __NVIC_EnableIRQ((IRQn_Type) 4);
+  }
+
+  // Alternative Peripherie (gleiche ID, also Alles) abschalten
+  //
+  twiPtr->ENABLE = TwiDisable;
+
+
+  // Takt
+  // -------------------------------------------------
+  //
+  // Pins zuweisen und initialisieren
+  //
+  if(inParPtr->clkPort == 1)
+  {
+    regVal = 32 + inParPtr->clkPin;
+    gpioPtr = NrfGpioPtr1;
+  }
+  else
+  {
+    regVal = inParPtr->clkPin;
+    gpioPtr = NrfGpioPtr0;
+  }
+
+  // Connect (hoechstwertiges Bit) beruecksichtigen
+  //
+  twiPtr->PSEL_SCL = regVal | 0x7FFFFFC0;
+
+  // Zugewiesenen Pin als Eingang schalten und Treibermodus setzen
+  // Laut Datenblatt ist das entsprechende Bit im Konfigurationsregister
+  // mit dem DIR-Register physikalisch verbunden
+  //
+  gpioPtr->PIN_CNF[inParPtr->clkPin] = GpioPinCnf_DRIVE(GpioDriveS0D1);
+
+  // Daten
+  // -------------------------------------------------
+  //
+  if(inParPtr->dataPort == 1)
+  {
+    regVal = 32 + inParPtr->dataPin;
+    gpioPtr = NrfGpioPtr1;
+  }
+  else
+  {
+    regVal = inParPtr->dataPin;
+    gpioPtr = NrfGpioPtr0;
+  }
+
+  // Connect (hoechstwertiges Bit) beruecksichtigen
+  //
+  twiPtr->PSEL_SDA = regVal | 0x7FFFFFC0;
+
+  // Zugewiesenen Pin als Eingang schalten und Treibermodus setzen
+  // Laut Datenblatt ist das entsprechende Bit im Konfigurationsregister
+  // mit dem DIR-Register physikalisch verbunden
+  //
+  gpioPtr->PIN_CNF[inParPtr->dataPin] = GpioPinCnf_DRIVE(GpioDriveS0D1);
+
+  // Frequenz einstellen
+  //
+  if(inParPtr->speed == Twi100k)
+    regVal = NrfTwi100k;
+  else if(inParPtr->speed == Twi400k)
+    regVal = NrfTwi400k;
+  else
+    regVal = NrfTwi250k;
+
+  twiPtr->FREQUENCY = regVal;
+
+  twiPtr->SHORTS = 0;
+
+  // Interrupts freischalten
+  //
+  curIntEn = (TwiInt_TXDSENT | TwiInt_RXDREADY | TwiInt_ERROR | TwiInt_STOPPED);
+  twiPtr->INTENSET = curIntEn;
+
+  // Und bereit machen
+  //
+  twiPtr->ENABLE = TwiEnable;
+
+  delay(10);
+
+  return(retv);
+}
+
+
+void nRF52840Twi::getParams(TwiParamsPtr parPtr)
+{
+  *parPtr = params;
+}
+
+
+// ----------------------------------------------------------------------------
+// Steuerfunktionen, gezielte Prozessorzugriffe und Hilfsfunktionen
+// ----------------------------------------------------------------------------
+//
+void nRF52840Twi::clrAllEvents()
+{
+  twiPtr->EVENTS_STOPPED    = 0;
+  twiPtr->EVENTS_RXDREADY   = 0;
+  twiPtr->EVENTS_TXDSENT    = 0;
+  twiPtr->EVENTS_SUSPENDED  = 0;
+  twiPtr->EVENTS_BB         = 0;
+  twiPtr->EVENTS_ERROR      = 0;
+}
+
+// ----------------------------------------------------------------------------
+//                      M a s t e r
+// ----------------------------------------------------------------------------
+//
+
+  // --------------------------------------------------------------------------
+  // Datenaustausch
+  // --------------------------------------------------------------------------
+  //
+TwiError nRF52840Twi::sendByte(int adr, TwiBytePtr refByte)
+{
+  TwiError retv = TEnoError;
+  lastError     = 0;
+
+  resetIrqList();
+
+  byteStruPtr     = refByte;
+  twiPtr->ADDRESS = adr;
+
+  byteStruPtr->twiStatus  = TwStWrReq;
+  trfMode                 = ttmWriteByte;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = refByte->value;
+
+  return(retv);
+}
+
+TwiError nRF52840Twi::sendByteReg(int adr, int reg, TwiBytePtr refByte)
+{
+  TwiError retv = TEnoError;
+
+  //dynHand = &nRF52840Twi::irqHandler;
+
+  resetIrqList();
+
+  byteStruPtr     = refByte;
+  twiPtr->ADDRESS = adr;
+
+  byteStruPtr->twiStatus  = TwStWrReq;
+  trfMode                 = ttmWriteByteReg;
+  comIdx                  = 1;
+  irqIdx                  = 0;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = reg;
+
+  return(retv);
+}
+
+TwiStatus nRF52840Twi::writeByteReg(int adr, int reg, byte value)
+{
+  twiPtr->INTENCLR = curIntEn;
+
+  tmpByte.value = value;
+
+  sendByteReg(adr, reg, &tmpByte);
+
+  while(tmpByte.twiStatus != TwStFin)
+  {
+    irqHandler();
+
+    if(tmpByte.twiStatus & TwStError)
+      break;
+  }
+
+  twiPtr->INTENSET = curIntEn;
+
+  return(tmpByte.twiStatus);
+}
+
+
+TwiError nRF52840Twi::recByteReg(int adr, int reg, TwiBytePtr refByte)
+{
+  TwiError retv = TEnoError;
+
+  //dynHand = &nRF52840Twi::irqHandler;
+
+  byteStruPtr     = refByte;
+  twiPtr->ADDRESS = adr;
+
+  resetIrqList();
+
+  byteStruPtr->twiStatus  = TwStRdReq;
+  trfMode                 = ttmReadByteReg;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = reg;
+
+  return(retv);
+}
+
+int nRF52840Twi::readByteReg(int adr, int reg)
+{
+  twiPtr->INTENCLR = curIntEn;
+
+  recByteReg(adr, reg, &tmpByte);
+
+  while(tmpByte.twiStatus != TwStFin)
+  {
+    irqHandler();
+
+    if(tmpByte.twiStatus & TwStError)
+      break;
+  }
+
+  twiPtr->INTENSET = curIntEn;
+
+  if(tmpByte.twiStatus == TwStFin)
+    return(tmpByte.value);
+  else
+    return(-1);
+}
+
+
+TwiError nRF52840Twi::recByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq)
+{
+  TwiError retv = TEnoError;
+
+  byteSeqPtr      = refByteSeq;
+  comIdx          = 0;
+  twiPtr->ADDRESS = adr;
+
+  byteSeqPtr->twiStatus   = TwStRdReq;
+  trfMode                 = ttmReadByteRegSeq;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = reg;
+
+  return(retv);
+}
+
+TwiStatus nRF52840Twi::readByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq)
+{
+  byteSeqPtr      = refByteSeq;
+  comIdx          = 0;
+  twiPtr->ADDRESS = adr;
+
+  byteSeqPtr->twiStatus   = TwStRdReq;
+  trfMode                 = ttmReadByteRegSeq;
+
+  twiPtr->INTENCLR        = curIntEn;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = reg;
+
+  while(byteSeqPtr->twiStatus != TwStFin)
+  {
+    irqHandler();
+
+    if(byteSeqPtr->twiStatus & TwStError)
+      break;
+  }
+
+  twiPtr->INTENSET        = curIntEn;
+
+  return(byteSeqPtr->twiStatus);
+}
+
+// ----------------------------------------------------------------------------
+// Ereignisbearbeitung und Interrupts
+// ----------------------------------------------------------------------------
+//
+nRF52840Twi *nRF52840Twi::instPtr0 = NULL;
+
+void nRF52840Twi::irqHandler0()
+{
+  if(instPtr0 == NULL) return;
+  instPtr0->irqCounter++;
+  instPtr0->irqHandler();
+}
+
+nRF52840Twi *nRF52840Twi::instPtr1 = NULL;
+
+void nRF52840Twi::irqHandler1()
+{
+  if(instPtr1 == NULL) return;
+  instPtr1->irqCounter++;
+  instPtr1->irqHandler();
+}
+
+
+  // --------------------------------------------------------------------------
+  // Interrupts (Ereignisbehandlung)
+  // --------------------------------------------------------------------------
+  //
+void nRF52840Twi::irqHandler()
+{
+  switch(trfMode)
+  {
+    case ttmWriteByte:
+    // ------------------------------------------------------------------------
+
+      if(twiPtr->EVENTS_ERROR)
+      {
+        twiPtr->EVENTS_ERROR    = 0;
+        lastError               = twiPtr->ERRORSRC;
+        twiPtr->ERRORSRC        = (lastError & 0x06);   // Clear AdrNak/DataNak
+        byteStruPtr->twiStatus  = (TwiStatus) ( (int) TwStError + lastError);
+        twiPtr->TASKS_STOP      = 1;
+
+        irqList[irqIdx++] = 8;
+        return;
+      }
+
+      if(twiPtr->EVENTS_TXDSENT)
+      {
+        twiPtr->EVENTS_TXDSENT   = 0;
+        byteStruPtr->twiStatus   = TwStSent;
+        twiPtr->TASKS_STOP       = 1;
+
+        irqList[irqIdx++] = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_STOPPED)
+      {
+        twiPtr->EVENTS_STOPPED  = 0;
+        if(lastError == 0)
+          byteStruPtr->twiStatus  = TwStFin;
+
+        irqList[irqIdx++] = 3;
+        return;
+      }
+
+      break;
+
+    case ttmWriteByteReg:
+    // ------------------------------------------------------------------------
+
+      if(twiPtr->EVENTS_ERROR)
+      {
+        twiPtr->EVENTS_ERROR    = 0;
+        lastError               = twiPtr->ERRORSRC;
+        twiPtr->ERRORSRC        = (lastError & 0x06);   // Clear AdrNak/DataNak
+        byteStruPtr->twiStatus  = (TwiStatus) ( (int) TwStError + lastError);
+        twiPtr->TASKS_STOP      = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_TXDSENT)
+      {
+        twiPtr->EVENTS_TXDSENT   = 0;
+        byteStruPtr->twiStatus   = TwStSent;
+        if(comIdx == 1)
+        {
+          comIdx = 0;
+          twiPtr->TXD = byteStruPtr->value;
+        }
+        else
+          twiPtr->TASKS_STOP    = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_STOPPED)
+      {
+        twiPtr->EVENTS_STOPPED  = 0;
+        if(lastError == 0)
+          byteStruPtr->twiStatus  = TwStFin;
+        return;
+      }
+
+      break;
+
+    case ttmReadByteReg:
+    // ------------------------------------------------------------------------
+
+      if(twiPtr->EVENTS_ERROR)
+      {
+        twiPtr->EVENTS_ERROR    = 0;
+        lastError               = twiPtr->ERRORSRC;
+        twiPtr->ERRORSRC        = (lastError & 0x06);   // Clear AdrNak/DataNak
+        byteStruPtr->twiStatus  = (TwiStatus) ( (int) TwStError + lastError);
+        twiPtr->TASKS_STOP      = 1;
+
+        irqList[irqIdx++] = 8;
+        return;
+      }
+
+      if(twiPtr->EVENTS_TXDSENT)
+      {
+        twiPtr->EVENTS_TXDSENT  = 0;
+        byteStruPtr->twiStatus  = TwStSent;
+        twiPtr->TASKS_STARTRX   = 1;
+        twiPtr->SHORTS          = 2;
+
+        irqList[irqIdx++] = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_STOPPED)
+      {
+        twiPtr->EVENTS_STOPPED  = 0;
+        if(lastError == 0)
+          byteStruPtr->twiStatus  = TwStFin;
+
+        irqList[irqIdx++] = 3;
+        twiPtr->SHORTS = 0;
+        return;
+      }
+
+      if(twiPtr->EVENTS_RXDREADY)
+      {
+        twiPtr->EVENTS_RXDREADY = 0;
+        byteStruPtr->twiStatus  = TwStRecvd;
+        byteStruPtr->value      = twiPtr->RXD;
+
+        irqList[irqIdx++] = 2;
+        return;
+      }
+
+      break;
+
+    case ttmReadByteRegSeq:
+    // ------------------------------------------------------------------------
+
+      if(twiPtr->EVENTS_ERROR)
+      {
+        twiPtr->EVENTS_ERROR    = 0;
+        lastError               = twiPtr->ERRORSRC;
+        twiPtr->ERRORSRC        = (lastError & 0x06);   // Clear AdrNak/DataNak
+        byteSeqPtr->twiStatus   = (TwiStatus) ( (int) TwStError + lastError);
+        twiPtr->TASKS_STOP      = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_TXDSENT)
+      {
+        twiPtr->EVENTS_TXDSENT  = 0;
+        byteSeqPtr->twiStatus   = TwStSent;
+        twiPtr->TASKS_STARTRX   = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_STOPPED)
+      {
+        twiPtr->EVENTS_STOPPED   = 0;
+        if(lastError == 0)
+          byteSeqPtr->twiStatus  = TwStFin;
+        twiPtr->SHORTS = 0;
+        return;
+      }
+
+      if(twiPtr->EVENTS_RXDREADY)
+      {
+        twiPtr->EVENTS_RXDREADY       = 0;
+        byteSeqPtr->twiStatus         = TwStRecvd;
+        /*
+        if(comIdx == (byteSeqPtr->len - 2))
+          twiPtr->SHORTS              = 2;
+        byteSeqPtr->valueRef[comIdx]  = twiPtr->RXD;
+        if(comIdx < (byteSeqPtr->len - 1))
+          comIdx++;
+        */
+        if(comIdx == (byteSeqPtr->len - 2))
+          twiPtr->SHORTS              = 2;
+
+        lastIn = twiPtr->RXD;
+
+        if(comIdx < (byteSeqPtr->len))
+          byteSeqPtr->valueRef[comIdx]  = lastIn;
+
+        comIdx++;
+        return;
+      }
+
+      break;
+
+  }
+}
+
+// ----------------------------------------------------------------------------
+//                      S l a v e
+// ----------------------------------------------------------------------------
+
+// Starten des Datenempfangs
+//
+
+// ----------------------------------------------------------------------------
+//                      D e b u g - H i l f e n
+// ----------------------------------------------------------------------------
+//
+dword nRF52840Twi::getIrqCount()
+{
+  return(irqCounter);
+}
+
+void nRF52840Twi::resetIrqList()
+{
+  irqIdx = 0;
+  firstRead = true;
+
+  for(int i = 0; i < 8; i++)
+    irqList[i] = 0;
+}
+
+void nRF52840Twi::getIrqList(char *dest)
+{
+  int destIdx = 0;
+
+  for(int i = 0; i < 8; i++)
+  {
+    if(irqList[i] == 0) break;
+
+    dest[destIdx++] = ' ';
+    dest[destIdx++] = irqList[i] + 0x30;
+  }
+
+  dest[destIdx] = '\0';
+}
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Twi/nRF52840Twi.h b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Twi/nRF52840Twi.h
new file mode 100644
index 0000000000000000000000000000000000000000..e33ca74b72c254311a695ab5ea7fd3152a8ebf4d
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/nRF52840Twi/nRF52840Twi.h
@@ -0,0 +1,250 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Twi.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef NRF52840TWI_H
+#define NRF52840TWI_H
+
+#include "Arduino.h"
+#include "arduinoDefs.h"
+#include "IntrfTw.h"
+
+// ----------------------------------------------------------------------------
+
+typedef struct _nrfTwi
+{
+  volatile  dword  TASKS_STARTRX;           // 000
+  volatile  dword  Reserve01;               // 004
+  volatile  dword  TASKS_STARTTX;           // 008
+  volatile  dword  Reserve02[2];            // 00C
+  volatile  dword  TASKS_STOP;              // 014
+  volatile  dword  Reserve03;               // 018
+  volatile  dword  TASKS_SUSPEND;           // 01C
+  volatile  dword  TASKS_RESUME;            // 020
+  volatile  dword  Reserve04[56];           // 024
+  volatile  dword  EVENTS_STOPPED;          // 104
+  volatile  dword  EVENTS_RXDREADY;         // 108
+  volatile  dword  Reserve05[4];            // 118
+  volatile  dword  EVENTS_TXDSENT;          // 11C
+  volatile  dword  Reserve06;               // 120
+  volatile  dword  EVENTS_ERROR;            // 124
+  volatile  dword  Reserve07[4];            // 128
+  volatile  dword  EVENTS_BB;               // 138
+  volatile  dword  Reserve08[3];            // 13C
+  volatile  dword  EVENTS_SUSPENDED;        // 148
+  volatile  dword  Reserve09[45];           // 14C
+  volatile  dword  SHORTS;                  // 200
+  volatile  dword  Reserve10[64];           // 204
+  volatile  dword  INTENSET;                // 304
+  volatile  dword  INTENCLR;                // 308
+  volatile  dword  Reserve11[110];          // 30C
+  volatile  dword  ERRORSRC;                // 4C4
+  volatile  dword  Reserve12[14];           // 4C8
+  volatile  dword  ENABLE;                  // 500
+  volatile  dword  Reserve13;               // 504
+  volatile  dword  PSEL_SCL;                // 508
+  volatile  dword  PSEL_SDA;                // 50C
+  volatile  dword  Reserve14[2];            // 510
+  volatile  dword  RXD;                     // 518
+  volatile  dword  TXD;                     // 51C
+  volatile  dword  Reserve15;               // 520
+  volatile  dword  FREQUENCY;               // 524
+  volatile  dword  Reserve16[24];           // 528
+  volatile  dword  ADDRESS;                 // 588
+} nrfTwi, *nrfTwiPtr;
+
+#define NrfTwiBase0   0x40003000
+#define NrfTwiPtr0    ((nrfTwiPtr) NrfTwiBase0)
+#define NrfTwiBase1   0x40004000
+#define NrfTwiPtr1    ((nrfTwiPtr) NrfTwiBase1)
+
+#define NrfTwi100k    0x01980000
+#define NrfTwi250k    0x04000000
+#define NrfTwi400k    0x06680000
+
+typedef enum _TwiTrfMode
+{
+  ttmWriteByte = 1,
+  ttmWriteByteReg,
+  ttmReadByteReg,
+  ttmReadByteRegSeq
+} TwiTrfMode;
+
+#ifndef nrfGpioDef
+
+typedef struct _nrfGpio
+{
+  volatile  dword Reserve01;                // 000
+  volatile  dword OUT;                      // 004
+  volatile  dword OUTSET;                   // 008
+  volatile  dword OUTCLR;                   // 00C
+  volatile  dword IN;                       // 010
+  volatile  dword DIR;                      // 014
+  volatile  dword DIRSET;                   // 018
+  volatile  dword DIRCLR;                   // 01C
+  volatile  dword LATCH;                    // 020
+  volatile  dword DETECTMODE;               // 024
+  volatile  dword Reserve02[118];           // 026
+  volatile  dword PIN_CNF[32];              // 200
+} nrfGpio, *nrfGpioPtr;
+
+#define NrfGpioBase   0x50000000
+#define NrfGpioBase0  0x50000500
+#define NrfGpioPtr0   ((nrfGpioPtr) NrfGpioBase0)
+#define NrfGpioBase1  0x50000800
+#define NrfGpioPtr1   ((nrfGpioPtr) NrfGpioBase1)
+
+#define GpioPinCnf_DIR        ((dword) 0x00000001)
+
+#define GpioPinCnf_INPUT      ((dword) 0x00000001 << 1)
+
+#define GpioPinCnf_PULL(x)    ((dword) x << 2)
+#define GpioPullDown          1
+#define GpioPullUp            3
+
+#define GpioPinCnf_DRIVE(x)   ((dword) x << 8)
+#define GpioDriveS0S1         0
+#define GpioDriveH0S1         1
+#define GpioDriveS0H1         2
+#define GpioDriveH0H1         3
+#define GpioDriveD0S1         4
+#define GpioDriveD0H1         5
+#define GpioDriveS0D1         6
+#define GpioDriveH0D1         7
+
+#define GpioPinCnf_SENSE(x)   ((dword) x << 16)
+#define GpioSenseHigh         2
+#define GpioSenseLow          3
+
+#define nrfGpioDef
+#endif
+
+// Festlegungen für die Paketkonfigurationsregister
+//
+
+#define TwiInt_STOPPED    ((dword) 0x00000001 << 1)
+// Interrupt für Event STOPPED
+
+#define TwiInt_RXDREADY   ((dword) 0x00000001 << 2)
+// Interrupt für Event RXDREADY
+
+#define TwiInt_TXDSENT    ((dword) 0x00000001 << 7)
+// Interrupt für Event TXDSENT
+
+#define TwiInt_ERROR      ((dword) 0x00000001 << 9)
+// Interrupt für Event ERROR
+
+#define TwiInt_BB         ((dword) 0x00000001 << 14)
+// Interrupt für Event BB
+
+#define TwiInt_SUSPENDED  ((dword) 0x00000001 << 18)
+// Interrupt für Event SUSPENDED
+
+#define TwiEnable   5
+#define TwiDisable  0
+
+
+
+
+// ----------------------------------------------------------------------------
+
+class nRF52840Twi : IntrfTw
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten und Funktionen
+  // --------------------------------------------------------------------------
+  //
+  nrfTwiPtr     twiPtr;
+  dword         irqCounter;
+
+  TwiBytePtr    byteStruPtr;
+  TwiWordPtr    wordStruPtr;
+  TwiByteSeqPtr byteSeqPtr;
+
+  TwiTrfMode    trfMode;
+  dword         lastError;
+  byte          lastIn;
+  int           comIdx;
+
+  int           curIRQ;
+  dword         curIntEn;
+
+  TwiByte       tmpByte;
+
+  TwiParams     params;
+
+  void clrAllEvents();
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen der Basis-Klasse
+  // --------------------------------------------------------------------------
+
+  nRF52840Twi();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  TwiError begin(TwiParamsPtr inParPtr);
+  void getParams(TwiParamsPtr parPtr);
+
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Datenaustausch
+  // --------------------------------------------------------------------------
+  //
+  // asynchrone Kommunikation, Zustand in TwiByte.twiStatus
+  //
+  TwiError sendByte(int adr, TwiBytePtr refByte);
+  TwiError sendByteReg(int addr, int reg, TwiBytePtr refByte);
+  TwiError recByteReg(int addr, int reg, TwiBytePtr refByte);
+  TwiError recByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq);
+
+  // synchrone Kommunikation
+  //
+  TwiStatus writeByteReg(int adr, int reg, byte value);
+  int       readByteReg(int adr, int reg);
+  TwiStatus readByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq);
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
+  static  nRF52840Twi *instPtr0;
+  static  void irqHandler0();
+
+  static  nRF52840Twi *instPtr1;
+  static  void irqHandler1();
+
+  void    irqHandler();
+
+  // ----------------------------------------------------------------------------
+  //                      D e b u g - H i l f e n
+  // ----------------------------------------------------------------------------
+  //
+  int           irqIdx;
+  int           irqList[8];
+
+  byte          extraValue;
+  bool          firstRead;
+
+  dword   getIrqCount();
+  void    resetIrqList();
+  void    getIrqList(char *dest);
+
+};
+
+#endif // NRF52840RADIO_H
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/template_platformio.txt b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/template_platformio.txt
new file mode 100644
index 0000000000000000000000000000000000000000..15fc69d85e05ee9d499f73ed91bde12711b55562
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/template_platformio.txt
@@ -0,0 +1,59 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+	
+[env:Logging]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM3
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33 -DsmnDEBUG
+lib_deps = 
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
+monitor_filters =
+  default   ; Remove typical terminal control codes from input
+  time      ; Add timestamp with milliseconds for each new line
+  log2file  ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/test/README b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/test/README
new file mode 100644
index 0000000000000000000000000000000000000000..9b1e87bc67c90e7f09a92a3e855444b085c655a6
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/test/README
@@ -0,0 +1,11 @@
+
+This directory is intended for PlatformIO Test Runner and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PlatformIO Unit Testing:
+- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/.vscode/extensions.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/.vscode/extensions.json
new file mode 100644
index 0000000000000000000000000000000000000000..080e70d08b9811fa743afe5094658dba0ed6b7c2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/.vscode/extensions.json
@@ -0,0 +1,10 @@
+{
+    // See http://go.microsoft.com/fwlink/?LinkId=827846
+    // for the documentation about the extensions.json format
+    "recommendations": [
+        "platformio.platformio-ide"
+    ],
+    "unwantedRecommendations": [
+        "ms-vscode.cpptools-extension-pack"
+    ]
+}
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/README.md b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..629d5c9a969b8193a9fb1ec9fd4df89bb5e23681
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/README.md
@@ -0,0 +1,2 @@
+Projektsnapshot der mit alten Versionen der Bibliotheken läuft.
+Die Versionen sind hier direkt im Projektverzeichnis gespeichert.
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/include/README b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/include/README
new file mode 100644
index 0000000000000000000000000000000000000000..194dcd43252dcbeb2044ee38510415041a0e7b47
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/include/README
@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/lib/README b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/lib/README
new file mode 100644
index 0000000000000000000000000000000000000000..6debab1e8b4c3faa0d06f4ff44bce343ce2cdcbf
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/lib/README
@@ -0,0 +1,46 @@
+
+This directory is intended for project specific (private) libraries.
+PlatformIO will compile them to static libraries and link into executable file.
+
+The source code of each library should be placed in a an own separate directory
+("lib/your_library_name/[here are source files]").
+
+For example, see a structure of the following two libraries `Foo` and `Bar`:
+
+|--lib
+|  |
+|  |--Bar
+|  |  |--docs
+|  |  |--examples
+|  |  |--src
+|  |     |- Bar.c
+|  |     |- Bar.h
+|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
+|  |
+|  |--Foo
+|  |  |- Foo.c
+|  |  |- Foo.h
+|  |
+|  |- README --> THIS FILE
+|
+|- platformio.ini
+|--src
+   |- main.c
+
+and a contents of `src/main.c`:
+```
+#include <Foo.h>
+#include <Bar.h>
+
+int main (void)
+{
+  ...
+}
+
+```
+
+PlatformIO Library Dependency Finder will find automatically dependent
+libraries scanning project source files.
+
+More information about PlatformIO Library Dependency Finder
+- https://docs.platformio.org/page/librarymanager/ldf.html
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/platformio.ini b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/platformio.ini
new file mode 100644
index 0000000000000000000000000000000000000000..bcf5898434bb08619b2e8f18f2bf32500807e6e1
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/platformio.ini
@@ -0,0 +1,32 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM5
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33  -DsmnDEBUG ;-DSlaveACM3
+lib_deps = 
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\BlePoll
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\environment
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\ComRingBuf
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\LoopCheck
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\MidiNotes
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\Monitor
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Gpio
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Radio
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Ser
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\nRF52840Twi
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SensorLSM9DS1
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\SoaapMsg
+	;symlink://C:\Users\Lennard\Documents\Git_local\REP_STR\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/BlePoll/BlePoll.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/BlePoll/BlePoll.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2b89ae3d67d527cf753ec12a685ac02e0bde3ae
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/BlePoll/BlePoll.cpp
@@ -0,0 +1,1624 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   BlePoll.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. September 2021
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Kommunikation
+// über BLE-Funkmodule auf niedriger Ebene, also dem direkten Telegrammaustausch.
+// Darauf aufbauend sollen mehrkanalige Messeinrichtungen mit möglichst
+// geringen Latenzzeiten entwickelt werden.
+//
+
+#include "BlePoll.h"
+
+// --------------------------------------------------------------------------
+// Textmakros zur Vereinfachung der Programmierung
+// --------------------------------------------------------------------------
+
+#define next(x) nextState = &BlePoll::x
+
+// --------------------------------------------------------------------------
+// Initialisierungen
+// --------------------------------------------------------------------------
+
+BlePoll::BlePoll(IntrfRadio *refRadio, dword inCycleMics)
+{
+  init(refRadio, inCycleMics, NULL);
+}
+
+BlePoll::BlePoll(IntrfRadio *refRadio, MicsecFuPtr inMicroFu)
+{
+  init(refRadio, 0, inMicroFu);
+}
+
+void BlePoll::init(IntrfRadio *refRadio, dword inCycleMics, MicsecFuPtr inMicroFu)
+{
+  radio = refRadio;
+  radio->setPacketParms(bptAdv);
+  radio->setAccessAddress(AdvAccAddr);
+  chn = adr = area = 0;
+  master = nak = eadr = false;
+  plMode = plmIdle;
+  plpType = plptEmpty;
+  micSec = inMicroFu;
+  cycleMics = inCycleMics;
+  cycleCnt = 0;
+  toValue = 0;
+  toSet = 0;
+  nextState = NULL;
+  slaveIdx = 0;
+  pollIdx = 0;
+  pollNr = 0;
+  maxAdr = MAXSLAVE;
+  curSlave = NULL;
+  cntAlien = 0;
+  cntWrong = 0;
+  cntAllNaks = 0;
+  cntWaitDisabled = 0;
+  cntPolling = 0;
+  cntAllRecs = 0;
+  cntAllTo = 0;
+  pollStopped = false;
+  pollStop = false;
+  recStopped = false;
+  recStop = false;
+  runCounter = 0;
+  newValue = false;
+  cbData = NULL;
+
+  for(int i = 1; i <= MAXSLAVE; i++)
+  {
+    slaveList[i].cntNakEP = 0;
+    slaveList[i].cntTo = 0;
+    slaveList[i].pIdx = 0;
+    slaveList[i].delayCnt = 5;
+    slaveList[i].newPdu = false;
+    slaveList[i].newMeas = false;
+    pollList[i].prioCnt = 0;
+    pollList[i].slIdx = 0;
+    pollList[i].status = 0;
+  }
+
+  DataExchange = false;
+}
+
+// ----------------------------------------------------------------------------
+void BlePoll::begin(ComType typeIn, int adrIn, AppType appType, dword watchDog)
+{
+  // TODO
+  // --------------------------------------------------------------------------
+  // Das muss nochmal völlig neu überarbeitet werden.
+  // Zur Zeit sind viele Redundanzen und teilweise Mehrdeutigkeiten enthalten,
+  // weil für jede Testanwendung spezifische Vorbereitungen gemacht wurden.
+  // --------------------------------------------------------------------------
+  //
+  wdTimeOut = watchDog;   // WatchDog-Time-Out in Mikrosekunden
+
+  if(typeIn == ctMASTER)
+    master  = true;
+  else
+    master = false;  void  resetPollCounters();
+
+
+  chn     = 0;          // 1. Bewerbungskanal
+  area    = 0;          // Default-Anwendungsbereich
+  eadr    = true;       // Start mit leerem Polling
+
+  // --------------------------------------------------------------------------
+  plMode  = plmEmpty;   // Leeres Polling (Adressenliste)
+  // --------------------------------------------------------------------------
+
+  if(master)
+  {
+    nak = true;         // Nak-Bit vom Master forciert leere Antwort
+    maxAdr = adrIn;
+    if(maxAdr > MAXSLAVE)
+      maxAdr = MAXSLAVE;
+    adr  = 1;
+    slaveIdx = adr;     // Reserve für getrennte Verwaltung von adr und slaveIdx
+    next(smInit);
+  }
+  else
+  {
+    nak = true;
+    adr = adrIn;
+    next(smInit);
+  }
+
+  if(appType == atSOAAP || appType == atTestSend || appType == atDevSOAAP)
+  {
+    pduOut.adr5 = 0x53;
+    pduOut.adr4 = 0x4F;
+    pduOut.adr3 = 0x41;
+
+    pduIn.adr5 = 0x53;
+    pduIn.adr4 = 0x4F;
+    pduIn.adr3 = 0x41;
+  }
+
+  if(appType == atTestSend)
+    plMode = plmTest;
+
+  pduOut.head = HeadS0B;
+  pduIn.head = HeadS0B;
+
+  pduOut.data[0] = 0;         // Pdu-Zähler (CNT)
+  pduIn.data[0] = 0;
+
+  pduOut.data[1] = appType;   // Pdu-Typ (TYPE)
+  pduIn.data[1] = appType;
+
+  if(appType == atSOAAP)
+  {
+    if(master)
+    {
+      valuePdu.appId = plptMeas9Ctrl4;
+      ctrlPdu.appId = plptCtrlX;
+      plMode = plmSoaapM;
+      fullCycle = true;
+    }
+    else
+    {
+      valuePdu.appId = plptMeas9Ctrl4;
+      ctrlPdu.appId = plptCtrlX;
+      plMode = plmSoaapS;
+    }
+  }
+  else if (appType == atDevSOAAP)
+  {
+    if(master)
+    {
+      valuePdu.appId = plptMeas13;
+      ctrlPdu.appId = plptCtrl2;
+      plMode = plmSoaapM;
+      fullCycle = true;
+    }
+    else
+    {
+      valuePdu.appId = plptMeas13;
+      ctrlPdu.appId = plptCtrl2;
+      plMode = plmSoaapS;
+    }
+  }
+
+  valuePdu.measCnt = 0;
+  valuePdu.counter = 0;
+  valuePdu.type = appType;
+}
+
+
+// --------------------------------------------------------------------------
+// Konfiguration
+// --------------------------------------------------------------------------
+//
+void BlePoll::setPollAddress(int chnIn, int adrIn, int areaIn, bool masterIn, bool eadrIn, bool nakIn)
+{
+  chn     = chnIn;
+  adr     = adrIn;
+  area    = areaIn;
+  master  = masterIn;
+  eadr    = eadrIn;
+  nak     = nakIn;
+}
+
+void BlePoll::setPduAddress()
+{
+  setPduAddress(&pduOut);
+}
+
+void BlePoll::setPduAddress(bcPduPtr pduPtr)
+{
+  pduPtr->adr0 = (byte) adr;
+  pduPtr->adr1 = (byte) (area & 0x3F);
+  if(nak) pduPtr->adr1 |= 0x40;
+  if(eadr) pduPtr->adr1 |= 0x80;
+  pduPtr->adr2 = (byte) chn;
+  if(master) pduPtr->adr2 |= 0x80;
+}
+
+void BlePoll::setEmptyPollParams(int cycleTotal, int cycleRun, dword timeOut)
+{
+  epCycleTotal  = cycleTotal;
+  epCycleRun    = cycleRun;
+  epTimeOut     = timeOut;
+}
+
+void BlePoll::setDataPollParams(int slAdr, int prio, int minPrio, dword timeOut)
+{
+  if(slAdr > MAXSLAVE) return;
+  slaveList[slAdr].prioSet = prio;
+  slaveList[slAdr].minPrio = minPrio;
+  slaveList[slAdr].timeOut = timeOut;
+}
+
+void BlePoll::setCbDataPtr(cbDataPtr cbPtr)
+{
+  cbData = cbPtr;
+}
+
+void BlePoll::setCbCtrlPtr(cbCtrlPtr cbPtr)
+{
+  cbCtrl = cbPtr;
+}
+
+
+dword smStartComESCnt;
+bcPdu recBeacon;
+int   lenBeacon = 0;
+
+// --------------------------------------------------------------------------
+// Hilfsfunktionen
+// --------------------------------------------------------------------------
+//
+void BlePoll::setTimeOut(dword value)
+{
+  if(micSec != NULL)
+  {
+    toSet = micSec();
+    toValue = value;
+  }
+  else
+  {
+    if(cycleMics > 1)
+      cycleCnt = value / cycleMics;
+    else
+      cycleCnt = value;
+  }
+}
+
+bool BlePoll::timeOut()
+{
+  if(micSec != NULL)
+  {
+    if((micSec() - toSet) > toValue)
+      return(true);
+    else
+      return(false);
+  }
+  else
+  {
+    if(cycleCnt > 0)
+      return(false);
+    else
+      return(true);
+  }
+}
+
+bool BlePoll::getValues(bcPduPtr pduPtr, PlpType appId)
+{
+  bool  retv = false;
+
+  switch (appId)
+  {
+    case plptMeas6:
+      pduPtr->len = sizeof(PlpMeas6) + 6;
+      break;
+
+    case plptMeas9Ctrl4:
+      pduPtr->len = sizeof(PlpM9C4) + 6;
+      break;
+  }
+  pduPtr->data[0]++;      // Pdu-Counter
+  pduPtr->data[1] = valuePdu.type;
+  pduPtr->data[2] = appId;
+
+  newValue = cbData(appId, &pduPtr->data[4]);
+
+  if(newValue)
+  {
+    retv = true;
+    pduPtr->data[3]++;              // measCnt
+  }
+  return(retv);
+}
+
+
+bool BlePoll::getCtrls(bcPduPtr pduPtr, PlpType appId)
+{
+  int   ctrlLen;
+
+  if(recBeacon.len > 6)
+    ctrlLen = recBeacon.len - 6;
+  else
+    ctrlLen = 4;
+
+  newCtrl = cbCtrl((PlpType) appId, &pduPtr->data[22], &recBeacon.data[0], ctrlLen);
+
+  return(newCtrl);
+}
+
+
+// --------------------------------------------------------------------------
+// Steuerung des Polling
+// --------------------------------------------------------------------------
+//
+
+// Aktuellen Betriebszustand einstellen
+//
+void BlePoll::start(PlMode inPlMode)
+{
+  oldPlMode = plMode;
+  plMode = inPlMode;
+  pollStop = true;
+}
+
+// Anhalten des leeren Polling
+//
+void BlePoll::stopEP()
+{
+  pollStop = true;
+}
+
+// Weiterlaufen des leeren Polling
+//
+void BlePoll::resumeEP()
+{
+  pollStop    = false;
+  pollStopped = false;
+}
+
+// Abfrage, ob gestoppt
+//
+bool BlePoll::stoppedEP()
+{
+  return(pollStopped);
+}
+
+// Anhalten des Empfangs beim Slave
+//
+void BlePoll::stopSR()
+{
+  recStop = true;
+}
+
+// Weiterlaufen des Empfangs beim Slave
+//
+void BlePoll::resumeSR()
+{
+  recStop     = false;
+  recStopped  = false;
+}
+
+// Abfrage, ob Slaveempfang gestoppt
+//
+bool BlePoll::stoppedSR()
+{
+  return(recStopped);
+}
+
+
+// Eintritt in die Zustandsmaschine
+//
+void BlePoll::run()
+{
+  runCounter++;
+  if(cycleCnt > 0) cycleCnt--;
+
+  if(nextState != NULL)
+    (this->*nextState)();
+}
+
+// --------------------------------------------------------------------------
+// Zugriff auf Polling-Informationen
+// --------------------------------------------------------------------------
+//
+int BlePoll::getSlaveList(byte *dest, int maxByte)
+{
+  int           slIdx;
+
+  for(int i = 1; i <= pollMaxNr; i++)
+  {
+    if(i == maxByte) break;
+    slIdx = pollList[i].slIdx;
+    dest[i-1] = slaveList[slIdx].adr;
+  }
+  return(pollMaxNr);
+}
+
+void  BlePoll::resetPollCounters()
+{
+  int           slIdx;
+  SlavePtr      slPtr;
+
+  for(int i = 1; i <= pollMaxNr; i++)
+  {
+    slIdx = pollList[i].slIdx;
+    slPtr = &slaveList[slIdx];
+    slPtr->cntAckDP = 0;
+    slPtr->cntErrCrc = 0;
+    slPtr->cntLostMeas = 0;
+    slPtr->cntLostPdu = 0;
+    slPtr->cntNakEP = 0;
+    slPtr->cntTo = 0;
+  }
+}
+
+
+
+
+// ****************************************************************************
+// Zustandsmaschine
+// ****************************************************************************
+//
+
+// ----------------------------------------------------------------------------
+// Verzweigung nach Anwendung (nach Anlauf)
+// ----------------------------------------------------------------------------
+//
+dword smInitCnt;
+
+void BlePoll::smInit()
+{
+  bleState = 100;
+  smInitCnt++;
+
+  switch(plMode)
+  {
+    case plmIdle:
+      break;
+
+    case plmTest:
+      next(smStartTest);
+      break;
+
+    case plmEmpty:
+      epCycleTotal = -1;
+      epCycleRun = -1;
+      next(smStartEP);
+      break;
+
+    case plmScan:
+      break;
+
+    case plmSoaapM:
+      if(pollStop)
+        pollStopped = true;
+      if(!pollStopped)
+        next(smStartEP);
+      break;
+
+    case plmSoaapS:
+      next(smStartComES);
+      break;
+
+    case plmXchg:
+      break;
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Verzweigung nach Anwendung (im Betrieb)
+// ----------------------------------------------------------------------------
+//
+dword smIdleCnt;
+
+void BlePoll::smIdle()
+{
+  bleState = 200;
+  smIdleCnt++;
+
+  switch(plMode)
+  {
+    case plmIdle:
+      break;
+
+    case plmTest:
+      next(smStartTest);
+      break;
+
+    case plmEmpty:
+      next(smStartEP);
+      break;
+
+    case plmScan:
+      if(master)
+        next(smReqComS);
+      break;
+
+    case plmXchg:
+      if(!master)
+        next(smStartComES);
+      break;
+
+    case plmSoaapM:
+      if(!pollStopped)
+        next(smStartEP);
+      break;
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Low Level Tests
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smStartTest()
+{
+  bleState = 500;
+
+  if(master)
+  {
+    nak = false;
+    adr = 1;
+    slaveIdx = adr;
+    setTimeOut(500000);
+  }
+  else
+  {
+    nak = true;
+  }
+  pduOut.len  = 6;
+  setPduAddress();
+  radio->setChannel(chn);
+  next(smWaitTest);
+}
+
+void BlePoll::smWaitTest()
+{
+  if(!timeOut()) return;
+  radio->disable(txmRead);
+  next(smLoopTest);
+}
+
+void BlePoll::smLoopTest()
+{
+  pduOut.adr0++;
+  radio->send(&pduOut, txmRead);
+  setTimeOut(500000);
+  next(smWaitTest);
+}
+
+
+
+// ----------------------------------------------------------------------------
+// L e e r e s   P o l l i n g
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smStartEP()
+{
+  bleState = 1000;
+
+  pduOut.len  = 6;          // Nur Adresse
+  radio->setChannel(chn);
+  pollMaxNr = 0;
+
+  nak = true;
+
+  if(master)
+  {
+    adr = 1;
+    slaveIdx = adr;         // Slave-Array[0] reserviert
+    pollIdx = 1;            // Poll-Array[0] reserviert
+    pollNr = 0;             // Anzahl in der Poll-Liste
+    next(smReqEadr);
+  }
+  else
+  {
+    next(smWaitEadr);
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Leeres Polling           M a s t e r
+// ----------------------------------------------------------------------------
+//
+
+void BlePoll::smReqEadr()
+{
+  bleState = 1100;
+
+  // Datenstruktur für den Slave definieren
+  //
+  curSlave = &slaveList[slaveIdx];    // Zeiger auf zu pollenden Slave
+  curSlave->adr  = adr;
+  curSlave->area = area;
+  curSlave->chn  = chn;
+
+  curPoll = &pollList[pollIdx];       // Zeiger auf freien Platz in Poll-Liste
+
+  setPduAddress();
+  setTimeOut(epTimeOut);
+
+  radio->getStatistics(&statistic);
+
+  radio->send(&pduOut, txmPoll);
+  cntPolling++;
+  next(smWaitNak);
+}
+
+
+void BlePoll::smWaitNak()
+{
+  bleState = 1110;
+
+  if(timeOut())
+  {
+    // Für die Adresse ist kein Teilnehmer vorhanden, oder die Übertragung ist gestört
+    //
+    radio->disable(txmPoll);
+
+    if(curSlave->pIdx != 0)
+    {
+      // Wenn der Teilnehmer bereits in die Poll-Liste eingetragen ist
+      // dann wird darin seine temporäre Abwesenheit markiert
+      pollList[(int) curSlave->pIdx].status &= ~psSlaveIsPresent;
+    }
+
+    // Der Time-Out-Zähler macht erkenntlich, wie stark sich Störungen auswirken
+    //
+    curSlave->cntTo++;
+    cntAllTo++;
+
+    // Nächste Adresse und zur Anforderung
+    //
+    adr++;
+    slaveIdx = adr;
+    if(adr > maxAdr)
+      next(smEndEP);
+    else
+      next(smReqEadr);
+    return;
+  }
+
+
+  if(radio->fin(txmPoll, &crcError))
+  {
+    // Auf dem Kanal wurde ein Datensatz (BLE-Beacon) empfangen
+    // und es werden die ersten 8 Byte (Header, Len und Adresse) geholt
+    //
+    cntAllRecs++;
+    radio->getRecData(&pduIn, 8);
+
+    if(pduIn.adr3 != pduOut.adr3 || pduIn.adr4 != pduOut.adr4 || pduIn.adr5 != pduOut.adr5)
+    {
+      // Wenn die höherwertigen 3 Byte der Adresse nicht mit der Anwendungskodierung
+      // übereinstimmen, dann ist es ein Fremd-Beacon.
+      // Diese werden gezählt und kennzeichnen, wie stark aktiv ein anderes
+      // BLE-Netzwerk in Reichweite ist.
+      //
+      cntAlien++;
+
+      // Nächste Adresse und zur Anforderung, nicht auf Time-Out warten
+      //
+      adr++;
+      slaveIdx = adr;
+      if(adr > maxAdr)
+        next(smEndEP);
+      else
+        next(smReqEadr);
+      return;
+    }
+
+    if(pduIn.adr0 != pduOut.adr0 || (pduIn.adr1 & 0x3F) != (pduOut.adr1 & 0x3F))
+    {
+      // Wenn die Teinehmernummer oder die Gebietsnummer falsch sind, dann ist
+      // möglicherweise ein weiterer Master aktiv, der fehlerhafterweise denselben
+      // Kanal verwendet.
+      // Auch dieses Ereignis wird gezäht.
+      cntWrong++;
+
+      // Nächste Adresse und zur Anforderung, nicht auf Time-Out warten
+      //
+      adr++;
+      slaveIdx = adr;
+      if(adr > maxAdr)
+        next(smEndEP);
+      else
+        next(smReqEadr);
+      return;
+    }
+
+    // Alles korrekt, der adressierte Teilnehmer hat rechtzeitig geantwortet
+    // Radio ist abgeschaltet
+    //
+
+    if(curSlave->pIdx != 0)
+    {
+      // Wenn der Teilnehmer bereits in die Poll-Liste eingetragen ist,
+      // dann wird er darin als aktuell anwesend markiert
+      //
+      pollList[(int) curSlave->pIdx].status |= psSlaveIsPresent;
+      pollNr++;
+    }
+    else
+    {
+      // Wenn nicht, wird der aktuelle Listeneintrag definiert
+      //
+      curPoll->status |= psSlaveIsPresent | psSlaveWasPresent;
+      curPoll->slIdx = slaveIdx;  // Querverweis zur Liste möglicher Teilnehmer
+      curSlave->pIdx = pollIdx;   // Und in der Liste auch ein Verweis zur Poll-Liste
+      pollIdx++;                  // Weiter mit nächstem Listenplatz
+      pollNr++;                   // Anzahl der beantworteten Pollings
+    }
+
+    // Die Nak-Antworten werden gezählt
+    //
+    curSlave->cntNakEP++; // Teilnehmerspezifisch
+    cntAllNaks++;         // und insgesamt
+
+    // Weiter mit nächstem Teilnehmer und nächster Adresse (TN-Nummer)
+    //
+    adr++;
+    slaveIdx = adr;
+
+    // Wenn die vorgegeben Endadresse erreicht ist
+    // dann zum Ende des Polldurchgangs über alle möglichen Teilnehmer,
+    // ansonsten nächsten Teilnehmer pollen
+    //
+    if(adr > maxAdr)
+      next(smEndEP);
+    else
+      next(smReqEadr);
+  }
+}
+
+
+void BlePoll::smEndEP()
+{
+  // Nach jedem vollständigen Polldurchlauf kann das Polling
+  // abgebrochen werden.
+  //
+  if(pollStop || pollStopped)
+  {
+    pollStopped = true;
+    next(smIdle);
+    return;
+  }
+
+  // Es werden die Maximalwerte der rechtzeitigen Antworten gebildet
+  //
+  if(pollNr > pollMaxNr)
+    pollMaxNr = pollNr;
+
+  if(pollMaxNr == 0)
+  {
+    // Wenn noch kein Teilnehmer angeschlossen ist (oder Kanal total gestört)
+    //
+    if(epCycleTotal > 0)
+    {
+      // dann wird der Pollvorgang so oft wie vorgegeben wiederholt
+      //
+      epCycleTotal--;
+      pollNr = 0;
+      pollIdx = 1;
+      adr = 1;
+      slaveIdx = adr;
+      next(smReqEadr);
+      return;
+    }
+    else if(epCycleTotal == 0)
+    {
+      // und anschließend der Idle-Zustand angenommen
+      next(smIdle);
+      return;
+    }
+  }
+  else
+  {
+    // Wenn wenigstens schon ein Teilnehmer geantwortet hat
+    //
+    if(epCycleRun > 0)
+    {
+      // dann wird der Pollvorgang auch so oft wie anderweitig vorgegeben wiederholt
+      //
+      epCycleRun--;
+      pollNr = 0;
+      //pollIdx = 1; falsch, pollIdx zeigt auf nächsten freien Platz
+      adr = 1;
+      slaveIdx = adr;
+      next(smReqEadr);
+      return;
+    }
+    else if(epCycleRun == 0)
+    {
+      // und anschließend die Datenübertragung gestartet
+      // oder das Polling ganz beendet
+      //
+      if(fullCycle)
+        next(smStartCom);
+      else
+        next(smIdle);
+      return;
+    }
+  }
+
+  // Nächster Poll-Lauf, wenn epCycleXXX noch nicht abgelaufen ist
+  // oder auf einen wert kleiner 0 gestellt wurde
+  //
+  pollNr = 0;
+  //pollIdx = 1; falsch, pollIdx zeigt auf nächsten freien Platz
+  adr = 1;
+  slaveIdx = adr;
+  next(smReqEadr);
+}
+
+// ----------------------------------------------------------------------------
+// Leeres Polling           S l a v e
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smWaitEadr()
+{
+  bleState = 1200;
+
+  if(!radio->disabled(txmRespE))
+  {
+    radio->disable(txmRespE);
+    cntWaitDisabled++;
+    return;
+  }
+
+  setPduAddress();
+  radio->send(&pduOut, txmRespE);
+  next(smEvalPoll);
+}
+
+void BlePoll::smEvalPoll()
+{
+  bleState = 1210;
+
+  radio->getStatistics(&statistic);
+  if(!radio->fin(txmRespE, &crcError)) return;
+  next(smWaitEadr);
+}
+
+// ----------------------------------------------------------------------------
+// D a t e n ü b e r t r a g u n g
+// ----------------------------------------------------------------------------
+//
+
+// Vorbereitung der Datenübertragung
+//
+void BlePoll::smStartCom()
+{
+  bleState = 2000;
+
+  if(pollStop || pollStopped) // Der Start der Datenübertragung kann
+  {                           // verzögert werden
+    pollStopped = true;
+    return;
+  }
+
+  // --------------------------------------------
+  // Auswahl des Funkkanals (Frequenz)
+  // --------------------------------------------
+  //
+  radio->setChannel(chn);
+
+  // --------------------------------------------
+  // Voreinstellungen für den Master
+  // --------------------------------------------
+  //
+  if(master)
+  {
+    // Aufbau der Polling-Liste
+    //
+    for(int i = 1; i <= pollMaxNr; i++)
+    {
+      int slIdx = pollList[i].slIdx;
+      pollList[i].prioCnt = slaveList[slIdx].prioSet;
+    }
+    pollIdx = 1;
+
+    // Vorbereitung der mit dem Polling übermittelten Daten
+    //
+    pduOut.len  = 13;                 // Adresse (6) + 7 Byte Steuerung
+    ctrlPdu.counter = 0;              // Zähler im Steuertelegramm
+    ctrlPdu.appId = plptMeas9Ctrl4;   // Info für Slave zur Antwort
+
+    next(smReqComS);
+  }
+  // --------------------------------------------
+  // Voreinstellungen für den Slave
+  // --------------------------------------------
+  //
+  else
+  {
+    nak = true;
+    next(smWaitEadr);
+  }
+
+  DataExchange = true;
+}
+
+// ----------------------------------------------------------------------------
+// Datenübertragung Master          S l a v e  - >  M a s t e r
+// ----------------------------------------------------------------------------
+//
+
+// M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M
+// Polling : Anfordern von Daten beim Slave
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smReqComS()
+{
+  bleState = 2100;
+
+  if(pollStop || pollStopped) // Das Polling kann
+  {                           // angehalten werden
+    pollStopped = true;
+    return;
+  }
+
+  // Es ist von einem vorherigen Funkempfang auszugehen
+  // Die Hardware muss erst ausgeschaltet werden
+  //
+  if(!radio->disabled(txmPoll))
+  {
+    radio->disable(txmPoll);
+    return;
+  }
+
+  // Der aufzufordernde Teilnehmer wird der Poll-Liste entnommen
+  //
+  curPoll = &pollList[pollIdx];
+
+  // Ein Aufruf erfolgt nur, wenn der Prioritätszähler auf 0 steht
+  // ansonsten wird er dekrementiert und der nächste Teilnehmer
+  // im nächsten Zustandslauf ausgewählt.
+  //
+  if(curPoll->prioCnt > 0)
+  {
+    curPoll->prioCnt--;
+    pollIdx++;
+    if(pollIdx > pollMaxNr)
+      pollIdx = 1;
+    return;
+  }
+
+  // Zugriff auf den Slave aus der Poll-Liste vorbereiten
+  //
+  slaveIdx = curPoll->slIdx;
+  curSlave = &slaveList[slaveIdx];
+
+  // Slave-spezifische Parameter setzen
+  //
+  eadr = false;         // Ist true, wenn Daten nur zum Slave übertragen werden
+  nak = false;          // Ist true, wenn keine Daten übertragen werden (empty poll)
+  adr = curSlave->adr;
+  area = curSlave->area;
+  setPduAddress();
+  setTimeOut(curSlave->timeOut);
+
+
+  // Statistic-Daten einholen für evt. Auswertung
+  //
+  radio->getStatistics(&statistic);
+
+  // Aufruf des Slave starten
+  //
+  radio->send(&pduOut, txmPoll);
+
+  cntPolling++;
+  next(smWaitAckComS);
+}
+
+// M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M
+// Warten auf die Antwort vom Slave
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smWaitAckComS()
+{
+  byte    tmpByte;
+  short   tmpShort;
+
+  // Zeiger zur spezifischen Betrachtung von Empfangsdaten
+  PlPduMeasPtr resPtr;
+
+  bleState = 2110;
+
+  if(timeOut())
+  {
+    // Wenn der Slave nicht antwortet (kann auch eine Störung sein),
+    // dann wird seine Priorität heruntergesetzt (Zählwert erhöht)
+    // und der nächste Slave aus der Poll-Liste angefragt
+    //  byte      oldPduCount;
+
+    curSlave->prioSet++;
+    if(curSlave->prioSet > curSlave->minPrio)
+      curSlave->prioSet = curSlave->minPrio;
+
+    curPoll->prioCnt = curSlave->prioSet;
+
+    curSlave->cntTo++;
+    pollIdx++;
+    if(pollIdx > pollMaxNr)
+      pollIdx = 1;
+
+    radio->disable(txmPoll);
+    next(smReqComS);
+    return;
+  }
+
+  if(radio->fin(txmPoll, &crcError))
+  {
+    cntAllRecs++;
+
+    // Wenn (irgend-) ein Beacon eingegangen ist,
+    // wird die maximale (BLE-Standard) Anzahl von Bytes kopiert
+    //
+    radio->getRecData(&pduIn, 39);
+
+    if(pduIn.adr3 != pduOut.adr3 || pduIn.adr4 != pduOut.adr4 || pduIn.adr5 != pduOut.adr5)
+    {
+      // Beacons aus fremdem Netzen werden nur gezählt und es wird weiter gewartet
+      //
+      cntAlien++;
+      pollIdx++;
+      if(pollIdx > pollMaxNr)
+        pollIdx = 1;
+
+      next(smReqComS);
+      return;
+    }
+
+    if(pduIn.adr0 != pduOut.adr0 || (pduIn.adr1 & 0x3F) != (pduOut.adr1 & 0x3F))
+    {
+      // Beacons mit falscher Slaveadresse werden ebenfalls nur gezählt
+      // Hier wird später die Rundrufübertragung implementiert
+      //
+      cntWrong++;
+      pollIdx++;
+      if(pollIdx > pollMaxNr)
+        pollIdx = 1;
+
+      next(smReqComS);
+      return;
+    }
+
+    // Antwort vom richtigen Teilnehmer ist eingegangen
+    //
+
+    if(crcError)
+    {
+      // Die Daten werden bei einem CRC-Fehler verworfen.
+      // Der Fehler wird gezählt und ist ein Hinweis auf fremde
+      // Funkaktivitäten
+      //
+      curSlave->cntErrCrc++;
+      pollIdx++;
+      if(pollIdx > pollMaxNr)
+        pollIdx = 1;
+
+      next(smReqComS);
+      return;
+    }
+
+    // Die Daten werden in der Slave-Struktur abgelegt
+    //
+    resPtr = (PlPduMeasPtr) &curSlave->result;
+
+    resPtr->counter  = pduIn.data[0];
+    resPtr->type     = pduIn.data[1];
+    resPtr->appId    = pduIn.data[2];
+    resPtr->measCnt  = pduIn.data[3];
+
+    // Die Inhalte sind abhängig von der <appId>
+    //
+    switch(resPtr->appId)
+    {
+      case plptMeas9Ctrl4:
+        ((PlpM9C4Ptr) resPtr)->meas[0]  = *(word *) &pduIn.data[4];
+        ((PlpM9C4Ptr) resPtr)->meas[1]  = *(word *) &pduIn.data[6];
+        ((PlpM9C4Ptr) resPtr)->meas[2]  = *(word *) &pduIn.data[8];
+        ((PlpM9C4Ptr) resPtr)->meas[3]  = *(word *) &pduIn.data[10];
+        ((PlpM9C4Ptr) resPtr)->meas[4]  = *(word *) &pduIn.data[12];
+        ((PlpM9C4Ptr) resPtr)->meas[5]  = *(word *) &pduIn.data[14];
+        ((PlpM9C4Ptr) resPtr)->meas[6]  = *(word *) &pduIn.data[16];
+        ((PlpM9C4Ptr) resPtr)->meas[7]  = *(word *) &pduIn.data[18];
+        ((PlpM9C4Ptr) resPtr)->meas[8]  = *(word *) &pduIn.data[20];
+        ((PlpM9C4Ptr) resPtr)->ctrlPath = pduIn.data[22];
+        ((PlpM9C4Ptr) resPtr)->procCnt  = pduIn.data[23];
+        ((PlpM9C4Ptr) resPtr)->ctrl[0]  = pduIn.data[24];
+        ((PlpM9C4Ptr) resPtr)->ctrl[1]  = pduIn.data[25];
+        break;
+
+      case plptMeas6:
+        ((PlpM9C4Ptr) resPtr)->meas[0]  = *(word *) &pduIn.data[4];
+        ((PlpM9C4Ptr) resPtr)->meas[1]  = *(word *) &pduIn.data[6];
+        ((PlpM9C4Ptr) resPtr)->meas[2]  = *(word *) &pduIn.data[8];
+        ((PlpM9C4Ptr) resPtr)->meas[3]  = *(word *) &pduIn.data[10];
+        ((PlpM9C4Ptr) resPtr)->meas[4]  = *(word *) &pduIn.data[12];
+        ((PlpM9C4Ptr) resPtr)->meas[5]  = *(word *) &pduIn.data[14];
+        ((PlpM9C4Ptr) resPtr)->meas[6]  = *(word *) &pduIn.data[16];
+        break;
+    }
+
+
+    // Zählen der verlorenen Telegramme und Messwerte
+    // beginnt um <delayCnt> Pollzyklen verzögert
+    //
+    if(curSlave->delayCnt == 0)
+    {
+      tmpByte = curSlave->result.counter - curSlave->oldPduCount;
+      if(tmpByte > 1)
+        curSlave->cntLostPdu += tmpByte - 1;
+
+      tmpByte = resPtr->measCnt - curSlave->oldMeasCount;
+      if(tmpByte != 0)
+        curSlave->newMeas = true;
+      if(tmpByte > 1)
+        curSlave->cntLostMeas += tmpByte - 1;
+    }
+    else curSlave->delayCnt--;
+
+    curSlave->oldPduCount = curSlave->result.counter;
+    curSlave->oldMeasCount = resPtr->measCnt;
+
+    curSlave->newPdu  = true;
+    curSlave->cntAckDP++;
+    curPoll->prioCnt = curSlave->prioSet;
+
+    pollIdx++;
+    if(pollIdx > pollMaxNr)
+      pollIdx = 1;
+
+    next(smReqComS);
+    return;
+  }
+}
+
+void BlePoll::smEndComS()
+{
+  if(pollStop || pollStopped)
+  {
+    pollStopped = true;
+    return;
+  }
+  // Von vorne (zur Zeit, Test)
+  //
+  adr = 1;
+  slaveIdx = adr;
+  next(smReqEadr);
+}
+
+// ----------------------------------------------------------------------------
+// Datenübertragung Master         M a s t e r  - >  S l a v e
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smReqComE()
+{
+  bleState = 4100;
+
+  if(!radio->disabled(txmRead))
+  {
+    radio->disable(txmRead);
+    return;
+  }
+
+  curSlave = &slaveList[slaveIdx];
+  curSlave->adr  = adr;
+  curSlave->area = area;
+  curSlave->chn  = chn;
+
+  setPduAddress();
+  //setTimeOut(2000);
+  // Test
+  setTimeOut(1000000);
+  radio->send(&pduOut, txmRead);
+  radio->getStatistics(&statistic);
+  cntPolling++;
+  next(smWaitNak);
+}
+
+void BlePoll::smWaitAckComE()
+{
+  bleState = 4110;
+
+  if(timeOut())
+  {
+    radio->disable(txmRead);
+    curSlave->cntTo++;
+    adr++;
+    slaveIdx = adr;
+    if(adr > maxAdr)
+      next(smEndEP);
+    else
+      next(smReqEadr);
+    return;
+  }
+
+
+  if(radio->fin(txmRead, &crcError))
+  {
+    radio->getRecData(&pduIn, 8);
+
+    if(pduIn.adr3 != pduOut.adr3 || pduIn.adr4 != pduOut.adr4 || pduIn.adr5 != pduOut.adr5)
+    {
+      cntAlien++;
+      radio->cont(txmRead);
+      return;
+    }
+
+    if(pduIn.adr0 != pduOut.adr0 || (pduIn.adr1 & 0x3F) != (pduOut.adr1 & 0x3F))
+    {
+      cntWrong++;
+      radio->cont(txmRead);
+      return;
+    }
+
+    radio->disable(txmRead);
+    curSlave->cntNakEP++;
+    cntAllNaks++;
+    adr++;
+    slaveIdx = adr;
+    if(adr > maxAdr)
+      next(smEndEP);
+    else
+      next(smReqEadr);
+  }
+  radio->getStatistics(&statistic);
+}
+
+void BlePoll::smEndComE()
+{
+  if(pollStop || pollStopped)
+  {
+    pollStopped = true;
+    return;
+  }
+  // Von vorne (zur Zeit, Test)
+  //
+  adr = 1;
+  slaveIdx = adr;
+  next(smReqEadr);
+}
+
+
+// S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S
+// ----------------------------------------------------------------------------
+// Datenübertragung Slave         M a s t e r  < - >  S l a v e
+// ----------------------------------------------------------------------------
+//
+
+// S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S
+// Vorbereitungen für den Empfang (Polling durch Master)
+// ----------------------------------------------------------------------------
+//
+void BlePoll::smStartComES()
+{
+  bool  newValues;
+  bool  newCtrl;
+  byte  lenValues;
+  byte  appId;
+
+  bleState = 1310;
+  smStartComESCnt++;
+
+  if(recStop || recStopped)
+  {
+    recStopped = true;
+    return;
+  }
+
+  // Wenn keine Daten von der Anwendung zur Verfügung gestellt werden,
+  // dann macht der Betrieb hier keinen Sinn und der Slave geht in IDLE
+  //
+  if(cbData == NULL)
+  {
+    next(smIdle);
+    return;
+  }
+
+  // Falls der Sender noch nicht ausgeschaltet ist, muss gewartet werden
+  //
+  if(!radio->disabled(txmResp))
+  {
+    radio->disable(txmResp);
+    cntWaitDisabled++;
+    return;
+  }
+
+  // Vorbereiten des erwarteten Inhalts beim Polling durch den Master
+  //
+  nak = true;
+  eadr = true;
+  setPduAddress(&pduIn);
+  pduIn.len = 6;
+
+
+  // Vorbereiten des zu sendenden Inhalts als Antwort auf das Polling
+  //
+  nak = false;
+  eadr = false;
+  setPduAddress(&pduOut);
+
+  // Eintragen der Messwerte in das Sendetelegramm
+  //
+  if(lenBeacon == 0)            // Wenn noch kein Empfangszyklus vorliegt
+    appId = valuePdu.appId;     // dann wird der voreingestellte Satz gewählt
+  else
+    appId = recBeacon.data[2];  // ansonsten der speziell angeforderte
+
+  newValues = getValues(&pduOut, (PlpType) appId);
+
+  if((appId == plptMeas9Ctrl4) && (cbCtrl != NULL))
+    getCtrls(&pduOut, (PlpType) appId);
+
+  radio->setChannel(chn);
+  radio->send(&pduIn, &pduOut, txmResp, newValues);
+
+  setTimeOut(wdTimeOut);
+  next(smWaitComES);
+}
+
+// S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S
+void BlePoll::smWaitComES()
+{
+  bleState = 1320;
+
+  radio->getStatistics(&statistic);
+  if(timeOut())
+  {
+    next(smStartComES);
+    return;
+  }
+
+  if(!radio->fin(txmResp, &crcError)) return;
+  //
+  // Übertragung beendet, Daten empfangen (polling) und versendet (response)
+  //
+  //lenBeacon = radio->getRecData(&recBeacon, txmResp, sizeof(recBeacon));
+  next(smStartComES);
+}
+
+// --------------------------------------------------------------------------
+// Anwenderfunktionen
+// --------------------------------------------------------------------------
+//
+
+// neue Steuerungsdaten für einen Slave
+
+void BlePoll::updControl(int adr, byte *ctrlList, int nr)
+{
+  if(adr <= 0) return;
+  if(adr >= MAXSLAVE) return;
+  if(nr <= 1) return;
+  if(nr > 27) return;
+
+  SlavePtr  slavePtr = &slaveList[adr];
+  PlpCtrl27Ptr ctrlPtr = (PlpCtrl27Ptr) &slavePtr->control;
+  for(int i = 0; i < nr; i++)
+    ctrlPtr->ctrl[i] = ctrlList[i];
+  ctrlPtr->ctrlCnt++;
+  slavePtr->rspOk = false;
+}
+
+// Feststellenn, ob Übertragung der Steuerungsdaten erfolgt ist
+
+bool BlePoll::ackTrans(int adr)
+{
+  if(adr <= 0) return(false);
+  if(adr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[adr];
+  return(slavePtr->rspOk);
+}
+
+// Feststellen, ob Steuerungsdaten beim Slave verarbeitet sind
+
+bool BlePoll::ackControl(int adr)
+{
+  if(adr <= 0) return(false);
+  if(adr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[adr];
+  PlpCtrl27Ptr ctrlPtr = (PlpCtrl27Ptr) &slavePtr->control;
+  if(ctrlPtr->ctrlCnt == slavePtr->rspCtrlCount)
+    return(true);
+  else
+    return(false);
+}
+
+// ----------------------------------------------------------------------------
+// Zugriff auf Slavedaten über die Adresse
+// ----------------------------------------------------------------------------
+//
+
+// Feststellen, ob ein Slave neue Messwerte hat
+//
+bool  BlePoll::measAvail(int slAdr)
+{
+  if(slAdr < 1) return(false);
+  if(slAdr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[slAdr];
+
+  if(!slavePtr->newMeas)
+    return(false);
+
+  slavePtr->newMeas = false;
+  return(true);
+}
+
+// Auslesen der Netzwerk-Area
+//
+int BlePoll::getArea(int slAdr)
+{
+  if(slAdr < 1) return(false);
+  if(slAdr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[slAdr];
+
+  return(slavePtr->area);
+}
+
+// Auslesen der AppId aus Sicht der Klasse BlePoll
+//
+PlpType BlePoll::getAppId(int slAdr)
+{
+  if(slAdr < 1) return(plptError);
+  if(slAdr >= MAXSLAVE) return(plptError);
+
+  SlavePtr  slavePtr = &slaveList[slAdr];
+
+  return((PlpType) slavePtr->result.plData[0]);
+}
+
+// Auslesen der Messwerte
+//
+int BlePoll::getMeas(int slAdr, byte *dest)
+{
+  int     anzByte;
+  PlpType appId;
+
+  if(slAdr < 1) return(false);
+  if(slAdr >= MAXSLAVE) return(false);
+
+  SlavePtr  slavePtr = &slaveList[slAdr];
+
+  appId = (PlpType) slavePtr->result.plData[0];
+
+  switch(appId)
+  {
+    case plptMeas6:
+      anzByte = 12;
+      break;
+
+    case plptMeas9:
+      anzByte = 18;
+      break;
+
+    case plptMeas9Ctrl4:
+      anzByte = 22;
+      break;
+
+    case plptMeas13:
+      anzByte = 26;
+      break;
+
+    default:
+      anzByte = 18;
+      break;
+  }
+
+  for (int i = 0; i < anzByte; i++)
+  {
+    dest[i] = slavePtr->result.plData[i+2];
+  }
+
+  return(anzByte);
+}
+
+int BlePoll::getCtrlM(int slAdr, byte *dest){
+  int     anzByte;
+  PlpType appId;
+
+  if(slAdr < 1) return(false);
+  if(slAdr >= MAXSLAVE) return(false);
+
+  
+  SlavePtr  slavePtr = &slaveList[slAdr];
+  appId = (PlpType) slavePtr->result.plData[0];
+
+  switch(appId)
+  {
+    case plptMeas6:
+      anzByte = 0;
+      break;
+
+    case plptMeas9:
+      anzByte = 0;
+      break;
+
+    case plptMeas9Ctrl4:
+      anzByte = 4;
+      break;
+
+    case plptMeas13:
+      anzByte = 0;
+      break;
+
+    default:
+      anzByte = 0;
+      break;
+  }
+
+  for (int i = 0; i < anzByte; i++)
+  {
+    dest[i] = slavePtr->result.plData[i+20];
+  }
+
+  return(anzByte);
+}
+
+
+// --------------------------------------------------------------------------
+// Debugging
+// --------------------------------------------------------------------------
+//
+dword BlePoll::debGetDword(int idx)
+{
+  dword retv = 0;
+
+  switch(idx)
+  {
+    case 0:
+      retv = plMode;
+      break;
+
+    case 1:
+      retv = cntAllRecs;
+      break;
+
+    case 2:
+      retv = cntAllNaks;
+      break;
+
+    case 3:
+      retv = cntAllTo;
+      break;
+
+    case 4:
+      retv = cntAlien;
+      break;
+
+    case 5:
+      retv = cntWrong;
+      break;
+
+    case 6:
+      retv = statistic.pollAcks;
+      break;
+
+    case 7:
+      retv = statistic.pollNaks;
+      break;
+
+    case 8:
+      retv = bleState;
+      break;
+
+    case 9:
+      retv = radio->getState();
+      break;
+  }
+
+  return(retv);
+}
+
+dword BlePoll::getStatistics(TxStatisticsPtr dest)
+{
+  *dest = statistic;
+  return(bleState);
+}
+
+
+SlavePtr      BlePoll::getSlavePtr(int idx)
+{
+  return(&slaveList[idx]);
+}
+
+PollStatePtr  BlePoll::getPollPtr(int idx)
+{
+  return(&pollList[idx]);
+}
+
+
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/BlePoll/BlePoll.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/BlePoll/BlePoll.h
new file mode 100644
index 0000000000000000000000000000000000000000..721d22c5c1b2fd65fc1415d7707fb2d93383e036
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/BlePoll/BlePoll.h
@@ -0,0 +1,513 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   BlePoll.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. September 2021
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Kommunikation
+// über BLE-Funkmodule auf niedriger Ebene, also dem direkten Telegrammaustausch.
+// Darauf aufbauend sollen mehrkanalige Messeinrichtungen mit möglichst
+// geringen Latenzzeiten entwickelt werden.
+//
+
+#ifndef BlePoll_h
+#define BlePoll_h
+// ----------------------------------------------------------------------------
+
+#include "stddef.h"
+#include "string.h"
+#include "arduinoDefs.h"
+#include "bleSpec.h"
+#include "IntrfRadio.h"
+
+#define MAXSLAVE  100
+
+// Betriebsmodus (Polling und Slave)
+//
+typedef enum _PlMode
+{
+  plmIdle,        // Ruhezustand, Gerät nicht im Netz aktiv
+  plmTest,        // Low Level Tests
+  plmEmpty,       // Leeres Polling (Aufbau Adressliste)
+  plmScan,        // Daten aller aktiven Teilnehmer holen (Master)
+  plmSoaapM,      // Vollständiger Betrieb SOAAP (Master)
+  plmSoaapS,      // Vollständiger Betrieb SOAAP (Slave)
+  plmXchg         // Daten übertragen (Slave, beide Richtungen)
+} PlMode;
+
+// Grundsätzliche Datenstruktur für die Nutzdaten (ohne 6 Bytes Adresse)
+//
+typedef struct _PlPduBase   // maximale Länge Beacon = 31 Bytes
+{
+  byte  counter;      // zyklischer Telegrammmzähler
+  byte  type;         // Kennzeichnung der Datenstruktur (AppType)
+  byte  plData[29];   // weitere spezifische Nutzdaten
+} PlPduBase, *PlPduBasePtr;
+
+// Grundsätzliche Datenstruktur für Messwerte (ohne 6 Bytes Adresse)
+//
+typedef struct _PlPduMeas   // maximale Länge Beacon = 31 Bytes
+{
+  byte  counter;      // zyklischer Telegrammmzähler
+  byte  type;         // Kennzeichnung der Datenstruktur (AppType)
+  byte  appId;        // Kennzeichnung für Dateninhalte (PlpType)
+  byte  measCnt;      // Zähler für Messwertaktualisierung
+  byte  plData[27];   // weitere spezifische Nutzdaten
+} PlPduMeas, *PlPduMeasPtr;
+
+// Erweiterte Datenstruktur für die Nutzdaten (ohne 6 Bytes Adresse)
+// zur Zeit noch nicht genutzt
+//
+typedef struct _PlPduExtd   // grundsätzliche maximale Länge = 249 Bytes
+{
+  byte  counter;      // zyklischer Telegrammmzähler
+  byte  type;         // Kennzeichnung der Datenstruktur (AppType)
+  byte  plData[247];  // weitere spezifische Nutzdaten
+} PlPduExtd, *PlPduExtdPtr;
+
+// Datentypen (appId in plPduBase)
+//
+typedef enum _PlpType
+{
+  plptError,        // Fehler erkannt
+  plptEmpty,        // Leeres Telegramm (nur adresse)
+  plptBasic,        // Grundlegende Bytestruktur
+  plptFullMeas,     // Maximale Belegung mit 16-Bit Messwerten (word)
+  plptMeas3,        // 3 Messwerte (1 Raumsensor)
+  plptMeas6,        // 6 Messwerte (2 Raumsensoren)
+  plptMeas9,        // 9 Messwerte (3 Raumsensoren)
+  plptMeas9Ctrl4,   // 9 Messwerte + 4 Byte Steuerung
+  plptMeas10Ctrl4,  // 10 Messwerte + 4 Byte Steuerung
+  plptMeas12,       // 12 Messwerte (9 + 6 Byte Extradaten)
+  plptMeas13,       // 13 Messwerte (9 + 8 Byte Extradaten)
+  plptMeasX,        // Variable Anzahl Messwerte
+  plptCtrl0,        // Keine Steuerung
+  plptCtrl2,        // 2 Byte Steuerung
+  plptCtrl27,       // 27 Byte Steuerung
+  plptCtrlX,        // Variable Anzahl Steuerbytes
+  plptMsg           // (Quittierte) Meldung an Slave
+} PlpType, *PlpTypePtr;
+
+// Spezifische Datenstrukturen
+//
+typedef struct _PlpFullMeas   // Ausnahme für vordefinierte Spezialfälle
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  word    meas[14];   // Liste von 14 Messwerten
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    align;      // Wird nicht gesendet, kennzeichnet Alignement
+} PlpFullMeas, *PlpFullMeasPtr;
+
+typedef struct _PlpMeas3      // Länge 10 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[3];    // Liste von 3 Messwerten
+} PlpMeas3, *PlpMeas3Ptr;
+
+typedef struct _PlpMeas6      // Länge 16 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[6];    // Liste von 6 Messwerten
+} PlpMeas6, *PlpMeas6Ptr;
+
+typedef struct _PlpMeas9      // Länge 22 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[9];    // Liste von 9 Messwerten
+} PlpMeas9, *PlpMeas9Ptr;
+
+typedef struct _PlpM9C4      // Länge 26 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[9];    // Liste von 9 Messwerten
+  byte    ctrlPath;   // Steuerungspfad (für Verzweigungen/Funktionen)
+  byte    procCnt;    // Prozesszähler
+  byte    ctrl[2];    // Steuerungsdaten
+} PlpM9C4, *PlpM9C4Ptr;
+
+typedef struct _PlpMeas12      // Länge 28 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[12];   // Liste von 12 Messwerten
+} PlpMeas12, *PlpMeas12Ptr;
+
+typedef struct _PlpMeas13      // Länge 30 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    measCnt;    // Zähler für Messwertaktualisierung
+  word    meas[13];   // Liste von 13 Messwerten
+} PlpMeas13, *PlpMeas13Ptr;
+
+typedef struct _PlpCtrl2        // Länge 7 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    ctrlCnt;    // Zähler für Kommandoaktualisierung
+  byte    procCnt;    // Zähler für Prozessaktualisierung
+  byte    ctrl[2];    // Liste von 2 Steuerbytes
+} PlpCtrl2, *PlpCtrl2Ptr;
+
+typedef struct _PlpCtrl27        // Länge 31 (+ 6 Bytes Adresse)
+{
+  byte    counter;    // zyklischer Telegrammmzähler
+  byte    type;       // Kennzeichnung der Datenstruktur (AppType)
+  byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    ctrlCnt;    // Zähler für Kommandoaktualisierung
+  byte    procCnt;    // Zähler für Prozessaktualisierung
+  byte    ctrl[26];   // Liste von bis zu 26 Steuerbytes
+} PlpCtrl27, *PlpCtrl27Ptr;
+
+// Identifikator für die Art der Daten
+//
+typedef enum _MeasId
+{
+  app               // Gestaltung/Bedeutung der Daten aus Anwendung
+} MeasId, *MeasIdPtr;
+
+typedef struct _Slave
+{
+  dword     timeOut;        // Wartezeit beim Polling in Mikrosekunden
+  dword     cntTo;          // Zähler für ausbleibende Antworten
+  dword     cntErrCrc;      // Zähler für CRC-Fehler bei der Übertragung
+  dword     cntNakEP;       // Zähler für NAK-Antworten beim Empty-Polling
+  dword     cntAckDP;       // Zähler für ACK-Antworten beim Data-Polling
+  dword     cntLostPdu;     // Zähler für verlorene Telegramme
+  dword     cntLostMeas;    // Zähler für verlorene Messwerte
+  dword     delayCnt;       // Verzögerung (Polldurchläufe) vor Fehlerzählung
+  byte      adr;            // Adresse (Nummer) des Slave (1-255)
+  byte      area;           // Einsatzgebiet des Slave (Adresserweiterung)
+  byte      chn;            // Aktueller Übertragungskanal (0-39)
+  byte      pIdx;           // Index in der aktuellen Pollingliste
+  word      prioSet;        // Anfangspriorität (rel. Häufigkeit) beim Polling
+  word      minPrio;        // Minimale Priorität (maximale Prioritätszahl)
+  PlPduBase result;         // Daten vom Slave
+  PlPduBase control;        // Daten zum Slave
+  bool      newPdu;         // Kennzeichnung für neues Telegramm
+  bool      rspOk;          // Rücksetz-Kennnzeichnung für neues Telegramm
+  bool      newMeas;        // Kennzeichnung für neuen Messwert
+  byte      oldPduCount;    // Merker für die Telegrammüberwachung
+  byte      oldMeasCount;   // Merker für die Messwertüberwachung
+  byte      rspCtrlCount;   // Merker für Steuerungsüberwachung
+} Slave, *SlavePtr;
+
+
+typedef struct _PollInfo
+{
+  dword   aliens;     // Anzahl der netzfremden Aktivitäten
+  dword   wrongs;     // Anzahl ungewünschter Netzaktivitäten
+} PollInfo, *PollInfoPtr;
+
+
+typedef struct _PollState
+{
+  byte    slIdx;      // Index in der Slave-Liste
+  byte    status;     // Zustand
+  word    prioCnt;    // Prioritätszähler
+} PollState, *PollStatePtr;
+
+typedef bool (*cbDataPtr)(PlpType dataType, byte *dest);
+typedef bool (*cbCtrlPtr)(PlpType plpType, byte *dest, byte *src, int sSize);
+
+#define psSlaveWasPresent 0x01
+#define psSlaveIsPresent  0x02
+
+// ----------------------------------------------------------------------------
+//                            B l e P o l l
+// ----------------------------------------------------------------------------
+class BlePoll
+{
+public:
+  // -------------------------------------------------------------------------
+  // Öffentliche Datentypen
+  // -------------------------------------------------------------------------
+  //
+  typedef enum _ComType
+  {
+    ctMASTER,
+    ctSLAVE,
+    ctHybrid
+  } ComType;
+
+  // Identifikator für die Anwendung
+  //
+  typedef enum _AppType
+  {
+    atDefault,        // Standard-Default-Anwendung
+    atTestSend,       // einfacher Sendetest (Soaap)
+    atSOAAP,          // Steuerung optischer und akustischer Ausgaben für Performance-Künstler
+    atDevSOAAP,       // Entwicklerbetrieb für SOAAP
+    atDHA             // Dezentrale Hausautomatisierung
+  } AppType;
+
+  // --------------------------------------------------------------------------
+  // Öffentliche Daten
+  // --------------------------------------------------------------------------
+  //
+  bool    DataExchange;
+
+private:
+  // -------------------------------------------------------------------------
+  // Private Datentypen
+  // -------------------------------------------------------------------------
+  //
+
+  typedef void (BlePoll::*cbVector)(void);
+  typedef dword (*MicsecFuPtr)(void);
+
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  IntrfRadio    *radio;
+  bcPdu         pduOut;
+  bcPdu         pduIn;
+  cbVector      nextState;
+  MicsecFuPtr   micSec;
+  cbDataPtr     cbData;
+  cbCtrlPtr     cbCtrl;
+  dword         toSet;
+  dword         toValue;
+  dword         cycleMics;
+  dword         cycleCnt;
+  dword         wdTimeOut;
+
+  int           chn;
+  int           adr;
+  int           area;
+  bool          master;
+  bool          eadr;
+  bool          nak;
+  bool          crcError;
+
+  PlMode        plMode;
+  PlMode        oldPlMode;
+  PlpType       plpType;
+
+  Slave         slaveList[MAXSLAVE+1];
+  SlavePtr      curSlave;
+  int           slaveIdx; // ist z.Zt. identisch mit Slaveadresse adr
+  PollState     pollList[MAXSLAVE+1];
+  PollStatePtr  curPoll;
+  int           pollIdx;
+  int           pollNr;
+  int           pollMaxNr;
+
+  int           maxAdr;
+  dword         cntPolling;
+  dword         cntAllRecs;
+  dword         cntAllTo;
+  bool          pollStop;
+  bool          pollStopped;
+
+  dword         cntAllNaks;
+  dword         cntAlien;
+  dword         cntWrong;
+  dword         cntWaitDisabled;
+
+  dword         bleState;
+  dword         runCounter;
+  bool          recStop;
+  bool          recStopped;
+
+  TxStatistics  statistic;
+  PlPduMeas     valuePdu;
+  PlpCtrl27     ctrlPdu;
+  bool          newValue;
+  bool          newCtrl;
+
+  // Einstellungen für den Anwendungsbetrieb
+  //
+  bool          fullCycle;      // Vollständige Anwendung (EP & Data)
+  int           epCycleTotal;   // Anzahl der leeren Pollings gesamt
+  int           epCycleRun;     // Anzahl der leeren Pollings nach Kontakt
+  dword         epTimeOut;      // Time-Out in Mikrosekunden
+
+
+  // --------------------------------------------------------------------------
+  // Lokale Funktionen
+  // --------------------------------------------------------------------------
+  //
+  void setPduAddress();
+  void setPduAddress(bcPduPtr pduPtr);
+  void setTimeOut(dword value);
+  bool timeOut();
+  bool getValues(bcPduPtr pduPtr, PlpType appId);
+  bool getCtrls(bcPduPtr pduPtr, PlpType appId);
+
+
+  // Zustandsmaschine
+  // -----------------------------
+  void smInit();
+  void smIdle();
+
+  // Leeres Polling Master
+  //
+  void smStartEP();
+  void smReqEadr();
+  void smWaitNak();
+  void smEndEP();
+
+  // Leeres Polling Slave
+  //
+  void smWaitEadr();
+  void smEvalPoll();
+
+  // Datenübertragung
+  //
+  void smStartCom();
+
+  // Master: Master -> Slave
+  //
+  void smReqComE();
+  void smWaitAckComE();
+  void smEndComE();
+
+  // Master: Slave -> Master
+  //
+  void smReqComS();
+  void smWaitAckComS();
+  void smEndComS();
+
+  // Slave: Master <-> Slave
+  //
+  void smStartComES();
+  void smWaitComES();
+  void smEvalComES();
+
+  // Test
+  //
+  void smStartTest();
+  void smWaitTest();
+  void smLoopTest();
+
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+  BlePoll(IntrfRadio *refRadio, dword inCycleMics);
+  BlePoll(IntrfRadio *refRadio, MicsecFuPtr inMicroFu);
+  void init(IntrfRadio *refRadio, dword inCycleMics, MicsecFuPtr inMicroFu);
+
+  void begin(ComType typeIn, int adrIn, AppType appType, dword watchDog);
+  void setCbDataPtr(cbDataPtr cbPtr);
+  void setCbCtrlPtr(cbCtrlPtr cbPtr);
+
+  // --------------------------------------------------------------------------
+  // Konfiguration
+  // --------------------------------------------------------------------------
+  //
+  void setPollAddress(int chnIn, int adrIn, int areaIn, bool masterIn, bool eadrIn, bool nakIn);
+  void setEmptyPollParams(int cycleTotal, int cycleRun, dword timeOut);
+  void setDataPollParams(int slAdr, int prio, int minPrio, dword timeOut);
+
+  // --------------------------------------------------------------------------
+  // Steuerung des Telegrammaustausches (Polling)
+  // --------------------------------------------------------------------------
+  //
+  void run();       // Ablaufsteuerung (CPU-Übergabe) dieses Moduls
+/**
+ * @brief Sendet neue Steuerungsdaten an einen Slave
+ * 
+ * @param adr Addresse d. zu Steuernden Slaves
+ * @param ctrlList Liste mit Bytes zum Austausch der Steuerbytes
+ * @param nr Anzahl d. Steuerbytes
+ */
+  void updControl(int adr, byte *ctrlList, int nr);   // neue Steuerungsdaten
+  //
+/**
+ * @brief Prüft ob Steuerungsdaten übertragen wurden
+ * 
+ * @param adr Adresse d. Slaves
+ * @return true Erfolgreiche übertragung
+ * @return false Fehler in Übertragung / Falsche Adresse
+ */
+  bool ackTrans(int adr);         // Bestätigung Steuerungsdaten übertragen
+  /**
+ * @brief Überprüft ob Steuerungsdaten korrekt übertragen wurden
+ * 
+ * @param adr Adresse d. Slavrs
+ * @return true Daten erfolgreich verarbeitet
+ * @return false Fehler in Übertragung
+ */
+  bool ackControl(int adr);       // Bestätigung Steuerung ausgeführt
+
+
+  // Test
+  //
+
+  // Leeres Polling
+  //
+  void stopEP();
+  void resumeEP();
+  bool stoppedEP();
+
+  // Empfangsbetrieb beim Slave
+  //
+  void stopSR();
+  void resumeSR();
+  bool stoppedSR();
+
+  // Laufender Betrieb
+  //
+  void start(PlMode inPlMode);
+
+
+
+  // --------------------------------------------------------------------------
+  // Zugriff auf Polling-Informationen
+  // --------------------------------------------------------------------------
+  //
+  int   getSlaveList(byte *dest, int maxByte);
+  void  resetPollCounters();
+
+  // --------------------------------------------------------------------------
+  // Zugriff auf Slavedaten
+  // --------------------------------------------------------------------------
+  // Der Index wird von 0 an ausgewertet. Allerdings ist [0] in der Slave-Liste
+  // auf den Index [1] abzubilden, weil Slave[0] für besondere Aufgaben
+  // reserviert und für den Anwender nicht zugänglich ist.
+  //
+  bool      measAvail(int slIdx);   // Feststellen, ob neue Messwerte da sind
+  int       getArea(int slIdx);     // Wert der Area auslesen
+  PlpType   getAppId(int slIdx);    // Wert der AppId (BlePoll) auslesen
+  int       getMeas(int slIdx, byte *dest);    // Messwerte übergeben
+  int       getCtrlM(int slIdx, byte *dest);
+
+
+  // --------------------------------------------------------------------------
+  // Debugging
+  // --------------------------------------------------------------------------
+  //
+  dword debGetDword(int idx);
+  dword getStatistics(TxStatisticsPtr dest);
+
+  SlavePtr      getSlavePtr(int idx);
+  PollStatePtr  getPollPtr(int idx);
+};
+
+
+// ----------------------------------------------------------------------------
+#endif // BlePoll_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/BlePoll/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/BlePoll/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..477225b9ff50f19fdf4a1ffb19f791f80efa4870
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/BlePoll/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "BlePoll",
+    "version": "0.0.0+20220804174235"
+  }
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/ComRingBuf/ComRingBuf.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/ComRingBuf/ComRingBuf.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..66a9784b5507d680cc700b0f7fe5e68379da7e3e
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/ComRingBuf/ComRingBuf.cpp
@@ -0,0 +1,782 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   ComRingBuf.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   21. November 2021
+//
+// Der Inhalt dieser Datei sind Festlegungen zur Gestaltung eines Ringpuffers.
+//
+
+#include "ComRingBuf.h"
+
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+
+  ComRingBuf::ComRingBuf()
+  {
+    rbReadIdx = 0;
+    rbWriteIdx = 0;
+    sbReadIdx = 0;
+    sbWriteIdx = 0;
+    newLineMode = NewLineModeNL;
+  }
+
+  void ComRingBuf::begin(IntrfSerial *ser)
+  {
+    serIf = ser;
+  }
+
+  // --------------------------------------------------------------------------
+  // Konfiguration
+  // --------------------------------------------------------------------------
+  //
+  void ComRingBuf::setNewLineMode(byte nlMode)
+  {
+    newLineMode = nlMode;
+  }
+
+
+  // --------------------------------------------------------------------------
+  // Schnittstellen
+  // --------------------------------------------------------------------------
+  //
+  // Byte aus dem Sendepuffer lesen
+  //
+  bool  ComRingBuf::getByteSnd(byte *dest)
+  {
+    if(sbReadIdx == sbWriteIdx) return(false);
+
+    *dest = sndBuffer[sbReadIdx];
+    sbReadIdx++;
+    if(sbReadIdx >= sbSize)
+      sbReadIdx = 0;
+    return(true);
+  }
+
+  // Byte in den Empfangspuffer schreiben
+  //
+  void  ComRingBuf::putByteRec(byte b)
+  {
+    int space = rbReadIdx - rbWriteIdx - 1;
+    if(space == 0) return;
+  }
+
+
+// ----------------------------------------------------------------------------
+// Writing and reading data via circular buffer (default usage)
+// ----------------------------------------------------------------------------
+//
+
+// ----------------------------------------------------------------------------
+// Lesen (Empfangsvorgänge)
+// ----------------------------------------------------------------------------
+
+void  ComRingBuf::setReadBuffer(int size, byte *bufPtr)
+{
+  recBuffer = bufPtr;
+  rbSize = size;
+  rbReadIdx = 0;
+  rbWriteIdx = 0;
+}
+
+int   ComRingBuf::getChr()
+{
+  int retv;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(EOF);
+
+  retv = recBuffer[rbReadIdx];
+  rbReadIdx++;
+  if(rbReadIdx >= rbSize)
+    rbReadIdx = 0;
+  return(retv);
+}
+
+void  ComRingBuf::clrRecBuf()
+{
+  rbReadIdx  = 0;
+  rbWriteIdx = 0;
+}
+
+int   ComRingBuf::getAll(byte *buffer)
+{
+  int   count, i;
+  int   tmpInt;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(EOF);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  for(i = 0; i < count; i++)
+  {
+    buffer[i] = recBuffer[rbReadIdx];
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+  }
+
+  return(count);
+}
+
+int   ComRingBuf::getCount(int len, byte *buffer)
+{
+  int  count, i;
+  int  tmpInt;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  if(len > count)
+    len = count;
+
+  for(i = 0; i < len; i++)
+  {
+    buffer[i] = recBuffer[rbReadIdx];
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+  }
+
+  return(len);
+}
+
+int   ComRingBuf::getCountStr(int len, char *buffer)
+{
+  int nrChar;
+
+  nrChar = getCount(len, (uint8_t *) buffer);
+  if(nrChar == EOF) return(EOF);
+
+  buffer[nrChar] = 0;
+  return(nrChar);
+}
+
+int   ComRingBuf::getLine(char *buffer)
+{
+  bool      eol;
+  int       count, i;
+  int       tmpInt;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  eol = false;
+
+  for(i = 0; i < count; i++)
+  {
+    buffer[i] = recBuffer[rbReadIdx];
+    if(!eol)
+    {
+    if(buffer[i] == '\r' || buffer[i] == '\n')
+      eol = true;
+    }
+    else
+    {
+      if(buffer[i] != '\r' && buffer[i] != '\n')
+        break;
+    }
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+  }
+
+  if(!eol) return(0);
+
+  buffer[i] = 0;
+  return(i);
+}
+
+int   ComRingBuf::getLineDec(int *intValue)
+{
+  bool      eol, inVal;
+  int       count, i, j;
+  int       tmpInt;
+  char      c;
+  char      buffer[32];
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  if(count > 30)
+    count = 30;
+
+  eol = false;
+
+  j = 0;
+  inVal = false;
+
+  for(i = 0; i < count; i++)
+  {
+    c = recBuffer[rbReadIdx];
+    if(!inVal)
+    {
+      if(c > '9')
+      {
+        rbReadIdx++;
+        if(rbReadIdx >= rbSize)
+          rbReadIdx = 0;
+        continue;
+      }
+      inVal = true;
+    }
+
+    if(!eol)
+    {
+    if(c == '\r' || c == '\n')
+      eol = true;
+    }
+    else
+    {
+      if(c != '\r' && c != '\n')
+        break;
+    }
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+    buffer[j++] = c;
+  }
+
+  if(!eol) return(0);
+
+  buffer[j] = 0;
+  *intValue = atoi(buffer);
+  return(i);
+}
+
+char ComRingBuf::getC()
+{
+  char retC;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  retC = recBuffer[rbReadIdx];
+  rbReadIdx++;
+  if(rbReadIdx >= rbSize)
+    rbReadIdx = 0;
+
+  return(retC);
+}
+
+
+int   ComRingBuf::waitLine(int waitLoop, char *buffer)
+{
+  char inChar;
+  bool eol;
+
+  if(loopCount == 0)
+  {
+    tmpIdx = 0;
+  }
+
+  tmpVal = inCount();
+  if(tmpVal < 1)
+  {
+    loopCount++;
+    if(loopCount < waitLoop)
+      return(0);
+    else
+    {
+      loopCount = 0;
+      return(EOF);
+    }
+  }
+
+  eol = false;
+
+  for(int i = 0; i < tmpVal; i++)
+  {
+    inChar = getC();
+    buffer[tmpIdx++] = inChar;
+    if(inChar == '\r' || inChar == '\n')
+    {
+      eol = true;
+      break;
+    }
+  }
+
+  if(eol)
+  {
+    buffer[tmpIdx] = 0;
+    loopCount = 0;
+    return(tmpIdx);
+  }
+
+  return(0);
+}
+
+//int   ComRingBuf::waitLineDec(int waitLoop, int *intValue)
+//{
+//};
+
+int   ComRingBuf::chkLine(char *rsp)
+{
+  int     i,chkVal;
+  char    chkChar;
+
+  chkVal = inCount();
+  if(chkVal <= strlen(rsp))
+    return(0);
+
+  chkVal = 0;
+
+  for(i = 0; i < strlen(rsp); i++)
+  {
+    chkChar = getC();
+    if(rsp[i] != chkChar)
+    {
+      chkVal = -100000;
+      break;
+    }
+    else
+      chkVal++;
+  }
+
+  if(chkVal < 0) chkVal = EOF;
+
+  while( (recBuffer[rbReadIdx] == '\r' || recBuffer[rbReadIdx] == '\n' )
+         && (rbReadIdx != rbWriteIdx))
+  {
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+  }
+
+  return(chkVal);
+}
+
+int   ComRingBuf::chkBuf(char *rsp)
+{
+  int     i,chkVal;
+  char    chkChar;
+
+  chkVal = inCount();
+  if(chkVal < strlen(rsp))
+    return(0);
+
+  chkVal = 0;
+
+  for(i = 0; i < strlen(rsp); i++)
+  {
+    chkChar = getC();
+    if(rsp[i] != chkChar)
+      chkVal = -100;
+    else
+      chkVal++;
+  }
+
+  return(chkVal);
+}
+
+int   ComRingBuf::waitAll(int waitLoop, byte *buffer)
+{
+}
+
+int   ComRingBuf::waitChkBuf(int waitLoop, char *rsp)
+{
+  int   i;
+  int   chkVal;
+  char  chkChar;
+
+  if(loopCount == 0)
+  {
+    tmpVal = strlen(rsp);
+  }
+
+  chkVal = inCount();
+  if(chkVal < tmpVal)
+  {
+    loopCount++;
+    if(loopCount < waitLoop)
+      return(0);
+    else
+    {
+      loopCount = 0;
+      return(-10);
+    }
+  }
+
+  chkChar = getC();
+
+  if(rsp[0] != chkChar)
+    return(0);
+
+  if(tmpVal == 1)
+  {
+     loopCount = 0;
+     return(1);
+  }
+
+  chkVal = 1;
+
+  for(i = 1; i < tmpVal; i++)
+  {
+    chkChar = getC();
+    if(rsp[i] != chkChar)
+      return(0);
+    else
+      chkVal++;
+  }
+
+  loopCount = 0;
+  return(chkVal);
+}
+
+int   ComRingBuf::inCount(void)
+{
+  int count = rbWriteIdx - rbReadIdx;
+  if(count < 0)
+    count += rbSize;
+  return(count);
+}
+
+int   ComRingBuf::getRestChar(byte tagChr, int len, byte *buffer)
+{
+  int       count, i, j;
+  byte      inChr;
+  int       tmpInt;
+  bool      tagged;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpInt = rbWriteIdx - rbReadIdx;
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  if(len > count)
+    len = count;
+
+  tagged = false;
+  j = 0;
+
+  for(i = 0; i < len; i++)
+  {
+    inChr = recBuffer[rbReadIdx];
+    rbReadIdx++;
+    if(rbReadIdx >= rbSize)
+      rbReadIdx = 0;
+
+    if(!tagged)
+    {
+      if(inChr != tagChr)
+        continue;
+
+      tagged = true;
+      continue;
+    }
+
+    buffer[j++] = inChr;
+  }
+
+  if(!tagged) j = -1;
+
+  return(j);
+}
+
+int   ComRingBuf::getRestStr(char *tagStr, int len, byte *buffer)
+{
+  int       count, i, j, tmpIdx;
+  byte      inChr;
+  int       tmpInt;
+  bool      tagged;
+  int       tagLen;
+  int       tagIdx;
+
+  if(rbReadIdx == rbWriteIdx)
+    return(0);
+
+  tmpIdx = rbReadIdx;
+  tmpInt = rbWriteIdx - tmpIdx;
+
+  if(tmpInt < 0)
+    count = tmpInt + rbSize;
+  else
+    count = tmpInt;
+
+  if(len > count)
+    len = count;
+
+  tagged = false;
+  j = 0;
+
+  tagLen = (int) strlen(tagStr);
+  tagIdx = 0;
+
+  if(len < tagLen)
+    return(0);
+
+  for(i = 0; i < len; i++)
+  {
+    inChr = recBuffer[tmpIdx];
+    tmpIdx++;
+    if(tmpIdx >= rbSize)
+      tmpIdx = 0;
+
+    if(!tagged)
+    {
+      if(inChr != tagStr[tagIdx])
+      {
+        tagIdx = 0;
+        continue;
+      }
+
+      tagIdx++;
+
+      if(tagIdx == tagLen)
+        tagged = true;
+      continue;
+    }
+
+    buffer[j++] = inChr;
+  }
+
+  if(!tagged) return(EOF);
+  else
+  {
+    rbReadIdx = tmpIdx;
+    return(j);
+  }
+}
+
+int   ComRingBuf::reqChkLine(char *req, char *rsp)
+{
+  int   i;
+  int   chkVal;
+  char  chkChar;
+
+  switch(reqChkState)
+  {
+    case 0:
+      rbReadIdx  = 0;
+      rbWriteIdx = 0;
+      chkVal = putLine(req);
+      if(chkVal <= 0)
+        return(EOF);
+      tmpVal = strlen(rsp);
+      reqChkState = 1;
+      return(0);
+
+    case 1:
+      chkVal = inCount();
+      if(chkVal <= tmpVal)
+        return(0);
+      chkVal = 0;
+
+      for(i = 0; i < tmpVal; i++)
+      {
+        chkChar = getC();
+        if(rsp[i] != chkChar)
+          chkVal = -100;
+        else
+          chkVal++;
+      }
+
+      while(     (recBuffer[rbReadIdx] == '\r' || recBuffer[rbReadIdx] == '\n')
+          && (rbReadIdx != rbWriteIdx) )
+      {
+        rbReadIdx++;
+        if(rbReadIdx >= rbSize)
+          rbReadIdx = 0;
+      }
+
+      reqChkState = 0;
+      return(chkVal);
+  }
+
+  return(-1000);    // internal error with <reqChkState>
+}
+
+// ----------------------------------------------------------------------------
+// Schreiben (Sendevorgänge)
+// ----------------------------------------------------------------------------
+
+void  ComRingBuf::setWriteBuffer(int size, byte *bufPtr)
+{
+  sndBuffer = bufPtr;
+  sbSize = size;
+  sbReadIdx = 0;
+  sbWriteIdx = 0;
+}
+
+int   ComRingBuf::putChr(int chr)
+{
+  int       space;
+  bool      txDone;
+
+  if(sndBuffer == NULL) return(EOF);
+  if(serIf == NULL) return(EOF);
+
+  space = getSpace();
+
+  if(space == 0)
+  {
+    // Wenn der Sendepuffer voll ist, dann kann der Entlader feststecken
+    serIf->resuSend();
+    return(EOF);
+  }
+
+  if(sbReadIdx == sbWriteIdx)
+  {
+    // Wenn der Sendepuffer leer ist, dann kann das Zeichen evt.
+    // direkt gesendet werden.
+    txDone = serIf->condSend(chr);
+    if(txDone) return(chr);
+  }
+
+  putBufB(chr);
+  return(chr);
+}
+
+int   ComRingBuf::putStr(char *msg)
+{
+  int sIdx = 0;
+
+  if(sndBuffer == NULL) return(EOF);
+  if(serIf == NULL) return(EOF);
+
+  int space = getSpace();
+  int len = strlen(msg);
+  if(space < len)
+  {
+    serIf->resuSend();
+    return(EOF);
+  }
+
+  if(sbReadIdx == sbWriteIdx)
+  {
+    // Wenn der Sendepuffer leer ist, dann kann das erste Zeichen evt.
+    // direkt gesendet werden.
+    if(serIf->condSend(msg[0]))
+      sIdx = 1;
+  }
+
+  for (int i = sIdx; i < len; i++)
+   {
+     sndBuffer[sbWriteIdx] = msg[i];
+     sbWriteIdx++;
+     if(sbWriteIdx >= sbSize)
+       sbWriteIdx = 0;
+   }
+
+  return(len);
+}
+
+int   ComRingBuf::putSeq(byte *msg, int n)
+{
+  int sIdx = 0;
+
+  if(sndBuffer == NULL) return(EOF);
+  if(serIf == NULL) return(EOF);
+
+  int space = getSpace();
+
+  if(space < n)
+  {
+    serIf->resuSend();
+    return(EOF);
+  }
+
+  if(sbReadIdx == sbWriteIdx)
+  {
+    // Wenn der Sendepuffer leer ist, dann kann das erste Zeichen evt.
+    // direkt gesendet werden.
+    if(serIf->condSend(msg[0]))
+      sIdx = 1;
+  }
+
+  for (int i = sIdx; i < n; i++)
+   {
+     sndBuffer[sbWriteIdx] = msg[i];
+     sbWriteIdx++;
+     if(sbWriteIdx >= sbSize)
+       sbWriteIdx = 0;
+   }
+
+  return(n);
+
+}
+
+int   ComRingBuf::putNL()
+{
+  int retv = 0;
+
+  if(newLineMode & NewLineModeCR)
+  {
+    putBufB('\r');
+    retv++;
+  }
+
+  if(newLineMode & NewLineModeNL)
+  {
+    putBufB('\n');
+    retv++;
+  }
+
+  return(retv);
+}
+
+int   ComRingBuf::putLine(char *msg)
+{
+  int retv, nl;
+
+  retv = putStr(msg);
+  if(retv < 0)
+    return(retv);
+
+  nl = putNL();
+  return(retv);
+}
+
+//int   ComRingBuf::putLine(char *msg, char c)
+//{
+//}
+
+//int   ComRingBuf::putLine(char *msg, int n)
+//{
+//}
+
+
+  // --------------------------------------------------------------------------
+  // Debugging
+  // --------------------------------------------------------------------------
+  //
+
+
+
+
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/ComRingBuf/ComRingBuf.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/ComRingBuf/ComRingBuf.h
new file mode 100644
index 0000000000000000000000000000000000000000..bd8ee0c8e604ac8ca5a6c344ca9966bb856f365b
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/ComRingBuf/ComRingBuf.h
@@ -0,0 +1,227 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   ComRingBuf.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   21. November 2021
+//
+// Der Inhalt dieser Datei sind Festlegungen zur Gestaltung eines Ringpuffers.
+//
+
+#ifndef ComRingBuf_h
+#define ComRingBuf_h
+// ----------------------------------------------------------------------------
+
+#include "stddef.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "arduinoDefs.h"
+#include "IntrfBuf.h"
+#include "IntrfSerial.h"
+
+#define NewLineModeCR     0x01
+#define NewLineModeNL     0x02
+
+// ----------------------------------------------------------------------------
+//                            C o m R i n g B u f
+// ----------------------------------------------------------------------------
+class ComRingBuf : IntrfBuf
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  // Zugang zur Peripherie
+  //
+  IntrfSerial *serIf;
+
+  // Lesen und Schreiben von Zeichen (Bytes)
+  //
+  byte      *ptrSend;         // Der (veraenderliche) Sendezeiger
+  byte      *ptrRec;          // Der (veraenderliche) Empfangszeiger
+  int       maxRec;           // Maximale Anzahl zu empfangender Bytes
+  byte      endChrRec;        // Abschlusszeichen beim Empfang
+  byte      condMaskCom;      // Bedingungen fuer den Datenaustausch
+  byte      newLineMode;      // Art für eine neue Zeile (CR/LF)
+
+  byte      *recBuffer;       // Receive ring buffer start address
+  word      rbReadIdx;        // Read index
+  word      rbWriteIdx;       // Write index
+  word      rbSize;           // Buffer size
+
+  byte      *sndBuffer;       // Transmit ring buffer start address
+  word      sbReadIdx;        // Read index
+  word      sbWriteIdx;       // Write index
+  word      sbSize;           // Buffer size
+
+  int       loopCount;        // For internal time out checking
+  int       reqChkState;      // State of request/check procedure
+  int       tmpVal;           // Variable for temporary data storage
+  int       tmpIdx;           // Variable for temporary array index
+
+
+  // --------------------------------------------------------------------------
+  // Lokale Funktionen
+  // --------------------------------------------------------------------------
+  //
+  char  getC();
+  int   putNL();
+
+  // --------------------------------------------------------------------------
+  // Inline-Funktionen
+  // --------------------------------------------------------------------------
+  //
+  void putBufB(byte b)
+  {
+    sndBuffer[sbWriteIdx] = b;
+    sbWriteIdx++;
+    if(sbWriteIdx >= sbSize)
+      sbWriteIdx = 0;
+  }
+
+  int getSpace()
+  {
+    int space = sbReadIdx - sbWriteIdx - 1;
+    if(space < 0) space += sbSize;
+    return(space);
+  }
+
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+  ComRingBuf();
+
+  void begin(IntrfSerial *ser);
+
+  // --------------------------------------------------------------------------
+  // Konfiguration
+  // --------------------------------------------------------------------------
+  //
+  void setNewLineMode(byte nlMode);
+
+  // --------------------------------------------------------------------------
+  // Schnittstellen
+  // --------------------------------------------------------------------------
+  //
+  bool  getByteSnd(byte *dest);
+  void  putByteRec(byte b);       // Byte vom Empfang an Puffer geben
+
+
+  // Zuweisen eines Speichers (*bufPtr) der Größe size für den Lesepuffer
+  //
+  void  setReadBuffer(int size, byte *bufPtr);
+
+
+  // --------------------------------------------------------------------------
+  // Steuerung
+  // --------------------------------------------------------------------------
+  //
+
+  // ----------------------------------------------
+  // Ein einzelnes Zeichen aus dem Ringpuffer lesen
+  // ----------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst das älteste Zeichen aus dem Ringpuffer
+  //
+  int   getChr();
+
+  // ----------------------------------------------
+  // Löschen des Emmpfangspuffers
+  // ----------------------------------------------
+  //
+  void  clrRecBuf();
+
+  // --------------------------------------------------
+  // Alle empfangenen Zeichen aus dem Ringpuffer lesen
+  // --------------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der empfangenen Zeichen
+  //
+  int   getAll(byte *buffer);
+
+  // ----------------------------------------------------------
+  // Begrenzte Anzahl empfangener Zeichen aus Ringpuffer lesen
+  // ----------------------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der ausgelesenen Zeichen
+  //
+  int   getCount(int count, byte *buffer);
+
+  // ------------------------------------------------------------------------
+  // Begrenzte Anzahl Zeichen als 0-terminierten String aus Ringpuffer lesen
+  // ------------------------------------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der ausgelesenen Zeichen
+  //
+  int   getCountStr(int count, char *buffer);
+
+  // ---------------------------------------------------------
+  // Die nächste Zeile (Zeichen bis CR und/oder LF) als String
+  // ---------------------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der ausgelesenen Zeichen
+  //
+  int   getLine(char *buffer);
+
+  // -----------------------------------------------
+  // Die nächste im Puffer enthaltene Zeile auslesen
+  // und die darin enthaltene Dezimalzahl übergeben
+  // -----------------------------------------------
+  // Rückgabe EOF (-1), wenn kein Zeichen vorhanden
+  // sonst die Anzahl der ausgelesenen Zeichen
+  // oder 0, wenn keine Dezimalzahl enthalten war
+  //
+  int   getLineDec(int *intValue);
+
+  // ---------------------------------------------------------
+  // Warten auf Zeile (Zeichen bis CR und/oder LF) als String
+  // ---------------------------------------------------------
+  // Rückgabe EOF (-1), wenn Wartezyklen verstrichen
+  // Rückgabe 0, solange kein Zeilenende gelesen
+  // sonst die Anzahl der ausgelesenen Zeichen
+  //
+  int   waitLine(int waitLoop, char *buffer);
+
+  //int   waitLineDec(int waitLoop, int *intValue);
+
+  // ---------------------------------------------------------
+  // Testen der Zeile im Puffer
+  // ---------------------------------------------------------
+  // Rückgabe 0, wenn Teststring (noch) nicht enthalten
+  // sonst die Länge des Teststring
+  // EOF, wenn Zeile im Puffer (gelöscht) nicht passte
+  //
+  int   chkLine(char *rsp);
+
+  int   chkBuf(char *rsp);
+  int   waitAll(int waitLoop, byte *buffer);
+  int   waitChkBuf(int waitLoop, char *rsp);
+  int   inCount(void);
+  int   getRestChar(byte tagChr, int len, byte *buffer);
+  int   getRestStr(char *tagStr, int len, byte *buffer);
+  int   reqChkLine(char *req, char *rsp);
+
+  void  setWriteBuffer(int size, byte *bufPtr);
+  int   putChr(int chr);
+  int   putStr(char *msg);
+  int   putSeq(byte *msg, int n);
+  int   putLine(char *msg);
+  //int   putLine(char *msg, char c);
+  //int   putLine(char *msg, int n);
+
+  // --------------------------------------------------------------------------
+  // Debugging
+  // --------------------------------------------------------------------------
+  //
+
+};
+
+
+// ----------------------------------------------------------------------------
+#endif // beacon_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/ComRingBuf/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/ComRingBuf/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..054f2c8c3093791dc7ce4f7de879b26a019e900b
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/ComRingBuf/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "BlePoll",
+  "version": "0.0.0+20220804174235"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/LoopCheck.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/LoopCheck.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b01795b4f033ebb0286340840a3b1507c6ef0302
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/LoopCheck.cpp
@@ -0,0 +1,838 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Software Loop Checking and Timing
+// Datei:   LoopCheck.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (siehe Wikipedia: Creative Commons)
+//
+
+#include "LoopCheck.h"
+
+
+  // -------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // -------------------------------------------------------------------------
+  //
+  LoopCheck::LoopCheck()
+  {
+    firstLoop       = true;
+    taskHappened    = false;
+    toggleMilli     = true;
+
+    initStatistics();
+    initTasks();
+    initClock();
+  }
+
+  void LoopCheck::initStatistics()
+  {
+    backgroundMicros        = 0;
+    loopMicros              = 0;
+    loopStartMicros         = 0;
+    loopEndMicros           = 0;
+    backgroundMaxMicros     = 0;
+    backgroundMinMicros     = (unsigned long) -1;
+    backgroundAvgMicros     = 0;
+    loopMaxMicros           = 0;
+    loopMinMicros           = (unsigned long) -1;
+    loopAvgMicros           = 0;
+    loopCounter             = 0;
+    periodFailCount         = 0;
+    periodMaxMicros         = 0;
+    periodMinMicros         = (unsigned int) -1;
+    periodMicros            = 0;
+    periodFailAlarm         = false;
+
+    year    = 0;
+    day     = 0;
+    hour    = 0;
+    min     = 0;
+    sec     = 0;
+    msec    = 0;
+
+    measureRuntime = 0;
+
+    calcAvgCounter = 0;
+  }
+
+  void LoopCheck::initTasks()
+  {
+    for (int i = 0; i < NrOfTimerTasks; i++)
+    {
+      timerTaskList[i].counterStarted    = false;
+      timerTaskList[i].finished          = false;
+      timerTaskList[i].firstRun          = true;
+      timerTaskList[i].runCounter        = 0;
+    }
+
+    for( int i = 0; i < NrOfOnceTasks; i++)
+    {
+      onceTaskList[i].finished      = false;
+      onceTaskList[i].firstRun      = true;
+      onceTaskList[i].waitCounter   = 0;
+    }
+  }
+
+  void LoopCheck::initClock()
+  {
+    strcpy(dateTimeStr,"2017-12-07T17:11:35.456+00:00");
+    dtYear      = 2017;
+    dtMonth     = 12;
+    dtDay       = 7;
+    dtHour      = 17;
+    dtMin       = 11;
+    dtSec       = 35;
+    dtmSec      = 456;
+  }
+
+  // -------------------------------------------------------------------------
+  // Anwenderfunktionen
+  // -------------------------------------------------------------------------
+  //
+
+  void LoopCheck::begin()
+  {
+    unsigned int    cycleMillis;
+    unsigned int    restMicros;
+    unsigned int    tmpInt;
+    unsigned int    tmpInt100, tmpInt10, tmpInt1;
+    div_t           divResult;
+
+    loopStartMicros = SYSMICSEC;
+    clockCycleMicros = loopStartMicros - lastClockMicros + lastRestMicros;
+    //
+    // Zeit seit dem letzten Aufruf von begin()
+
+  
+    //
+    if(firstLoop == true)
+    {
+      clockCycleMicros = 0;
+      lastClockMicros = loopStartMicros;
+    }
+
+    // Aufteilen in Millisekunden und Mikrosekunden
+    //
+    divResult = DIV((int) clockCycleMicros, 1000);
+
+    restMicros = divResult.rem;
+    cycleMillis = divResult.quot;
+
+    if(cycleMillis > 0)
+    {
+      lastRestMicros = restMicros;
+      lastClockMicros = loopStartMicros;
+      msec += cycleMillis;
+      dtmSec += cycleMillis;
+
+      // Betriebsstundenzähler
+      //
+      if(msec >= 1000)
+      {
+        msec -= 1000;
+        sec++;
+        measureRuntime++;
+
+        if(sec == 60)
+        {
+          sec = 0;
+          min++;
+          if(min == 60)
+          {
+            min = 0;
+            hour++;
+            if(hour == 24)
+            {
+              hour = 0;
+              day++;
+              if(day == 365)
+              {
+                day = 0;
+                year++;
+              }
+            }
+          }
+        }
+      }
+
+      // Software-Uhr
+      //
+      if(dtmSec >= 1000)
+      {
+        dtmSec -= 1000;
+
+        dtSec++;
+        dateTimeStr[20] = '0';
+        dateTimeStr[21] = '0';
+        dateTimeStr[22] = '0';
+
+        if(dtSec == 60)
+        {
+          dtSec = 0;
+          dtMin++;
+          dateTimeStr[17] = '0';
+          dateTimeStr[18] = '0';
+
+          if(dtMin == 60)
+          {
+            dtMin = 0;
+            dtHour++;
+            dateTimeStr[14] = '0';
+            dateTimeStr[15] = '0';
+
+            if(dtHour == 24)
+            {
+              dtHour = 0;
+              dtDay++;
+              dateTimeStr[11] = '0';
+              dateTimeStr[12] = '0';
+
+              if  (
+                       (dtDay == (febLen + 1) && dtMonth == 2)
+                    || (dtDay == 31 && (dtMonth == 4 ||
+                                        dtMonth == 6 ||
+                                        dtMonth == 9 ||
+                                        dtMonth == 11))
+                    || dtDay == 32
+                  )
+              {
+                dtDay = 1;
+                dtMonth++;
+                dateTimeStr[8] = '0';
+                dateTimeStr[9] = '1';
+
+                if(dtMonth == 13)
+                {
+                  dtMonth = 1;
+                  dtYear++;
+                  tmpInt = dtYear - 2000;
+                  if((tmpInt % 4) == 0)
+                    febLen = 29;
+                  else
+                    febLen = 28;
+                  dateTimeStr[5] = '0';
+                  dateTimeStr[6] = '1';
+
+                  divResult   = DIV(tmpInt,100);
+                  tmpInt100   = divResult.quot;
+                  tmpInt      = divResult.rem;
+
+                  divResult   = DIV(tmpInt,10);
+                  tmpInt10    = divResult.quot;
+                  tmpInt1     = divResult.rem;
+
+                  dateTimeStr[1] = (char) (tmpInt100 | 0x30);
+                  dateTimeStr[2] = (char) (tmpInt10  | 0x30);
+                  dateTimeStr[3] = (char) (tmpInt1   | 0x30);
+                }
+                else
+                {
+                  divResult      = DIV(dtMonth,10);
+                  dateTimeStr[5] = (char) (divResult.quot | 0x30);
+                  dateTimeStr[6] = (char) (divResult.rem  | 0x30);
+                }
+              }
+              else
+              {
+                divResult      = DIV(dtDay,10);
+                dateTimeStr[8] = (char) (divResult.quot | 0x30);
+                dateTimeStr[9] = (char) (divResult.rem  | 0x30);
+              }
+            }
+            else
+            {
+              divResult       = DIV(dtHour,10);
+              dateTimeStr[11] = (char) (divResult.quot | 0x30);
+              dateTimeStr[12] = (char) (divResult.rem  | 0x30);
+            }
+          }
+          else
+          {
+            divResult       = DIV(dtMin,10);
+            dateTimeStr[14] = (char) (divResult.quot | 0x30);
+            dateTimeStr[15] = (char) (divResult.rem  | 0x30);
+          }
+        }
+        else
+        {
+          divResult     = DIV(dtSec,10);
+          dateTimeStr[17] = (char) (divResult.quot | 0x30);
+          dateTimeStr[18] = (char) (divResult.rem  | 0x30);
+        }
+      }
+      else
+      {
+        divResult   = DIV(dtmSec,100);
+        tmpInt100   = divResult.quot;
+        tmpInt      = divResult.rem;
+
+        divResult   = DIV(tmpInt,10);
+        tmpInt10    = divResult.quot;
+        tmpInt1     = divResult.rem;
+
+        dateTimeStr[20] = (char) (tmpInt100 | 0x30);
+        dateTimeStr[21] = (char) (tmpInt10  | 0x30);
+        dateTimeStr[22] = (char) (tmpInt1   | 0x30);
+      }
+
+    }
+
+    if(firstLoop == false)
+    {
+      backgroundMicros = loopStartMicros - loopEndMicros;
+      if(backgroundMicros > backgroundMaxMicros)
+        backgroundMaxMicros = backgroundMicros;
+      if(backgroundMicros < backgroundMinMicros)
+        backgroundMinMicros = backgroundMicros;
+      periodMicros = loopStartMicros - lastStartMicros;
+      if(periodMicros > periodMaxMicros)
+        periodMaxMicros = periodMicros;
+      periodSumMicros += periodMicros;
+      if(periodMicros < periodMinMicros)
+        periodMinMicros = periodMicros;
+      if(periodMicros > PeriodMinTime)
+      {
+        periodFailAlarm = true;
+        periodFailCount++;
+      }
+
+      divResult = DIV(periodMicros, 1000);
+      if(divResult.quot > 0)
+      {
+        if(divResult.quot >= LoopScreeningGrades)
+          ++loopScreening[LoopScreeningGrades - 1];
+        else
+          ++loopScreening[divResult.quot -1];
+      }
+    } // if()
+
+    lastStartMicros = loopStartMicros;
+
+  }
+
+
+  unsigned int LoopCheck::done()
+  {
+    return(SYSMICSEC - loopStartMicros);
+  }
+
+  void LoopCheck::end()
+  {
+    loopEndMicros = SYSMICSEC;
+    loopMicros = loopEndMicros - loopStartMicros;
+    if(loopMicros > loopMaxMicros)
+      loopMaxMicros = loopMicros;
+    if(loopMicros < loopMinMicros)
+      loopMinMicros = loopMicros;
+
+    if(firstLoop == false)
+    {
+      loopSumMicros += loopMicros;
+      backgroundSumMicros += backgroundMicros;
+      calcAvgCounter++;
+      if(calcAvgCounter == CalcAverageDepth)
+      {
+        loopAvgMicros = loopSumMicros / CalcAverageDepth;
+        backgroundAvgMicros = backgroundSumMicros / CalcAverageDepth;
+        periodAvgMicros = periodSumMicros / CalcAverageDepth;
+        calcAvgCounter = 0;
+        loopSumMicros = 0;
+        backgroundSumMicros = 0;
+        periodSumMicros = 0;
+      }
+    }
+    else
+    {
+      loopAvgMicros = loopMicros;
+      backgroundAvgMicros = backgroundMicros;
+    }
+
+    loopCounter++;
+    firstLoop = false;
+    taskHappened = false;
+  }
+
+  bool LoopCheck::timerMicro
+    (int taskIdx, unsigned long repeatTime, unsigned int repetitions, unsigned long delay)
+  {
+    TimerTask     *ctrlPtr;
+    unsigned long calcMics;
+
+    // Test the limit of enabled timers
+    //
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfTimerTasks) return(false);
+
+    // Get the reference to timer data for the selected timer
+    //
+    ctrlPtr = &timerTaskList[taskIdx];
+
+    // If the timer task has finished, we are ready here
+    //
+    if(ctrlPtr->finished == true) return(false);
+
+    // If it is the first run (initialisation 1)
+    //
+    if(ctrlPtr->firstRun == true)
+    {
+      ctrlPtr->firstRun     = false;
+      ctrlPtr->repCounter   = repetitions;
+      ctrlPtr->delayCounter = delay;
+    }
+
+    // If counting is not started yet (initialisation 2)
+    //
+    if(ctrlPtr->counterStarted == false)
+    {
+      ctrlPtr->startCount = loopStartMicros;
+      ctrlPtr->counterStarted = true;
+      return(false);
+    }
+
+    // If another count task has happened in this loop, we have to wait
+    //
+    if(taskHappened == true) return(false);
+
+    // Calculate the number of microseconds since the start of the counter
+    //
+    calcMics = loopStartMicros - ctrlPtr->startCount;
+    ctrlPtr->ticks = calcMics;
+
+    // If there is a delay, wait the delay time
+    //
+    if(ctrlPtr->delayCounter > 0)
+    {
+      if(calcMics < ctrlPtr->delayCounter)
+        return(false);
+      else
+      {
+        ctrlPtr->delayCounter = 0;                // delay finished
+        ctrlPtr->startCount = loopStartMicros;    // reset counter
+      }
+      return(false);
+    }
+
+    // There is no delay (or delay is finished)
+    // If repeatTime is not passed, leave with FALSE
+    //
+    if(calcMics < repeatTime)
+    {
+      return(false);
+    }
+
+    // One counter period finished
+    //
+    taskHappened            = true;               // disable other timers in this loop
+    ctrlPtr->counterStarted = false;              // prepare resetting the counter
+    ctrlPtr->runCounter++;                        // count the timer events
+
+    // If the number of periods is limited finish in time
+    //
+    if(ctrlPtr->repCounter > 0)
+    {
+      ctrlPtr->repCounter--;
+      if(ctrlPtr->repCounter == 0)
+        ctrlPtr->finished = true;
+    }
+
+    return(true);
+  }
+
+  bool LoopCheck::timerMicro
+    (int taskIdx, unsigned long repeatTime, unsigned int repetitions)
+  {
+    return(timerMicro(taskIdx, repeatTime, repetitions, 0));
+  }
+
+
+  bool LoopCheck::timerMilli
+    (int taskIdx, unsigned long repeatTime, unsigned int repetitions, unsigned long delay)
+  {
+    return(timerMicro(taskIdx, repeatTime * 1000, repetitions, delay * 1000));
+  }
+
+  bool LoopCheck::timerMilli
+    (int taskIdx, unsigned long repeatTime, unsigned int repetitions)
+  {
+    return(timerMicro(taskIdx,repeatTime * 1000,repetitions,0));
+  }
+
+  bool LoopCheck::once(int taskIdx)
+  {
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfOnceTasks) return(false);
+
+    if(onceTaskList[taskIdx].finished == true) return(false);
+    onceTaskList[taskIdx].finished = true;
+    return(true);
+  }
+
+  bool LoopCheck::once(int taskIdx, unsigned int nrOfLoops)
+  {
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfOnceTasks) return(false);
+
+    if(onceTaskList[taskIdx].finished == true) return(false);
+    if(nrOfLoops <= 1)
+    {
+      onceTaskList[taskIdx].finished = true;
+      return(true);
+    }
+
+    if(onceTaskList[taskIdx].firstRun == true)
+    {
+      onceTaskList[taskIdx].firstRun = false;
+      onceTaskList[taskIdx].waitCounter = nrOfLoops;
+    }
+
+    onceTaskList[taskIdx].waitCounter--;
+    if(onceTaskList[taskIdx].waitCounter > 0)
+      return(false);
+
+    onceTaskList[taskIdx].finished = true;
+    return(true);
+  }
+
+  bool LoopCheck::onceDelayed(int taskIdx, unsigned long delay)
+  {
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfOnceTasks) return(false);
+
+    if(onceTaskList[taskIdx].finished == true) return(false);
+
+    if(onceTaskList[taskIdx].firstRun == true)
+    {
+      onceTaskList[taskIdx].firstRun = false;
+      onceTaskList[taskIdx].startCount = loopStartMicros;
+    }
+
+    if(loopStartMicros - onceTaskList[taskIdx].startCount < delay)
+      return(false);
+
+    onceTaskList[taskIdx].finished = true;
+    return(true);
+  }
+
+  bool LoopCheck::toggle(int taskIdx)
+  {
+    bool    toggleBit;
+
+    if(taskIdx < 0) return(false);
+    if(taskIdx >= NrOfToggleTasks) return(false);
+    toggleBit = toggleTaskList[taskIdx];
+    toggleTaskList[taskIdx] = !toggleBit;
+    return(toggleBit);
+  }
+
+  unsigned long LoopCheck::timerCycle(int taskIdx)
+  {
+    if(taskIdx < 0) return(0);
+    if(taskIdx >= NrOfTimerTasks) return(0);
+    return(timerTaskList[taskIdx].runCounter);
+  }
+
+  bool LoopCheck::timerCycleMod(int taskIdx, int modulo)
+  {
+    div_t divResult;
+
+    if(taskIdx < 0) return(0);
+    if(taskIdx >= NrOfTimerTasks) return(0);
+    divResult   = DIV(timerTaskList[taskIdx].runCounter,modulo);
+    if(divResult.rem == 0)
+      return(true);
+    else
+      return(false);
+  }
+
+  unsigned long LoopCheck::tick(int taskIdx)
+  {
+    if(taskIdx < 0) return(0);
+    if(taskIdx >= NrOfTimerTasks) return(0);
+    return(timerTaskList[taskIdx].ticks);
+  }
+
+  unsigned long LoopCheck::operationTime(OpHourMeter *opHourMeter)
+  {
+    opHourMeter->Milliseconds    = msec;
+    opHourMeter->Seconds         = sec;
+    opHourMeter->Minutes         = min;
+    opHourMeter->Hours           = hour;
+    opHourMeter->Days            = day;
+    opHourMeter->Years           = year;
+    return(loopStartMicros);
+  }
+
+  unsigned long LoopCheck::getStatistics(LoopStatistics *statistics)
+  {
+    statistics->loopTime    =   (unsigned int) loopMicros;
+    statistics->loopMaxTime =   (unsigned int) loopMaxMicros;
+    statistics->loopMinTime =   (unsigned int) loopMinMicros;
+    statistics->loopAvgTime =   (unsigned int) loopAvgMicros;
+
+    statistics->bgTime      =   (unsigned int) backgroundMicros;
+    statistics->bgMaxTime   =   (unsigned int) backgroundMaxMicros;
+    statistics->bgMinTime   =   (unsigned int) backgroundMinMicros;
+    statistics->bgAvgTime   =   (unsigned int) backgroundAvgMicros;
+
+    statistics->alarmCount  =   periodFailCount;
+    statistics->periodAlarm =   periodFailAlarm;
+    periodFailAlarm = false;
+
+    statistics->loopPeriod  =   periodMicros;
+    statistics->maxPeriod   =   periodMaxMicros;
+    statistics->minPeriod   =   periodMinMicros;
+    statistics->avgPeriod   =   periodAvgMicros;
+
+    for (int i = 0; i < LoopScreeningGrades; i++)
+      statistics->rtScreening[i] = loopScreening[i];
+
+    return(loopCounter);
+  }
+
+  void LoopCheck::resetStatistics()
+  {
+    backgroundMicros        = 0;
+    loopMicros              = 0;
+
+    backgroundMaxMicros     = 0;
+    backgroundMinMicros     = (unsigned long) -1;
+    backgroundAvgMicros     = 0;
+
+    loopMaxMicros           = 0;
+    loopMinMicros           = (unsigned long) -1;
+    loopAvgMicros           = 0;
+    loopCounter             = 0;
+
+    periodFailCount         = 0;
+    periodMaxMicros         = 0;
+    periodMinMicros         = (unsigned int) -1;
+    periodAvgMicros         = 0;
+    periodMicros            = 0;
+    periodFailAlarm         = false;
+
+    for (int i = 0; i < LoopScreeningGrades; i++)
+      loopScreening[i] = 0;
+
+    calcAvgCounter          = 0;
+  }
+
+  bool LoopCheck::setDateTime(const char *dtStr)
+  {
+    int tmpInt;
+
+     if(strlen(dtStr) < 23) return(false);
+     strcpy(dateTimeStr,dtStr);
+     dtYear   = (dateTimeStr[0]  & 0x0F) * 1000 +
+                (dateTimeStr[1]  & 0x0F) * 100  +
+                (dateTimeStr[2]  & 0x0F) * 10   +
+                (dateTimeStr[3]  & 0x0F);
+
+     tmpInt = dtYear - 2000;
+     if((tmpInt % 4) == 0)
+       febLen = 29;
+     else
+       febLen = 28;
+
+
+     dtMonth  = (dateTimeStr[5]  & 0x0F) * 10   +
+                (dateTimeStr[6]  & 0x0F);
+
+     dtDay    = (dateTimeStr[8]  & 0x0F) * 10   +
+                (dateTimeStr[9]  & 0x0F);
+
+     dtHour   = (dateTimeStr[11] & 0x0F) * 10   +
+                (dateTimeStr[12] & 0x0F);
+
+     dtMin    = (dateTimeStr[14] & 0x0F) * 10   +
+                (dateTimeStr[15] & 0x0F);
+
+     dtSec    = (dateTimeStr[17] & 0x0F) * 10   +
+                (dateTimeStr[18] & 0x0F);
+
+     dtmSec   = (dateTimeStr[20] & 0x0F) * 10   +
+                (dateTimeStr[21] & 0x0F) * 10   +
+                (dateTimeStr[22] & 0x0F);
+
+     return(true);
+  }
+
+  bool LoopCheck::setDateTime(lcDateTime dt)
+  {
+    div_t   divResult;
+    int     tmpInt;
+
+    dtYear    = dt.Year;
+
+    tmpInt = dtYear - 2000;
+    if((tmpInt % 4) == 0)
+      febLen = 29;
+    else
+      febLen = 28;
+
+
+    divResult = DIV(dtYear,1000);
+    dateTimeStr[0] = (char) (0x30 + divResult.quot);
+
+    divResult = DIV(divResult.rem,100);
+    dateTimeStr[1] = (char) (0x30 + divResult.quot);
+
+    divResult = DIV(divResult.rem,10);
+    dateTimeStr[2] = (char) (0x30 + divResult.quot);
+    dateTimeStr[3] = (char) (0x30 + divResult.rem);
+
+    dtMonth   = dt.Month;
+    divResult = DIV(dtMonth,10);
+    dateTimeStr[5] = (char) (0x30 + divResult.quot);
+    dateTimeStr[6] = (char) (0x30 + divResult.rem);
+
+    dtDay     = dt.Day;
+    divResult = DIV(dtDay,10);
+    dateTimeStr[8] = (char) (0x30 + divResult.quot);
+    dateTimeStr[9] = (char) (0x30 + divResult.rem);
+
+    dtHour    = dt.Hour;
+    divResult = DIV(dtHour,10);
+    dateTimeStr[11] = (char) (0x30 + divResult.quot);
+    dateTimeStr[12] = (char) (0x30 + divResult.rem);
+
+    dtMin     = dt.Minute;
+    divResult = DIV(dtMin,10);
+    dateTimeStr[14] = (char) (0x30 + divResult.quot);
+    dateTimeStr[15] = (char) (0x30 + divResult.rem);
+
+    dtSec     = dt.Second;
+    divResult = DIV(dtSec,10);
+    dateTimeStr[17] = (char) (0x30 + divResult.quot);
+    dateTimeStr[18] = (char) (0x30 + divResult.rem);
+
+    dtmSec    = dt.Millisecond;
+    divResult = DIV(dtmSec, 100);
+    dateTimeStr[20] = (char) (0x30 + divResult.quot);
+    divResult = DIV(divResult.rem, 10);
+    dateTimeStr[21] = (char) (0x30 + divResult.quot);
+    dateTimeStr[22] = (char) (0x30 + divResult.rem);
+
+    return(true);
+  }
+
+  bool LoopCheck::getDateTime(lcDateTime *dt)
+  {
+    dt->Year        = dtYear;
+    dt->Month       = dtMonth;
+    dt->Day         = dtDay;
+    dt->Hour        = dtHour;
+    dt->Minute      = dtMin;
+    dt->Second      = dtSec;
+    dt->Millisecond = dtmSec;
+    return(true);
+  }
+
+  const char * LoopCheck::refDateTime()
+  {
+    return(dateTimeStr);
+  }
+
+  unsigned long LoopCheck::locMicros()
+  {
+#ifdef smnSimLinux
+    struct timespec clockTime;
+    unsigned long retv;
+
+    clock_gettime(CLOCK_MONOTONIC, &clockTime);
+    retv = clockTime.tv_nsec / 1000;
+    return(retv);
+#endif
+
+#ifdef smnSimWindows
+    LARGE_INTEGER countValue, frequency, result;
+
+    QueryPerformanceCounter(&countValue);
+    QueryPerformanceFrequency(&frequency);
+
+    result.QuadPart = (countValue.QuadPart * 1000000) / frequency.QuadPart;
+    return((unsigned long) result.QuadPart);
+#endif
+
+#ifdef smnSloeber
+    return(micros());
+#endif
+  }
+
+#ifdef smnESP8266
+  div_t LoopCheck::locDiv(int numer, int denom)
+  {
+    div_t retv;
+
+    retv.quot = numer / denom;
+    retv.rem  = numer % denom;
+
+    return(retv);
+  }
+#endif
+
+  void LoopCheck::startTimeMeasure()
+  {
+    measureTimeSet = SYSMICSEC;
+  }
+
+  unsigned long LoopCheck::getTimeMeasure()
+  {
+    return(SYSMICSEC - measureTimeSet);
+  }
+
+  unsigned long LoopCheck::getRuntime()
+  {
+    return(measureRuntime);
+  }
+
+  void LoopCheck::hexAsc(char * dest, byte val)
+  {
+    char cv;
+
+    cv = val >> 4;
+    if(cv < 10)
+      cv += 0x30;
+    else
+      cv += 0x37;
+    dest[0] = cv;
+
+    cv = val & 0x0F;
+    if(cv < 10)
+      cv += 0x30;
+    else
+      cv += 0x37;
+    dest[1] = cv;
+
+    dest[2] = '\0';
+  }
+
+
+  // -------------------------------------------------------------------------
+  // Debug-Funktionen
+  // -------------------------------------------------------------------------
+  //
+#ifdef smnLoopCheckDebug
+
+  void LoopCheck::dbgGetStatistics(char *buffer, int idxItem)
+  {
+    switch(idxItem)
+    {
+      case 0:
+        sprintf(buffer,"lT=%d, lMaxT=%d, lMinT=%d, lAvgT=%d",
+            loopMicros,loopMaxMicros,loopMinMicros,loopAvgMicros);
+        break;
+
+      case 1:
+        sprintf(buffer,"bT=%d, bMaxT=%d, bMinT=%d, bAvgT=%d",
+            backgroundMicros,backgroundMaxMicros,backgroundMinMicros,backgroundAvgMicros);
+        break;
+
+      case 2:
+        sprintf(buffer,"rtAlCnt=%d, lCnt=%d, Scr=%d,%d,%d,%d,%d,%d",
+            periodFailCount, loopCounter, loopScreening[0],loopScreening[1],loopScreening[2],loopScreening[3],loopScreening[4],loopScreening[5]);
+        break;
+    }
+  }
+
+#endif
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/LoopCheck.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/LoopCheck.h
new file mode 100644
index 0000000000000000000000000000000000000000..9588f3e56dc3ebe52890b772533793e533aad05d
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/LoopCheck.h
@@ -0,0 +1,343 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   LoopCheck.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (siehe Wikipedia: Creative Commons)
+//
+#ifndef _LoopCheck_h
+#define _LoopCheck_h
+//-----------------------------------------------------------------------------
+
+#define PeriodMinTime       5000
+// Wenn der Aufrufzyklus der Loop diese Zeit (in Mikrosekunden) überschreitet,
+// dann wird ein Alarmbit gesetzt und ein Alarmzähler inkrementiert
+
+#ifndef LoopScreeningGrades
+  #define LoopScreeningGrades 6
+#endif
+
+#define NrOfTimerTasks      10
+
+#define lcTimer0  0
+#define lcTimer1  1
+#define lcTimer2  2
+#define lcTimer3  3
+#define lcTimer4  4
+#define lcTimer5  5
+#define lcTimer6  6
+#define lcTimer7  7
+#define lcTimer8  8
+#define lcTimer9  9
+
+
+#define NrOfOnceTasks       4
+
+#define lcOnce0  0
+#define lcOnce1  1
+#define lcOnce2  2
+#define lcOnce3  3
+
+#define NrOfToggleTasks     4
+
+#define lcToggle0  0
+#define lcToggle1  1
+#define lcToggle2  2
+#define lcToggle3  3
+
+#define CalcAverageDepth    32
+
+#ifdef UseGithubPath
+  #include "../environment/environment.h"
+#else
+  #include "environment.h"
+#endif
+
+#if defined(smnSimLinux) || defined(smnSimWindows)
+  #include <stdlib.h>
+  #include <string.h>
+  #include <time.h>
+  #define SYSMICSEC locMicros()
+#endif
+
+#ifdef smnSimWindows
+#include <Windows.h>
+#endif
+
+#ifdef smnSloeber
+  #include "Arduino.h"
+  #define SYSMICSEC    micros()
+#endif
+
+#ifdef smnESP8266
+  #define DIV(x,y)    locDiv(x,y)
+#else
+  #define DIV(x,y)    div(x,y)
+#endif
+
+typedef struct _OpHourMeter
+{
+  int   Years;
+  int   Days;
+  int   Hours;
+  int   Minutes;
+  int   Seconds;
+  int   Milliseconds;
+} OpHourMeter;
+
+typedef struct _lcDateTime
+{
+  int   Year;
+  int   Month;
+  int   Day;
+  int   Hour;
+  int   Minute;
+  int   Second;
+  int   Millisecond;
+} lcDateTime;
+
+typedef struct _LoopStatistics
+{
+  unsigned int  loopTime;       // Schleifenzeit in Mikrosekunden
+  unsigned int  loopMaxTime;    // Maximale Schleifenzeit
+  unsigned int  loopMinTime;    // Minimale Schleifenzeit
+  unsigned int  loopAvgTime;    // Mittlere Schleifenzeit
+
+  unsigned int  bgTime;         // Zeit außerhalb der Schleife
+  unsigned int  bgMaxTime;      // Maximale Außenzeit
+  unsigned int  bgMinTime;      // Minimale Außenzeit
+  unsigned int  bgAvgTime;      // Mittlere Außenzeit
+
+  unsigned int  loopPeriod;     // Zeit zwischen loop-Aufrufen
+  unsigned int  maxPeriod;      // Maximale Aufrufdistanz
+  unsigned int  minPeriod;      // Minimale Aufrufdistanz
+  unsigned int  avgPeriod;      // Mittlere Aufrufdistanz
+
+  bool          periodAlarm;    // Aufrufdistanz > PeriodMinTime
+  unsigned int  alarmCount;     // Anzahl der Überschreitungen
+
+  unsigned int  rtScreening[LoopScreeningGrades];
+  // Echtzeitüberwachung (Klassierung der ms Überschreitungen)
+} LoopStatistics;
+
+
+// ---------------------------------------------------------------------------
+// class LoopCheck
+// ---------------------------------------------------------------------------
+//
+class LoopCheck
+{
+  // -------------------------------------------------------------------------
+  // Klassenspezifische Datentypen
+  // -------------------------------------------------------------------------
+  //
+  typedef struct _TimerTask
+  {
+    bool            counterStarted;
+    bool            finished;
+    bool            firstRun;
+    unsigned long   startCount;
+    unsigned long   runCounter;
+    unsigned long   delayCounter;
+    unsigned long   ticks;
+    unsigned int    repCounter;
+  } TimerTask;
+
+  typedef struct _OnceTask
+  {
+    bool            finished;
+    bool            firstRun;
+    unsigned int    waitCounter;
+    unsigned long   startCount;
+  } OnceTask;
+
+private:
+  // -------------------------------------------------------------------------
+  // Lokale Variablen
+  // -------------------------------------------------------------------------
+  //
+  unsigned long checkStartMicros;       // Zeit des ersten Aufrufs von begin()
+
+  unsigned long backgroundMicros;       // Zeit, die außerhalb von loop()
+                                        // verstrichen ist (in Mikrosekunden)
+  unsigned long loopMicros;             // Zeit, die innerhalb von loop()
+                                        // verstrichen ist (in Mikrosekunden)
+  unsigned long loopStartMicros;        // Loop-Startzeit (us seit CPU-Start)
+  unsigned long lastClockMicros;
+  unsigned long lastStartMicros;
+  unsigned long lastRestMicros;
+
+  unsigned long loopEndMicros;          // Loop-Endezeit (us seit CPU-Start)
+  unsigned long clockCycleMicros;       // Abstand zwischen zwei clock ticks
+  unsigned long mainStartMicros;        // Zählerstand bei Programmstart
+
+  unsigned long backgroundMaxMicros;    // Maximale Zeit außerhalb loop()
+  unsigned long backgroundMinMicros;    // Minimale Zeit außerhalb loop()
+  unsigned long backgroundAvgMicros;    // Mittlere Zeit außerhal loop() {32}
+  unsigned long backgroundSumMicros;    // Summe für Mittelwertberechnung
+
+  unsigned long loopMaxMicros;          // Maximale Zeit innerhalb loop()
+  unsigned long loopMinMicros;          // Minimale Zeit innerhalb loop()
+  unsigned long loopAvgMicros;          // Mittlere Zeit innerhalb loop()
+  unsigned long loopSumMicros;          // Summe für Mittelwertberechnung
+
+  unsigned long loopCounter;            // Anzahl der loop()-Durchläufe
+
+  unsigned int  loopScreening[LoopScreeningGrades];
+
+  int           calcAvgCounter;         // Zähler für die Mittelwertbildung
+  bool          firstLoop;              // Spezielle Kennzeichnung erste loop()
+  bool          taskHappened;           // Kennzeichnung: Es lief ein LoopTask
+
+  TimerTask     timerTaskList[NrOfTimerTasks];  // Steuerung der zyklischen
+                                                // Tasks (Timer-Ersatz in loop())
+  OnceTask      onceTaskList[NrOfOnceTasks];
+  bool          toggleTaskList[NrOfToggleTasks];
+
+  int           year;               // Betriebsstundenzähler gesamt
+  int           day;
+  int           hour;
+  int           min;
+  int           sec;
+  int           msec;
+  bool          toggleMilli;
+
+  int           dtYear;             // Zeit / Uhr
+  int           dtMonth;
+  int           dtDay;
+  int           dtHour;
+  int           dtMin;
+  int           dtSec;
+  int           dtmSec;
+  int           febLen;
+  char          dateTimeStr[30];
+
+  unsigned int  periodMicros;           // Zeit zwischen zwei loop-Aufrufen
+  unsigned int  periodMinMicros;
+  unsigned int  periodMaxMicros;
+  unsigned int  periodAvgMicros;
+  unsigned int  periodSumMicros;
+
+  bool          periodFailAlarm;        // periodMicros > Millisekunde
+  unsigned int  periodFailCount;        // Anzahl der Überschreitungen
+
+  unsigned long measureTimeSet;         // Mikrosekunden-Offset Zeitmessung
+
+  unsigned long measureRuntime;         // Laufzeit seit Start in Sekunden
+
+private:
+  // -------------------------------------------------------------------------
+  // Lokale Funktionen
+  // -------------------------------------------------------------------------
+  //
+  void initTasks();
+  void initStatistics();
+  void initClock();
+  unsigned long locMicros();
+#ifdef smnESP8266
+  div_t locDiv(int numer, int denom);
+#endif
+
+public:
+  // -------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // -------------------------------------------------------------------------
+  //
+  LoopCheck();
+
+  // -------------------------------------------------------------------------
+  // Anwenderfunktionen
+  // -------------------------------------------------------------------------
+  //
+  void begin();     // Diese Funktion muss am Anfang der Schleife aufgerufen
+                    // werden.
+
+  unsigned int done();  // Diese Funktion kann vor dem Aufruf von end()
+                        // genutzt werden und liefert die Laufzeit bis dahin
+
+  void end();       // Diese Funktion muss am Ende der Schleife aufgerufen
+                    // werden.
+
+  bool timerMicro(int taskIdx, unsigned long repeatTime, unsigned int repetitions);
+  bool timerMicro(int taskIdx, unsigned long repeatTime, unsigned int repetitions, unsigned long delay);
+  // Diese Funktion muss als Bedingung (if) aufgerufen werden, um den
+  // nachfolgenden Block {} mit der Wiederholzeit <repeatTime> auszuführen
+  // Für jede Taskschleife muss ein anderer Index <taskIdx> aus dem Bereich
+  // 0 <= taskIdx < MaxNrOfLoopTasks angegeben werden.
+  // Mit <repetitions> wird angegeben, wie oft der Durchlauf überhaupt erfolgt.
+  // Der Wert 0 gibt an, dass der Task für immer läuft
+
+  bool timerMilli(int taskIdx, unsigned long repeatTime, unsigned int repetitions);
+  bool timerMilli(int taskIdx, unsigned long repeatTime, unsigned int repetitions, unsigned long delay);
+
+  bool once(int taskIdx);
+  // Diese Funktion liefert nur einmal den Wert <true>
+
+  bool once(int taskIdx, unsigned int nrOfLoops);
+  // Diese Funktion liefert nur einmal den Wert <true>
+  // nach Ablauf von nrOfLoops Aufrufen
+
+  bool onceDelayed(int taskIdx, unsigned long delay);
+  // Diese Funktion liefert nur einmal den Wert <true>
+  // nach Ablauf von <delay> Mikrosekunden
+
+  bool toggle(int taskIdx);
+  // Diese Funktion liefert abwechselnd die Werte <true> oder <false>
+
+  unsigned long timerCycle(int taskIdx);
+  // Rückgabe des aktuellen Timerablaufes (startet ab 0).
+
+  bool timerCycleMod(int taskIdx, int modulo);
+  // Liefert alle <modulo> Timerabläufe den Wert <true>
+
+  unsigned long tick(int taskIdx);
+  // Rückgabe des aktuellen Zählwertes in Mikrosekunden
+
+  unsigned long operationTime(OpHourMeter *opHourMeter);
+  // Die Zeit ab Start der CPU
+
+  unsigned long getStatistics(LoopStatistics *statistics);
+  // Statistik über Ablaufzeiten
+
+  void resetStatistics();
+  // Rücksetzen der Statistikdaten
+
+  bool setDateTime(const char *dtStr);
+  // Setzen der Uhr über standardisierten String
+
+  bool setDateTime(lcDateTime dt);
+  // Setzen der Uhr über lokal definierte Struktur
+
+  bool getDateTime(lcDateTime *dt);
+  // Abfragen der Uhr über lokal definierte Struktur
+
+  const char * refDateTime();
+  // Zeiger auf Datum/Uhrzeit holen
+
+  void startTimeMeasure();
+  // Zeitmessung starten
+
+  unsigned long getTimeMeasure();
+  // Zeitmesswert holen
+
+  unsigned long getRuntime();
+  // Laufzeit in Sekunden
+
+  void hexAsc(char * dest, byte val);
+  // Umwandlung byte in Hex-ASCII
+
+  // -------------------------------------------------------------------------
+  // Debug-Funtionen
+  // -------------------------------------------------------------------------
+  //
+
+#ifdef smnLoopCheckDebug
+  void dbgGetStatistics(char *buffer, int idxItem);
+#endif
+
+};
+
+//-----------------------------------------------------------------------------
+#endif
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/ReadMe.md b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/ReadMe.md
new file mode 100644
index 0000000000000000000000000000000000000000..7701d9d3347942f8c88807f2f8342bade47ace46
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/ReadMe.md
@@ -0,0 +1,20 @@
+# Tools for cyclic called procedures
+Arduino Sketches are build on two basic functions. 
+*void setup()* is called once when the CPU is reset and programmers place their initialisation code here.
+*void loop()* is called in an endless loop, i.e. a cyclic entered function. 
+But the cycle time is not determined, it depends on the speed of the CPU and the used resources.
+Many examples for Arduino use the function *delay(milliseconds)* to organise a kind of timing. 
+But this function is really freezing your program for the given number of milliseconds.
+Using a real timer is a good solution, but some CPUs have only less timers 
+and they sometimes are already used for some libraries.
+
+The tools presented with LoopCheck-library give You the features of (many) timers inside *loop()* 
+based on the Arduino-function *micros()* which is called with the macro SYSMICSEC, 
+defined in *LoopCheck.h*.
+
+You will find, that there is another file included: *environment.h*, which you can find here:
+https://github.com/RobertPatzke/homeautomation/blob/developer/libraries/environment/environment.h
+*environment.h* defines the IDE you are using, the CPU and specific development boards. 
+Code is in several parts conditional, depending on the definitions you make in *environment.h*.
+You will see, that this library is not fixed to Arduino, it may be used for any environment
+where cyclic called functions happen.
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..3af69246689b448266e74521f4ff1d792450456f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/LoopCheck/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "LoopCheck",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/MidiNotes/MidiNotes.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/MidiNotes/MidiNotes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec91464f7411b1f25f33b3b536faf3b8dc1e8dcd
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/MidiNotes/MidiNotes.cpp
@@ -0,0 +1,405 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   Midi.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   27. November 2021
+//
+// Der Inhalt dieser Datei sind Festlegungen für steuerbare Midi-Controller.
+//
+//
+
+#include "MidiNotes.h"
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+//
+
+void MidiNotes::begin(int inBpm, NoteDiv inRes, int inMidiCycle, IntrfBuf *inCRB)
+{
+  dword       stdNoteMicroTick;
+
+  crb = inCRB;                        // Zeiger auf Ringpuffer
+  midiCycle = inMidiCycle;            // Zuklus der ZM in Mikrosekunden
+  bpm = inBpm;                        // Beats Per Minute (Metronom)
+  stdNoteMicroTick = 60000000 / bpm;  // Viertelnotenlänge in Mikrosekunden
+  stdNoteCount = stdNoteMicroTick / inMidiCycle;  // "  in Zyklen der ZM
+  stdNoteTick = 60000 / bpm;          // Viertelnotenlänge in Millisekunden
+  minNoteTick = stdNoteTick / inRes;  // Zu erwartende kürzeste Note (ms)
+
+  typeList[nti0].length   = 8 * stdNoteCount;
+  setNoteType(nti0);
+
+  typeList[nti1].length   = 4 * stdNoteCount;
+  setNoteType(nti1);
+
+  typeList[nti2p].length  = 3 * stdNoteCount;
+  setNoteType(nti2p);
+
+  typeList[nti2].length   = 2 * stdNoteCount;
+  setNoteType(nti2);
+
+  typeList[nti4p].length  = stdNoteCount + stdNoteCount / 2;
+  setNoteType(nti4p);
+
+  // Standard-Note = Viertelnote (
+  typeList[nti4].length   = stdNoteCount;
+  setNoteType(nti4);
+
+  typeList[nti8].length   = stdNoteCount / 2;
+  setNoteType(nti8);
+
+  typeList[nti8p].length  = stdNoteCount / 2 + stdNoteCount / 4;
+  setNoteType(nti8p);
+
+  typeList[nti16].length  = stdNoteCount / 4;
+  setNoteType(nti16);
+
+  typeList[nti16p].length = stdNoteCount / 4 + stdNoteCount / 8;
+  setNoteType(nti16p);
+
+  typeList[nti32].length  = stdNoteCount / 8;
+  setNoteType(nti32);
+
+  typeList[nti32p].length = stdNoteCount / 8 + stdNoteCount / 16;
+  setNoteType(nti32p);
+
+  typeList[nti64].length  = stdNoteCount / 16;
+  setNoteType(nti64);
+
+  typeList[nti64p].length = stdNoteCount / 16 + stdNoteCount / 32;
+  setNoteType(nti64p);
+
+  opMode = momIdle;
+  setChannel(1);
+  stopRun = false;
+  stoppedRun = false;
+  next(smInit);
+}
+
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+//
+void MidiNotes::setNoteType(NoteTypeIdx nt)
+{
+  NoteTypePtr typePtr;
+
+  typePtr = &typeList[nt];
+  typePtr->attack   = 0;
+  typePtr->decay    = 0;
+  typePtr->sustain  = typePtr->length;
+  typePtr->release  = 0;
+  typePtr->pause    = (typePtr->length * 20) / 100;
+
+  typePtr->deltaAttack    = 0;
+  typePtr->deltaDecay     = 0;
+  typePtr->percentSustain = 70;
+  typePtr->deltaRelease   = 0;
+}
+
+
+void MidiNotes::setNoteType(NoteTypeIdx nt, byte pAttL, byte pDecL, byte pSusL, byte pRelL,
+                            byte pPauL, byte dAtt, byte dDec, byte pSusV, byte dRel)
+{
+  NoteTypePtr typePtr;
+
+  typePtr = &typeList[nt];
+  typePtr->attack   = (typePtr->length * pAttL) / 100;
+  typePtr->decay    = (typePtr->length * pDecL) / 100;
+  typePtr->sustain  = (typePtr->length * pSusL) / 100;
+  typePtr->release  = (typePtr->length * pRelL) / 100;
+  typePtr->pause    = (typePtr->length * pPauL) / 100;
+
+  typePtr->deltaAttack    = dAtt;
+  typePtr->deltaDecay     = dDec;
+  typePtr->percentSustain = pSusV;
+  typePtr->deltaRelease   = dRel;
+}
+
+int MidiNotes::addChordNote(NoteTypeIdx nti, byte val, byte vel)
+{
+  NotePtr notePtr;
+  int     i;
+
+  for(i = 0; i < MaxNrNoteSim; i++)
+  {
+    notePtr = &chord[i];
+    if(notePtr->mode == NoteModeEmpty)
+    {
+      notePtr->mode     = NoteModeRun;
+      notePtr->typeIdx  = nti;
+      notePtr->value    = val;
+      notePtr->veloc    = vel;
+      break;
+    }
+  }
+  return(i);
+}
+
+void MidiNotes::setChannel(int chnVal)
+{
+  if(chnVal < 1) chnVal = 1;
+  if(chnVal > 16) chnVal = 16;
+  chn = chnVal - 1;
+}
+
+// ----------------------------------------------------------------------------
+// Betrieb
+// ----------------------------------------------------------------------------
+//
+void MidiNotes::setOpMode(MidiOpMode mom)
+{
+  opMode = mom;
+}
+
+
+void MidiNotes::setChordNote(int idx, NoteTypeIdx nti, int val, int vel)
+{
+  if(idx < 0) return;
+  if(idx >= MaxNrNoteSim) return;
+
+  if(nti >= 0 && nti < ntiNr)
+    newNote[idx].typeIdx = nti;
+
+  if(val >= 0 && val <= 127)
+    newNote[idx].value = val;
+
+  if(vel >= 0 && vel <= 127)
+    newNote[idx].veloc = vel;
+
+  newNote[idx].newVal = true;
+}
+
+
+// ----------------------------------------------------------------------------
+// Steuerung, Zustandsmaschine
+// ----------------------------------------------------------------------------
+//
+
+void MidiNotes::stop()
+{
+  stopRun = true;
+}
+
+void MidiNotes::resume()
+{
+  stopRun = false;
+  stoppedRun = false;
+}
+
+void MidiNotes::run()
+{
+  runCounter++;
+  if(cycleCnt > 0) cycleCnt--;
+
+  if(nextState != NULL)
+    (this->*nextState)();
+}
+
+void MidiNotes::smInit()
+{
+  next(smIdle);
+}
+
+void MidiNotes::smIdle()
+{
+  switch(opMode)
+  {
+    case momIdle:
+      break;
+
+    case momSequence:
+      next(smNoteOn);
+      break;
+
+    case momRunDelta:
+      break;
+  }
+}
+
+void MidiNotes::smNoteOn()
+{
+  int   i, j, tIdx;
+  bool  doAttack;
+  dword attack, sustain;
+
+  if(stopRun || stoppedRun)         // Unterbrechen/Stoppen des Ablaufs
+  {                                 // vor dem Einschalten einer Note
+    stoppedRun = true;
+    return;
+  }
+
+  if(crb == NULL)                   // Ohne Ausgabepuffer in Wartezustand
+  {
+    next(smIdle);
+    return;
+  }
+
+  doAttack = false;                 // Voreinstellung kein Aufklingen
+
+  // Auslesen der Noten aus dem Akkordspeicher
+  //
+  j = 0;
+  for(i = 0; i < MaxNrNoteSim; i++)
+  {
+    notePtr = &chord[i];
+
+    if(i == 0)  // erste Note
+    {
+      if(notePtr->mode == NoteModeEmpty)  // Wenn die erste Note leer ist
+      {                                   // dann in den Wartezustand
+        next(smIdle);
+        return;
+      }
+      noteSeq[j++] = 0x90 | chn;          // ansonsten startet die Notenfolge **
+    }
+    else        // weitere Noten
+    {
+      if(notePtr->mode == NoteModeEmpty)  // bei leerer Note Schleife beendet
+        break;
+    }
+
+    // Die Noten im Akkordspeicher können durch aktuelle Noten
+    // ersetzt werden.
+
+    if(newNote[i].newVal) // wenn neue Note vorliegt
+    {
+      newNote[i].newVal = false;                  // neue Note quittieren
+      notePtr->typeIdx = newNote[i].typeIdx;      // und Inhalte im
+      notePtr->value = newNote[i].value;          // Akkordspeicher
+      notePtr->veloc = newNote[i].veloc;          // überschreiben
+    }
+
+    noteSeq[j++] = notePtr->value;        // Notenwert in Sequenz eintragen   **
+
+    // Daten für die Note aus der Typenliste holen
+    //
+    tIdx = notePtr->typeIdx;
+    typePtr = &typeList[tIdx];
+    notePtr->cntAttack  = typePtr->attack;    // Aufklingzeit in Zähler
+    notePtr->cntDecay   = typePtr->decay;     // Abklingzeit in Zähler
+    notePtr->cntSustain = typePtr->sustain;   // Klingzeit in Zähler
+    notePtr->cntRelease = typePtr->release;   // Ausklingzeit in Zähler
+    notePtr->cntPause   = typePtr->pause;     // Pausenzeit in Zähler
+
+    if(notePtr->cntAttack != 0)   // Wenn ein Attack-Wert gegeben ist
+    {
+      doAttack = true;            // dann attack markieren
+      attack =                    // und den Wert auf den erste Schritt setzen
+          (typePtr->deltaAttack * notePtr->veloc) / 100;
+      if(attack > 127) attack = 127;
+      noteSeq[j++] = attack;              // Lautstärke in Sequenz eintragen  **
+    }
+    else  // ohne Attack-Wert geht es hier gleich in Sustain weiter
+    {
+      sustain = (typePtr->percentSustain * notePtr->veloc) / 100;
+      if(sustain > 127) sustain = 127;
+      noteSeq[j++] = sustain;             // Lautstärke in Sequenz eintragen  **
+    }
+  }
+
+  crb->putSeq(noteSeq, j);                // Sequenz an Puffer übergeben   *****
+
+  if(doAttack)
+    next(smAttack);
+  else
+    next(smSustain);
+}
+
+void MidiNotes::smAttack()
+{
+
+}
+
+void MidiNotes::smDecay()
+{
+
+}
+
+// TODO
+// Es können noch nicht Noten unterschiedlicher Länge in einem Akkord
+// verarbeitet werden. Bei mehreren eingetragenen Noten würde die
+// kürzeste Note den Ablauf bestimmen.
+
+void MidiNotes::smSustain()
+{
+  int   i;
+  bool  sustFin;
+
+  sustFin = false;
+  for(i = 0; i < MaxNrNoteSim; i++)
+  {
+    notePtr = &chord[i];
+    if(notePtr->mode == NoteModeEmpty)
+      break;
+
+    if(notePtr->cntSustain > 0)     // Die Sustain-Zeit in diesem Zustand verweilen
+      notePtr->cntSustain--;
+    else
+      sustFin = true;
+  }
+
+  if(sustFin)
+    next(smNoteOff);
+}
+
+void MidiNotes::smRelease()
+{
+
+}
+
+void MidiNotes::smNoteOff()
+{
+  int   i,j;
+
+  j = 0;
+  for(i = 0; i < MaxNrNoteSim; i++)   // Alle Noten im Akkord bearbeiten
+  {
+    notePtr = &chord[i];
+    if(notePtr->mode == NoteModeEmpty)
+      break;
+
+    if(i == 0)
+    {
+      noteSeq[j++] = 0x80 | chn;      // Erste Note bestimmt den Befehl AUS    **
+      absPause = notePtr->cntPause;
+    }
+
+    noteSeq[j++] = notePtr->value;    //Erste und weitere Noten liefern Liste  **
+    noteSeq[j++] = 0;
+  }
+
+  crb->putSeq(noteSeq, j);            // Sequenz an Puffer übergeben   *****
+
+  next(smPause);
+}
+
+void MidiNotes::smPause()
+{
+  if(absPause > 0)
+  {
+    absPause--;
+    return;
+  }
+
+  next(smNoteOn);
+}
+
+// ----------------------------------------------------------------------------
+// Debugging
+// ----------------------------------------------------------------------------
+//
+
+
+
+
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/MidiNotes/MidiNotes.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/MidiNotes/MidiNotes.h
new file mode 100644
index 0000000000000000000000000000000000000000..0f09fccd7d1a19c3c9171b0cf96c8320f5ad0b44
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/MidiNotes/MidiNotes.h
@@ -0,0 +1,226 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   MidiNotes.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   27. November 2021
+//
+// Der Inhalt dieser Datei sind Festlegungen für steuerbare Midi-Controller
+//
+
+#ifndef MidiNotes_h
+#define MidiNotes_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+#include "ComRingBuf.h"
+
+#define MaxNrNoteSim    4
+#define MaxMidiSeq      (2 * MaxNrNoteSim + 1)
+
+// Definierte Noten
+//
+#define SchlossC    60
+#define Kammerton   69
+
+typedef enum  _NoteDiv
+{
+  nd4   = 1,
+  nd8   = 2,
+  nd16  = 4,
+  nd32  = 8,
+  nd64  = 16
+} NoteDiv;
+
+typedef enum  _MidiOpMode
+{
+  momIdle,
+  momSequence,
+  momRunDelta
+} MidiOpMode;
+
+
+// ----------------------------------------------------------------------------
+//                            M i d i N o t e s
+// ----------------------------------------------------------------------------
+//
+class MidiNotes
+{
+#define next(x) nextState = &MidiNotes::x
+
+public:
+  // -------------------------------------------------------------------------
+  // Öffentliche Datentypen
+  // -------------------------------------------------------------------------
+  //
+  typedef enum _NoteTypeIdx
+  {
+    nti0  = 0,
+    nti1,
+    nti2p,
+    nti2,
+    nti4p,
+    nti4,
+    nti8p,
+    nti8,
+    nti16p,
+    nti16,
+    nti32p,
+    nti32,
+    nti64p,
+    nti64,
+    ntiNr
+  } NoteTypeIdx;
+
+
+private:
+  // -------------------------------------------------------------------------
+  // Private Datentypen
+  // -------------------------------------------------------------------------
+  //
+  typedef void (MidiNotes::*cbVector)(void);
+
+  typedef struct _NoteType
+  {
+    dword   length;
+    dword   attack;
+    dword   decay;
+    dword   sustain;
+    dword   release;
+    dword   pause;
+    byte    deltaAttack;
+    byte    deltaDecay;
+    byte    percentSustain;
+    byte    deltaRelease;
+  } NoteType, *NoteTypePtr;
+
+  typedef struct  _Note
+  {
+    byte      mode;
+    byte      typeIdx;
+    byte      value;
+    byte      veloc;
+    int       state;
+    dword     cntAttack;
+    dword     cntDecay;
+    dword     cntSustain;
+    dword     cntRelease;
+    dword     cntPause;
+  } Note, *NotePtr;
+
+  typedef struct _NewNote
+  {
+    bool      newVal;
+    byte      typeIdx;
+    byte      value;
+    byte      veloc;
+  }NewNote;
+
+#define NoteModeEmpty     0x00
+#define NoteModeRun       0x01
+#define NoteModeDoChange  0x02
+
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  IntrfBuf    *crb;
+  cbVector    nextState;
+
+  MidiOpMode  opMode;
+
+  dword     runCounter;
+  dword     cycleCnt;
+
+  dword     midiCycle;      // Zustandstakt in Mikrosekunden
+  dword     minNoteTick;    // minimale Notendauer in Millisekunden
+  dword     bpm;            // Beats per Minute (Metronom)
+  dword     stdNoteTick;    // Dauer einer Viertelnote in Millisekunden
+  dword     stdNoteCount;   // Viertelnote in Zyklen der Zustandsmaschine
+
+  Note      chord[MaxNrNoteSim];  // Liste der simultanen Noten (Akkord)
+  NoteType  typeList[ntiNr];      // Liste der Notentypen
+  byte      chn;                  // Aktueller Kanal
+  byte      noteSeq[MaxMidiSeq];  // Lokaler Telegrammaufbau
+
+  NotePtr     notePtr;      // Temporäre Notendaten
+  NoteTypePtr typePtr;      // Temporärer Notentyp
+
+  dword     absPause;       // Pause für den zyklischen Ablauf
+  NewNote   newNote[MaxNrNoteSim];  // Übergabe neuer Noten
+
+  bool      stopRun;           // Anhalten der Midi-Schleife
+  bool      stoppedRun;        // Midi-Schleife angehalten
+
+
+  // --------------------------------------------------------------------------
+  // Lokale Funktionen
+  // --------------------------------------------------------------------------
+  //
+
+  // Zustandsmaschine
+  // -----------------------------
+  void smInit();
+  void smIdle();
+
+  void smNoteOn();
+  void smAttack();
+  void smDecay();
+  void smSustain();
+  void smRelease();
+  void smNoteOff();
+  void smPause();
+
+
+  // --------------------------------------------------------------------------
+  // Inline-Funktionen
+  // --------------------------------------------------------------------------
+  //
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+  void begin(int inBpm, NoteDiv inRes, int inMidiCycle, IntrfBuf *inCRB);
+
+
+  // --------------------------------------------------------------------------
+  // Konfiguration
+  // --------------------------------------------------------------------------
+  //
+  void  setNoteType(NoteTypeIdx nt);
+
+  void  setNoteType(NoteTypeIdx nt, byte pAttL, byte pDecL, byte pSusL, byte pRelL,
+                    byte dAtt, byte dDec, byte pSusV, byte dRel, byte pPauL);
+
+  int   addChordNote(NoteTypeIdx nti, byte val, byte vel);
+
+  void  setChannel(int chnVal);
+
+  // --------------------------------------------------------------------------
+  // Betrieb
+  // --------------------------------------------------------------------------
+  //
+  void setOpMode(MidiOpMode mom);
+  void setChordNote(int idx, NoteTypeIdx nti, int val, int vel);
+
+  // --------------------------------------------------------------------------
+  // Steuerung, Zustandsmaschine
+  // --------------------------------------------------------------------------
+  //
+  void run();
+  void stop();
+  void resume();
+
+  // --------------------------------------------------------------------------
+  // Debugging
+  // --------------------------------------------------------------------------
+  //
+
+};
+
+
+// ----------------------------------------------------------------------------
+#endif // MidiNotes_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/MidiNotes/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/MidiNotes/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..a95d68926746af5b6e20d30d2a29ea5b513110ad
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/MidiNotes/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "MidiNotes",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/Monitor/Monitor.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/Monitor/Monitor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c30d24b20011e8d22623c261a295ccfb42fe1ea
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/Monitor/Monitor.cpp
@@ -0,0 +1,1165 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   Monitor.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   15. Mai 2021
+//
+// Der Monitor dient zum direkten Zugriff auf die Ressourcen eines
+// Mikrocontrollers über die serielle Schnittstelle.
+// ACHTUNG!
+// Er ist nicht für die Anwendung des "Serial Monitor" aus der Arduino-IDE
+// bzw. aus Eclipse/Sloeber gedacht, sondern für ein typisches "Terminal".
+// Verwendet wurde bei der Entwicklung unter Linux das GtkTerm.
+//
+
+#include "Monitor.h"
+
+//-----------------------------------------------------------------------------
+// Initialisierungen
+//-----------------------------------------------------------------------------
+
+void Monitor::init(int inMode, int inCpu, LoopCheck *inLcPtr, IntrfTw *inTwPtr)
+{
+  mode          = inMode;
+  cpu           = inCpu;
+  wrIdx         = 0;
+  rdIdx         = 0;
+  blkOut        = false;
+  blkIn         = false;
+  inIdx         = 0;
+  info          = NULL;
+  readOffsAddr  = 0;
+  doReadReg     = false;
+  extraIn       = false;
+  lcPtr         = inLcPtr;
+  twiPtr        = inTwPtr;
+  nrOfChnChar   = '@';
+
+#ifdef smnNANOBLE33
+
+  microTicValPtr  = (dword *) 0x40009548;
+  microTicCapPtr  = (dword *) 0x40009048;
+
+#endif
+
+  nextState =
+      &Monitor::waitEnter;
+}
+
+
+Monitor::Monitor(int inMode, int inCpu)
+{
+  init(inMode, inCpu, NULL, NULL);
+}
+
+Monitor::Monitor(int inMode, int inCpu, LoopCheck *inLcPtr)
+{
+  init(inMode, inCpu, inLcPtr, NULL);
+}
+
+Monitor::Monitor(int inMode, int inCpu, LoopCheck *inLcPtr, IntrfTw *inTwiPtr)
+{
+  init(inMode, inCpu, inLcPtr, inTwiPtr);
+}
+
+//-----------------------------------------------------------------------------
+// Konfiguration, Hilfsfunktionen
+//-----------------------------------------------------------------------------
+//
+int Monitor::putBuf(char c)
+{
+  if(blkIn) return(-1);
+
+  int free = rdIdx - wrIdx - 1;
+  if(free < 0) free += BufSize;
+  if(free < 1) return(0);
+  buffer[wrIdx++] = c;
+  if(wrIdx == BufSize)
+    wrIdx = 0;
+  return(1);
+}
+
+int Monitor::putBuf(char *txt)
+{
+  if(blkIn) return(-1);
+
+  int free = rdIdx - wrIdx - 1;
+  int size = strlen(txt);
+  if(free < 0) free += BufSize;
+  if(free < size) return(0);
+  for(int i = 0; i < size; i++)
+  {
+  buffer[wrIdx++] = txt[i];
+  if(wrIdx == BufSize)
+    wrIdx = 0;
+  }
+  return(size);
+}
+
+char Monitor::getBuf()
+{
+  int num = wrIdx - rdIdx;
+  if(num == 0) return('\0');
+  char c = buffer[rdIdx++];
+  if(rdIdx == BufSize)
+    rdIdx = 0;
+  return(c);
+}
+
+void Monitor::clrBuf()
+{
+  wrIdx = 0;
+  rdIdx = 0;
+}
+
+void Monitor::sendConfig()
+{
+  int           nrChn   = nrOfChnChar & 0x3F;
+  int           bufIdx  = 0;
+  CfgMeasChnPtr cfgPtr;
+
+  // Visualisierungskanäle (Anzahl) anfordern
+  outChar[bufIdx++] = '&';
+  outChar[bufIdx++] = '@';    // Kanalnummer
+  outChar[bufIdx++] = '@';    // Typ
+  outChar[bufIdx++] = nrOfChnChar;
+  outChar[bufIdx++] = '$';
+
+  for(int i = 0; i < nrChn; i++)
+  {
+    cfgPtr = &cfgChnArr[i];
+    outChar[bufIdx++] = '&';
+    outChar[bufIdx++] = (i+1) | 0x40;
+    outChar[bufIdx++] = cfgPtr->type;
+    hexWord(&outChar[bufIdx], cfgPtr->maxVal);
+    bufIdx += 4;
+    hexWord(&outChar[bufIdx], cfgPtr->minVal);
+    bufIdx += 4;
+    if(cfgPtr->name != NULL)
+    {
+      bufIdx += cpyStr(&outChar[bufIdx], cfgPtr->name);
+    }
+    outChar[bufIdx++] = '$';
+  }
+  outChar[bufIdx] = '\0';
+  out(outChar);
+}
+
+//-----------------------------------------------------------------------------
+// Lokale Abläufe
+//-----------------------------------------------------------------------------
+//
+
+volatile dword calcTest1, calcTest2, calcTest3;
+
+void Monitor::waitEnter()
+{
+  char  c;
+
+  busy = false;
+
+  if(!keyHit()) return;
+  c = keyIn();
+  if(c != '\r' && c != '\n')
+  {
+    lastKeyIn = c;
+    return;
+  }
+
+  busy = true;
+
+  blkIn   = true;
+  blkOut  = true;
+  GoPrm
+}
+
+void doSomeCode()
+{
+  for(int i = 0; i < 500; i++)
+  {
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+    calcTest1++;
+  }
+}
+
+volatile dword micTime;
+
+void Monitor::getKey()
+{
+  char  cin,c1,c0;
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  if(mode & modeEcho)
+    out(cin);
+
+  c0 = c1 = '\0';
+
+  if(inIdx == 0)
+    c0 = cin;
+  else if(inIdx == 1)
+  {
+    c0 = inChar[0];
+    c1 = cin;
+  }
+  else if(inIdx == 2)
+  {
+    c0 = inChar[0];
+    c1 = inChar[1];
+  }
+
+  switch(c0)
+  {
+    case '\r':
+      out("\r\n");
+      blkIn   = false;
+      blkOut  = false;
+      GoWt
+      break;
+
+    case 'c':
+    case 'C':
+      if(inIdx == 0)
+      {
+        inChar[inIdx] = cin;
+        inIdx++;
+      }
+      else if(inIdx == 1)
+      {
+
+        if(cin >= '0' && cin <= '9')
+        {
+          inIdx = 0;
+          out('=');
+          int cIdx = cin - 0x30;
+          if(cFlag[cIdx])
+          {
+            cFlag[cIdx] = false;
+            out('0');
+          }
+          else
+          {
+            cFlag[cIdx] = true;
+            out('1');
+          }
+          GoPrm
+        }
+
+        else if(cin == 'f' || cin == 'F')
+        {
+          inChar[inIdx] = cin;
+          inIdx++;
+        }
+      }
+
+      else if(inIdx == 2)
+      {
+        inIdx = 0;
+        if(cin == 'g' || cin == 'G')
+        {
+          sendConfig();
+          GoPrm
+        }
+      }
+      else
+        GoPrm
+      break;
+
+    case 'i':
+    case 'I':
+      if(inIdx == 0)
+      {
+        inChar[inIdx] = cin;
+        inIdx++;
+      }
+      else if(inIdx == 1)
+      {
+        inIdx = 0;
+        out(' ');
+        if(cin == 'a' || cin == 'A')
+          nextState = &Monitor::getTwiAdr;
+        else if(cin == 'l' || cin == 'L')
+          nextState = &Monitor::readTwiList;
+        else if(cin == 'r' || cin == 'R')
+          nextState = &Monitor::readTwiByte;
+        else if(cin == 'w' || cin == 'W')
+          nextState = &Monitor::writeTwiByte;
+      }
+      break;
+
+    case 'r':
+    case 'R':
+      if(inIdx == 0)
+      {
+        inChar[inIdx] = cin;
+        inIdx++;
+      }
+      else if(inIdx == 1)
+      {
+        inIdx = 0;
+        out(' ');
+        if(cin == 'o' || cin == 'O')
+          nextState = &Monitor::getRdOffsAdr;
+        else if(cin == 'r' || cin == 'R')
+          nextState = &Monitor::readRegVal;
+      }
+      break;
+
+    // ------------------------------------------------------------------------
+    case 't':     //                 Zeitmessungen
+    case 'T':     //
+    // ------------------------------------------------------------------------
+      if(inIdx == 0)
+      {
+        inChar[inIdx] = cin;
+        inIdx++;
+      }
+      else if(inIdx == 1)
+      {
+        inIdx = 0;
+        nextState = &Monitor::getTiming;
+        if(cin == 'l' || cin == 'L')
+        {
+          cmdMode1 = 'L';
+        }
+        else if(cin == 'b' || cin == 'B')
+        {
+          cmdMode1 = 'B';
+        }
+        else if(cin == 'c' || cin == 'C')
+        {
+          cmdMode1 = 'C';
+        }
+#ifdef smnNANOBLE33
+        else if(cin == 'p' || cin == 'P')
+        {
+          micTime = micsecs();
+          doSomeCode();
+          micTime = (micsecs() - micTime - 11) / 10;
+          out(' ');
+          out(micTime);
+          GoPrm
+        }
+#endif
+        else if(cin == 'r' || cin == 'R')
+        {
+          if(lcPtr != NULL)
+          {
+            lcPtr->resetStatistics();
+            out(' ');
+          }
+          GoPrm
+        }
+        else if(cin == 't' || cin == 'T')
+        {
+          dword micTime = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          calcTest2 = micros();
+          micTime = (micros() - micTime) / 20;
+          out(' ');
+          out(micTime);
+          GoPrm
+        }
+        else
+        {
+          GoPrm
+        }
+      }
+      break;
+
+    case 'V':
+    case 'v':
+      out(' ');
+      nextState = &Monitor::version;
+      break;
+
+  }
+}
+
+void Monitor::prompt()
+{
+  if(mode & modeNl)
+    out('\n');
+
+  out("\rM>");
+  GoInp
+}
+
+void Monitor::version()
+{
+  out("Monitor: Version 0.1, May 16, 2021");
+  GoPrm
+}
+
+void Monitor::getRdOffsAdr()
+{
+  char  cin;
+  dword val;
+  int   valIdx;
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  readOffsAddr = 0;
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx < 16)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    valIdx = 0;
+    inIdx--;
+    while(inIdx >= 0)
+    {
+      val = inChar[inIdx];
+      readOffsAddr |= val << valIdx * 4;
+      inIdx--;
+      valIdx++;
+    }
+
+    // TEST
+    //out(" = ");
+    //out(readOffsAddr);
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::readRegVal()
+{
+  char  cin;
+  dword val,adr;
+  int   valIdx;
+
+  dword *regPtr;
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  adr = 0;
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx < 16)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    valIdx = 0;
+    inIdx--;
+    while(inIdx >= 0)
+    {
+      val = inChar[inIdx];
+      adr |= val << valIdx * 4;
+      inIdx--;
+      valIdx++;
+    }
+
+    regPtr = (dword *) (readOffsAddr + adr);
+    val = *regPtr;
+
+    out(": ");
+    hexDword(outChar, val);
+    out(outChar);
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::getTiming()
+{
+  LoopStatistics  lStat;
+  unsigned int    maxVal;
+  unsigned int    minVal;
+  unsigned int    avgVal;
+  char  cin;
+
+  if(lcPtr == NULL)
+  {
+    outl("Kein LoopCheck.");
+    GoPrm
+    return;
+  }
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  if(mode & modeEcho)
+    out(cin);
+
+  if(cin == 'r' || cin == 'R')
+  {
+    out(' ');
+    lcPtr->getStatistics(&lStat);
+    if(cmdMode1 == 'L')
+    {
+      maxVal = lStat.loopMaxTime;
+      minVal = lStat.loopMinTime;
+      avgVal = lStat.loopAvgTime;
+    }
+    else if(cmdMode1 == 'B')
+    {
+      maxVal = lStat.bgMaxTime;
+      minVal = lStat.bgMinTime;
+      avgVal = lStat.bgAvgTime;
+    }
+    else if(cmdMode1 == 'C')
+    {
+      maxVal = lStat.maxPeriod;
+      minVal = lStat.minPeriod;
+      avgVal = lStat.avgPeriod;
+    }
+    else
+    {
+      maxVal = 0;
+      minVal = 0;
+      avgVal = 0;
+    }
+
+    out(maxVal); out("/"); out(minVal); out("/"); out(avgVal); out("\r");
+    GoPrm
+  }
+  else if(cin == 'm' || cin == 'M')
+  {
+    lcPtr->resetStatistics();
+    lcPtr->startTimeMeasure();
+    nextState = &Monitor::getLoopMeasure;
+  }
+
+}
+
+void Monitor::getLoopMeasure()
+{
+  LoopStatistics  lStat;
+  unsigned int    maxVal;
+  unsigned int    minVal;
+  unsigned int    avgVal;
+
+  if(lcPtr->getTimeMeasure() < 1000000)
+    return;
+
+  out(' ');
+  lcPtr->getStatistics(&lStat);
+  if(cmdMode1 == 'L')
+  {
+    maxVal = lStat.loopMaxTime;
+    minVal = lStat.loopMinTime;
+    avgVal = lStat.loopAvgTime;
+  }
+  else if(cmdMode1 == 'B')
+  {
+    maxVal = lStat.bgMaxTime;
+    minVal = lStat.bgMinTime;
+    avgVal = lStat.bgAvgTime;
+  }
+  else if(cmdMode1 == 'C')
+  {
+    maxVal = lStat.maxPeriod;
+    minVal = lStat.minPeriod;
+    avgVal = lStat.avgPeriod;
+  }
+  else
+  {
+    maxVal = 0;
+    minVal = 0;
+    avgVal = 0;
+  }
+
+  out(maxVal); out("/"); out(minVal); out("/"); out(avgVal); out("\r");
+  GoPrm
+}
+
+
+void Monitor::getTwiAdr()
+{
+  char  cin;
+
+  if(!keyHit()) return;
+  cin = keyIn();
+  twiAdr = 0;
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx < 2)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    twiAdr = (inChar[0] << 4) | inChar[1];
+
+    out(" = ");
+    out(twiAdr);
+
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::readTwiList()
+{
+  char  cin;
+  int   reg;
+  int   anz;
+
+  char  tmpOut[3];
+
+  TwiStatus twiStatus;
+
+  if(twiPtr == NULL)
+  {
+    out("no Twi");
+    inIdx = 0;
+    GoPrm
+  }
+
+  if(!keyHit()) return;
+  cin = keyIn();
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx == 1)
+      out(" ");
+
+    if(inIdx < 4)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    reg = (inChar[0] << 4) | inChar[1];
+    anz = (inChar[2] << 4) | inChar[3];
+
+    twiByteSeq.len = anz;
+    twiByteSeq.valueRef = byteArray;
+
+    twiStatus = twiPtr->readByteRegSeq(twiAdr, reg, &twiByteSeq);
+
+    out(" [");
+    out((int) twiStatus);
+    out("] ");
+
+    if((int) twiStatus == 128)
+    {
+      for(int i = 0; i < anz; i++)
+      {
+        hexByte(tmpOut, byteArray[i]);
+        out(tmpOut);
+        if(i != (anz-1)) out(':');
+      }
+    }
+
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::readTwiByte()
+{
+  char  cin;
+  int   reg;
+  byte  val;
+
+  if(twiPtr == NULL)
+  {
+    out("no Twi");
+    inIdx = 0;
+    GoPrm
+  }
+
+  if(!keyHit()) return;
+  cin = keyIn();
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx < 2)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    reg = (inChar[0] << 4) | inChar[1];
+
+    val = twiPtr->readByteReg(twiAdr, reg);
+
+    out(" = ");
+    binByte(outChar, val);
+    out(outChar);
+
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+void Monitor::writeTwiByte()
+{
+  char  cin;
+  int   reg;
+  int   val;
+
+  TwiStatus twiStatus;
+
+  if(twiPtr == NULL)
+  {
+    out("no Twi");
+    inIdx = 0;
+    GoPrm
+  }
+
+  if(!keyHit()) return;
+  cin = keyIn();
+
+  if(cin != '\r')
+  {
+    if(cin >= '0' && cin <= '9')
+      inChar[inIdx] = cin - 0x30;
+    else if(cin >= 'A' && cin <= 'F')
+      inChar[inIdx] = cin - 0x37;
+    else if(cin >= 'a' && cin <= 'f')
+      inChar[inIdx] = cin - 0x57;
+    else
+      return;
+
+    out(cin);
+    if(inIdx == 1)
+      out(" ");
+
+    if(inIdx < 4)
+      inIdx++;
+    else
+      out((char) 0x08);
+  }
+  else
+  {
+    reg = (inChar[0] << 4) | inChar[1];
+    val = (inChar[2] << 4) | inChar[3];
+
+    twiStatus = twiPtr->writeByteReg(twiAdr, reg, val);
+
+    out(" : ");
+    out((int) twiStatus);
+
+    inIdx = 0;
+    GoPrm
+  }
+}
+
+//-----------------------------------------------------------------------------
+// Lokale Schnittstelle
+//-----------------------------------------------------------------------------
+//
+void Monitor::print(char c, int eol)
+{
+  putBuf(c);
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+void Monitor::print(char *txt, int eol)
+{
+  if(txt != NULL)
+    putBuf(txt);
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+void Monitor::print(byte *hex, int nr, char fill, int eol)
+{
+  if(hex == NULL) return;
+
+  for(int i = 0; i < nr; i++)
+  {
+    hexByte(tmpChar,hex[i]);
+    tmpChar[2] = fill;
+    tmpChar[3] = '\0';
+    putBuf(tmpChar);
+  }
+
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+void Monitor::print(unsigned int iVal, int eol)
+{
+  char  iBuf[16];
+
+  itoa(iVal, iBuf, 10);
+  putBuf(iBuf);
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+void Monitor::prints(int iVal, int eol)
+{
+  char  iBuf[16];
+
+  itoa(iVal, iBuf, 10);
+  putBuf(iBuf);
+  if(eol & eolCR)
+    putBuf('\r');
+  if(eol & eolLF)
+    putBuf('\n');
+}
+
+//-----------------------------------------------------------------------------
+// Datenaufbereitung
+//-----------------------------------------------------------------------------
+//
+void Monitor::hexByte(char * dest, byte val)
+{
+  char cv;
+
+  cv = val >> 4;
+  if(cv < 10)
+    cv += 0x30;
+  else
+    cv += 0x37;
+  dest[0] = cv;
+
+  cv = val & 0x0F;
+  if(cv < 10)
+    cv += 0x30;
+  else
+    cv += 0x37;
+  dest[1] = cv;
+
+  dest[2] = '\0';
+}
+
+void Monitor::binByte(char * dest, byte val)
+{
+  byte mask;
+
+  mask = 0x80;
+
+  for(int i = 0; i < 8; i++)
+  {
+    if((val & mask) != 0)
+      dest[i] = '1';
+    else
+      dest[i] = '0';
+    mask >>= 1;
+  }
+
+  dest[8] = '\0';
+}
+
+int   Monitor::cpyStr(char *dest, char *src)
+{
+  int   i = 0;
+
+  while((dest[i] = src[i]) != '\0') i++;
+  return(i);
+}
+
+void Monitor::binDword(char *dest, dword dwVal)
+{
+  int   idx = 0;
+  byte  bVal;
+
+  bVal = dwVal >> 24;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+  dest[idx++] = ' ';
+
+  bVal = dwVal >> 16;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+  dest[idx++] = ' ';
+
+  bVal = dwVal >> 8;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+  dest[idx++] = ' ';
+
+  bVal = dwVal;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+
+  dest[idx] = '\0';
+}
+
+void Monitor::hexDword(char *dest, dword dwVal)
+{
+  int   idx = 0;
+  byte  bVal;
+
+  bVal = dwVal >> 24;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  bVal = dwVal >> 16;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  bVal = dwVal >> 8;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  bVal = dwVal;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  dest[idx] = '\0';
+}
+
+void Monitor::binWord(char *dest, word wVal)
+{
+  int   idx = 0;
+  byte  bVal;
+
+  bVal = wVal >> 8;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+  dest[idx++] = ' ';
+
+  bVal = wVal;
+  binByte(&dest[idx], bVal);
+  idx += 8;
+
+  dest[idx] = '\0';
+}
+
+void Monitor::hexWord(char *dest, word wVal)
+{
+  int   idx = 0;
+  byte  bVal;
+
+  bVal = wVal >> 8;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  bVal = wVal;
+  hexByte(&dest[idx], bVal);
+  idx += 2;
+
+  dest[idx] = '\0';
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Anwenderschnittstelle
+//-----------------------------------------------------------------------------
+//
+
+void Monitor::run()
+{
+  char c;
+
+  if(!blkOut)
+  {
+    c = getBuf();
+    if(c != '\0')
+      smnSerial.print(c);
+  }
+  (this->*nextState)();
+}
+
+void Monitor::cprint(char c)
+{
+  print(c, 0);
+}
+
+void Monitor::cprintln(char c)
+{
+  print(c, eolCR | eolLF);
+}
+
+void Monitor::cprintcr(char c)
+{
+  print(c, eolCR);
+}
+
+void Monitor::print(char *txt)
+{
+  print(txt, 0);
+}
+
+void Monitor::println(char *txt)
+{
+  print(txt, eolCR | eolLF);
+}
+
+void Monitor::println()
+{
+  print((char *) NULL, eolCR | eolLF);
+}
+
+void Monitor::printcr(char *txt)
+{
+  print(txt, eolCR);
+}
+
+void Monitor::printcr()
+{
+  print((char *) NULL, eolCR);
+}
+
+void Monitor::print(unsigned int iVal)
+{
+  print(iVal, 0);
+}
+
+void Monitor::prints(int iVal)
+{
+  prints(iVal, 0);
+}
+
+void Monitor::println(unsigned int iVal)
+{
+  print(iVal, eolCR | eolLF);
+}
+
+void Monitor::printcr(unsigned int iVal)
+{
+  print(iVal, eolCR);
+}
+
+void Monitor::print(byte *iVal, int nr, char fill)
+{
+  print(iVal, nr, fill, 0);
+}
+
+void Monitor::printcr(byte *iVal, int nr, char fill)
+{
+  print(iVal, nr, fill, eolCR);
+}
+
+void Monitor::println(byte *iVal, int nr, char fill)
+{
+  print(iVal, nr, fill, eolCR | eolLF);
+}
+
+void Monitor::setInfo(char *txt)
+{
+  info = txt;
+}
+
+void Monitor::config(int inNrOfChn)
+{
+  if(inNrOfChn < 0) return;
+
+  if(inNrOfChn > MaxChn)
+    inNrOfChn = MaxChn;
+
+  nrOfChnChar = inNrOfChn | 0x40;
+}
+
+void Monitor::config(int inChn, char inType, word inMax, word inMin, char *inName)
+{
+  if(inChn < 1) return;
+
+  if(inChn > MaxChn)
+    inChn = MaxChn;
+
+  CfgMeasChnPtr chnPtr = &cfgChnArr[inChn-1];
+  chnPtr->maxVal = inMax;
+  chnPtr->minVal = inMin;
+  chnPtr->name = inName;
+  chnPtr->type = inType;
+}
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/Monitor/Monitor.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/Monitor/Monitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ee2bb11830c716703e5489655355c93a039d131
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/Monitor/Monitor.h
@@ -0,0 +1,211 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   Monitor.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   15. Mai 2021
+//
+// Der Monitor dient zum direkten Zugriff auf die Ressourcen eines
+// Mikrocontrollers über die serielle Schnittstelle.
+//
+
+#include  "Arduino.h"
+#include  "environment.h"
+#include  "arduinoDefs.h"
+#include  "LoopCheck.h"
+#include  "IntrfTw.h"
+
+#ifndef Monitor_h
+#define Monitor_h
+// ----------------------------------------------------------------------------
+
+#define keyHit()  smnSerial.available()
+#define keyIn()   smnSerial.read()
+#define out(x)    smnSerial.print(x)
+#define outl(x)   smnSerial.println(x)
+#define GoInp     nextState = &Monitor::getKey;
+#define GoPrm     nextState = &Monitor::prompt;
+#define GoWt      nextState = &Monitor::waitEnter;
+
+#define modeEcho  0x01
+#define modeNl    0x02
+
+#define eolCR     0x01
+#define eolLF     0x02
+#define eolNL     0x03
+
+#define BufSize   512
+#define MaxChn    32
+
+class Monitor
+{
+  // -------------------------------------------------------------------------
+  // class specific data types
+  // -------------------------------------------------------------------------
+  //
+  typedef void (Monitor::*StatePtr)(void);
+  typedef struct _ConfMeasChannel
+  {
+    word    maxVal;
+    word    minVal;
+    char    *name;
+    char    type;
+  } CfgMeasChn, *CfgMeasChnPtr;
+
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  int       cpu;
+  int       mode;
+
+#ifdef smnNANOBLE33
+  dword     *microTicValPtr;
+  dword     *microTicCapPtr;
+#endif
+
+  char      buffer[BufSize];
+  int       wrIdx;
+  int       rdIdx;
+  bool      blkOut;
+  bool      blkIn;
+
+  char      inChar[16];
+  char      outChar[128];
+  char      tmpChar[8];
+  int       inIdx;
+  bool      extraIn;
+
+  char      cmdMode1;
+  char      cmdMode2;
+
+  char      *info;
+
+  StatePtr  nextState;
+  LoopCheck *lcPtr;
+
+  IntrfTw     *twiPtr;
+  int         twiAdr;
+  TwiByteSeq  twiByteSeq;
+  byte        byteArray[32];
+
+  dword       readOffsAddr;
+  bool        doReadReg;
+
+  CfgMeasChn  cfgChnArr[MaxChn];
+  char        nrOfChnChar;
+
+  // --------------------------------------------------------------------------
+  // Lokale Funktionen
+  // --------------------------------------------------------------------------
+  //
+  void  init(int mode, int cpu);
+  void  init(int mode, int cpu, LoopCheck *inLcPtr);
+  void  init(int mode, int cpu, LoopCheck *inLcPtr, IntrfTw *inTwPtr);
+
+  void  waitEnter();
+  void  prompt();
+  void  getKey();
+  void  version();
+  void  getRdOffsAdr();
+  void  readRegVal();
+  void  getTiming();
+  void  getLoopMeasure();
+
+  void  getTwiAdr();
+  void  readTwiList();
+  void  readTwiByte();
+  void  writeTwiByte();
+
+  void  print(char c, int eol);
+  void  print(char *txt, int eol);
+  void  print(byte *hex, int nr, char fill, int eol);
+  void  print(unsigned int iVal, int eol);
+  void  prints(int iVal, int eol);
+
+#ifdef smnNANOBLE33
+
+  dword micsecs()
+  {
+    *microTicCapPtr = 1;
+    return(*microTicValPtr);
+  }
+
+#endif
+
+  // --------------------------------------------------------------------------
+  // Datenaufbereitung
+  // --------------------------------------------------------------------------
+  //
+  void hexByte(char *dest, byte val);
+  void binByte(char *dest, byte val);
+  void hexWord(char *dest, word val);
+  void binWord(char *dest, word val);
+  void hexDword(char *dest, dword val);
+  void binDword(char *dest, dword val);
+  int  cpyStr(char *dest, char *src);
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen
+  // --------------------------------------------------------------------------
+
+  Monitor(int mode, int cpu);
+  Monitor(int mode, int cpu, LoopCheck *inLcPtr);
+  Monitor(int mode, int cpu, LoopCheck *inLcPtr, IntrfTw *inTwiPtr);
+
+  // --------------------------------------------------------------------------
+  // Konfiguration und Hilfsfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void  setInfo(char *txt);
+  int   putBuf(char c);
+  int   putBuf(char *txt);
+  char  getBuf();
+  void  clrBuf();
+  void  sendConfig();
+
+
+  // --------------------------------------------------------------------------
+  // Anwenderschnittstelle
+  // --------------------------------------------------------------------------
+  //
+
+  // Funktionen
+  //
+  void run();
+  void cprint(char c);
+  void print(char *txt);
+  void print(unsigned int iVal);
+  void prints(int iVal);
+  void print(byte *iVal, int nr, char fill);
+  void printcr();
+  void cprintcr(char c);
+  void printcr(char *txt);
+  void printcr(unsigned int iVal);
+  void printcr(byte *iVal, int nr, char fill);
+  void println();
+  void cprintln(char c);
+  void println(char *txt);
+  void println(unsigned int iVal);
+  void println(byte *iVal, int nr, char fill);
+
+  void config(int inNrOfChn);
+  void config(int inChn, char inType, word inMax, word inMin, char *inName);
+
+
+  // Zustände (Variablen)
+  //
+  bool  busy;
+  char  lastKeyIn;
+
+  // Steuerbits (Kommandobits)
+  //
+  bool  cFlag[10];
+  };
+
+// ----------------------------------------------------------------------------
+#endif // Monitor_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/Monitor/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/Monitor/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..a9b281138760d16aa71d51ecec1518e22188a30f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/Monitor/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "Monitor",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5a57198a5bb3b3c340ffa5a725f7f7c009725d9a
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.cpp
@@ -0,0 +1,875 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   SensorLSM9DS1.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#include "SensorLSM9DS1.h"
+#include <string.h>
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+
+SensorLSM9DS1::SensorLSM9DS1(IntrfTw *refI2C, int inRunCycle)
+{
+  TwiParams twiParams;
+
+  twPtr               = refI2C;
+  runState            = rsInit;
+  twiByteSeq.len      = 12;
+  twiByteSeq.valueRef = byteArray;
+  runCycle            = inRunCycle;
+
+  fullScaleA  = 4;
+  fullScaleG  = 2000;
+  fullScaleM  = 4;
+
+  newValueAG  = false;
+  newValueM   = false;
+
+  avgSetAG    = 0;
+  avgCntAG    = 0;
+  avgSetM     = 0;
+  avgCntM     = 0;
+
+  errorCntAdrNakAG    = 0;
+  errorCntDataNakAG   = 0;
+  errorCntOverAG      = 0;
+
+  errorCntAdrNakM     = 0;
+  errorCntDataNakM    = 0;
+  errorCntOverM       = 0;
+
+  timeOutTwiStatus    = 0;
+  timeOutTwiDataAG    = 0;
+  timeOutTwiDataM     = 0;
+
+  timeOutStatusAG     = 0;
+  toValueStatusAG     = 0;
+  timeOutStatusM      = 0;
+  toValueStatusM      = 0;
+
+  toCntTwiStatusAG  = 0;
+  toCntTwiStatusM   = 0;
+  toCntTwiDataAG    = 0;
+  toCntTwiDataM     = 0;
+  toCntStatusAG     = 0;
+  toCntStatusM      = 0;
+
+  sumA.x = sumA.y = sumA.z = sumG.x = sumG.y = sumG.z = 0;
+  waitCnt = 2;
+
+  refI2C->getParams(&twiParams);
+  switch(twiParams.speed)
+  {
+    case Twi100k:
+      twiCycle = 10;
+      break;
+
+    case Twi250k:
+      twiCycle = 4;
+      break;
+
+    case Twi400k:
+      twiCycle = 2;
+      break;
+  }
+
+  twiStatusCycle  = 40 * twiCycle;
+  twiDataCycleAG  = 160 * twiCycle;
+  twiDataCycleM   = 100 * twiCycle;
+
+  enableMeasAG  = false;
+  enableMeasM   = false;
+
+  runStateCntTotal = 0;
+}
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+//
+int SensorLSM9DS1::resetAG()
+{
+  twPtr->writeByteReg(AG_Adr, AG_Ctrl8, 0x05);
+
+  // Get ID
+  return(twPtr->readByteReg(AG_Adr, AG_Id));
+}
+
+int SensorLSM9DS1::resetM()
+{
+  twPtr->writeByteReg(M_Adr, M_Ctrl2, 0x0C);
+
+  // Get ID
+  return(twPtr->readByteReg(M_Adr, M_Id));
+}
+
+int SensorLSM9DS1::reset()
+{
+  int retv;
+
+  twPtr->writeByteReg(AG_Adr, AG_Ctrl8, 0x05);
+  twPtr->writeByteReg(M_Adr, M_Ctrl2, 0x0C);
+
+  retv = twPtr->readByteReg(AG_Adr, AG_Id);
+  retv += twPtr->readByteReg(M_Adr, M_Id);
+  return(retv);
+}
+
+void SensorLSM9DS1::setScanAG(byte scValueAG, byte scValueA, byte scValueG)
+{
+  twPtr->writeByteReg(AG_Adr, AG_Ctrl6, scValueAG | scValueA);
+  twPtr->writeByteReg(AG_Adr, AG_Ctrl1, scValueAG | scValueG);
+}
+
+void SensorLSM9DS1::setScanM(byte scValue1, byte scValue2, byte scValue3, byte scValue4)
+{
+  twPtr->writeByteReg(M_Adr, M_Ctrl1, scValue1);
+  twPtr->writeByteReg(M_Adr, M_Ctrl2, scValue2);
+  twPtr->writeByteReg(M_Adr, M_Ctrl3, scValue3);
+  twPtr->writeByteReg(M_Adr, M_Ctrl4, scValue4);
+}
+
+void SensorLSM9DS1::setTimeOutValues(FreqAG fAG, FreqM fM)
+{
+  int freqA = 1190, freqM = 40000;
+  int cycleA, cycleM;
+
+  enableMeasAG = true;
+
+  switch(fAG)
+  {
+    case FreqAG14_9:
+      freqA = 149;
+      break;
+
+    case FreqAG59_5:
+      freqA = 595;
+      break;
+
+    case FreqAG119:
+      freqA = 1190;
+      break;
+
+    case FreqAG238:
+      freqA = 2380;
+      break;
+
+    case FreqAG476:
+      freqA = 4760;
+      break;
+
+    case FreqAG952:
+      freqA = 9520;
+      break;
+
+    case FreqAG_OFF:
+      freqA = 1190;
+      enableMeasAG = false;
+      break;
+  }
+
+  cycleA = (freqA * runCycle) / 10;     // Zyklusfrequenz
+  toValueStatusAG = 1200000 / cycleA;   // Mikrosekunden + 20% Verlängerung
+
+  // Test
+  //toValueStatusAG += 2;
+
+  enableMeasM = true;
+
+  switch(fM)
+  {
+    case FreqM0_625:
+      freqM = 625;
+      break;
+
+    case FreqM1_25:
+      freqM = 1250;
+      break;
+
+    case FreqM2_5:
+      freqM = 2500;
+      break;
+
+    case FreqM5:
+      freqM = 5000;
+      break;
+
+    case FreqM10:
+      freqM = 10000;
+      break;
+
+    case FreqM20:
+      freqM = 20000;
+      break;
+
+    case FreqM40:
+      freqM = 40000;
+      break;
+
+    case FreqM80:
+      freqM = 80000;
+      break;
+
+    case FreqM_OFF:
+      freqM = 40000;
+      enableMeasM = false;
+      break;
+  }
+
+  cycleM = (freqM * runCycle) / 1000;   // Zyklusfrequenz
+  toValueStatusM = 1200000 / cycleM;    // Mikrosekunden + 20% Verlängerung
+
+  // Test
+  //toValueStatusM += 3;
+
+}
+
+void SensorLSM9DS1::begin(FreqAG freqAG, int avgAG, MaxA maxA, MaxG maxG, FreqM freqM, int avgM, MaxM maxM)
+{
+  setScanAG((byte) freqAG, (byte) maxA | A_LpAuto, (byte) maxG | G_LpHH);
+  setScanM((byte) freqM | Mxy_PmMed | M_TmpOn, (byte) maxM, M_Contin, Mz_PmMed);
+
+  setTimeOutValues(freqAG, freqM);
+
+  if(avgAG == 1)
+  {
+    avgSetAG = 0;
+    avgCntAG = 0;
+  }
+  else
+  {
+    avgSetAG = avgAG;
+    avgCntAG = avgAG;
+  }
+
+  if(avgM == 1)
+  {
+    avgSetM = 0;
+    avgCntM = 0;
+  }
+  else
+  {
+    avgSetM = avgM;
+    avgCntM = avgM;
+  }
+
+  delay(10);
+}
+
+void SensorLSM9DS1::begin()
+{
+  //reset();
+
+  delay(10);
+
+  setScanAG(AG_Odr119, A_Fs4g | A_LpAuto, G_Fs2000 | G_LpHH);
+  setScanM(M_Odr40 | Mxy_PmMed | M_TmpOn, M_Fs4G, M_Contin, Mz_PmMed);
+
+  avgSetAG  = 6;
+  avgCntAG  = 6;
+
+  avgSetM   = 0;
+  avgCntM   = 0;
+
+
+  delay(10);
+}
+
+// ----------------------------------------------------------------------------
+// Steuerfunktionen, gezielte Prozessorzugriffe und Hilfsfunktionen
+// ----------------------------------------------------------------------------
+//
+/*
+void SensorLSM9DS1::run0()
+{
+  switch(runState)
+  {
+    case rsInit:
+      runState = rsScanAGReq;
+      break;
+
+      // ------------ Accel & Gyro ------------
+
+    case rsScanAGReq:
+      twPtr->recByteReg(AG_Adr, AG_Status, &twiByte);
+      runState = rsScanAGChk;
+      break;
+
+    case rsScanAGChk:
+      if(twiByte.twiStatus != TwStFin)
+        break;
+
+      if((twiByte.value & 0x03) == 0)
+      {
+        waitCnt = 2;
+        runState = rsWaitAG;
+        break;
+      }
+
+      twiByteSeq.len = 12;
+      twPtr->recByteRegSeq(AG_Adr, G_Out, &twiByteSeq);
+      runState = rsFetchAG;
+      break;
+
+    case rsWaitAG:
+      if(waitCnt > 0)
+      {
+        waitCnt--;
+        break;
+      }
+      else
+      {
+        runState = rsScanAGReq;
+      }
+      break;
+
+    case rsFetchAG:
+      if(twiByte.twiStatus != TwStFin)
+        break;
+
+      for(int i = 0; i < 12; i++)
+        tmpDataAG.byteArray[i] = byteArray[i];
+
+      if(avgSetAG > 0)
+      {
+        sumA.x += (int) tmpDataAG.valueAG.A.x;
+        sumA.y += (int) tmpDataAG.valueAG.A.y;
+        sumA.z += (int) tmpDataAG.valueAG.A.z;
+        sumG.x += (int) tmpDataAG.valueAG.G.x;
+        sumG.y += (int) tmpDataAG.valueAG.G.y;
+        sumG.z += (int) tmpDataAG.valueAG.G.z;
+        avgCntAG--;
+
+        if(avgCntAG == 0)
+        {
+          rawDataAG.valueAG.A.x = short (sumA.x / avgSetAG);
+          rawDataAG.valueAG.A.y = short (sumA.y / avgSetAG);
+          rawDataAG.valueAG.A.z = short (sumA.z / avgSetAG);
+          rawDataAG.valueAG.G.x = short (sumG.x / avgSetAG);
+          rawDataAG.valueAG.G.y = short (sumG.y / avgSetAG);
+          rawDataAG.valueAG.G.z = short (sumG.z / avgSetAG);
+
+          sumA.x = sumA.y = sumA.z = sumG.x = sumG.y = sumG.z = 0;
+          avgCntAG = avgSetAG;
+
+          newValueAG = true;
+        }
+      }
+      else
+      {
+        rawDataAG.valueAG.A.x = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.A.y = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.A.z = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.G.x = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.G.y = tmpDataAG.valueAG.A.x;
+        rawDataAG.valueAG.G.z = tmpDataAG.valueAG.A.x;
+        newValueAG = true;
+      }
+
+      runState = rsScanAGReq;
+      break;
+  }
+}
+
+void SensorLSM9DS1::run1()
+{
+  switch(runState)
+  {
+    case rsInit:
+      runState = rsScanAGReq;
+      break;
+
+      // ------------ Accel & Gyro ------------
+
+    case rsScanAGReq:
+      twPtr->recByteReg(AG_Adr, AG_Status, &twiByte);
+      runState = rsScanAGChk;
+      break;
+
+    case rsScanAGChk:
+      if(twiByte.twiStatus != TwStFin)
+        break;
+
+      if((twiByte.value & 0x03) == 0)
+      {
+        waitCnt = 2;
+        runState = rsWaitAG;
+        break;
+      }
+
+      twiByteSeq.len = 12;
+      twPtr->recByteRegSeq(AG_Adr, G_Out, &twiByteSeq);
+      runState = rsFetchAG;
+      break;
+
+    case rsWaitAG:
+      if(waitCnt > 0)
+      {
+        waitCnt--;
+        break;
+      }
+      else
+      {
+        runState = rsScanAGReq;
+      }
+      break;
+
+    case rsFetchAG:
+      if(twiByteSeq.twiStatus != TwStFin)
+        break;
+
+      for(int i = 0; i < 12; i++)
+        rawDataAG.byteArray[i] = byteArray[i];
+
+      newValueAG = true;
+
+      runState = rsScanAGReq;
+      break;
+  }
+}
+
+*/
+
+void SensorLSM9DS1::stop()
+{
+  enableMeasAG = false;
+  enableMeasM = false;
+}
+
+void SensorLSM9DS1::resume()
+{
+  enableMeasAG = true;
+  enableMeasM = true;
+}
+
+void SensorLSM9DS1::run()
+{
+  runStateCntTotal++;
+
+  switch(runState)
+  {
+    // ------------------------------------------------------------------------
+    case rsInit:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsInit]++;
+      runState = rsScanAGReq;
+      timeOutStatusAG = toValueStatusAG;
+      timeOutStatusM  = toValueStatusM;
+      break;
+
+      // ------------ Accel & Gyro ------------
+
+    // ------------------------------------------------------------------------
+    case rsScanAGReq:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsScanAGReq]++;
+      if(!enableMeasAG)
+      {
+        runState = rsScanMReq;
+        break;
+      }
+
+      twPtr->recByteReg(AG_Adr, AG_Status, &twiByte);
+      timeOutTwiStatus = twiStatusCycle / runCycle + 1;
+      runState = rsScanAGChk;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsWaitAG:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsWaitAG]++;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsScanAGChk:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsScanAGChk]++;
+      if((twiByte.twiStatus != TwStFin) && ((twiByte.twiStatus & TwStError) == 0))
+      {
+        if(timeOutTwiStatus > 0)
+          timeOutTwiStatus--;
+        else
+        {
+          toCntTwiStatusAG++;
+          runState = rsScanAGReq;
+        }
+        break;
+      }
+
+      if((twiByte.twiStatus & TwStError) != 0)
+      {
+        if(twiByte.twiStatus == TwStAdrNak)
+          errorCntAdrNakAG++;
+        else if(twiByte.twiStatus == TwStDataNak)
+          errorCntDataNakAG++;
+        else
+          errorCntOverAG++;
+
+        runState = rsScanAGReq;
+        break;
+      }
+
+      if((twiByte.value & 0x03) == 0)
+      {
+        if(timeOutStatusAG > 0)
+          timeOutStatusAG--;
+        else
+        {
+          timeOutStatusAG = toValueStatusAG;
+          toCntStatusAG++;
+        }
+        runState = rsScanMReq;    // -> Magnet
+        break;
+      }
+
+      timeOutStatusAG = toValueStatusAG;
+      twiByteSeq.len = 12;
+      twPtr->recByteRegSeq(AG_Adr, G_Out, &twiByteSeq);
+      timeOutTwiDataAG = twiDataCycleAG / runCycle + 1;
+      runState = rsFetchAG;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsFetchAG:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsFetchAG]++;
+      if((twiByteSeq.twiStatus != TwStFin) && ((twiByte.twiStatus & TwStError) == 0))
+      {
+        if(timeOutTwiDataAG > 0)
+        {
+          timeOutTwiDataAG--;
+          break;
+        }
+      }
+
+      if(((twiByteSeq.twiStatus & TwStError) != 0) || (timeOutTwiDataAG == 0))
+      {
+        if(twiByteSeq.twiStatus == TwStAdrNak)
+          errorCntAdrNakAG++;
+        else if(twiByteSeq.twiStatus == TwStDataNak)
+          errorCntDataNakAG++;
+        else if(twiByteSeq.twiStatus == TwStOverrun)
+          errorCntOverAG++;
+        else
+          toCntTwiDataAG++;
+
+        twiByteSeq.len = 12;
+        twPtr->recByteRegSeq(AG_Adr, G_Out, &twiByteSeq);
+        timeOutTwiDataAG = twiDataCycleAG / runCycle + 1;
+        break;
+      }
+
+      for(int i = 0; i < 12; i++)
+        comDataAG.byteArray[i] = byteArray[i];
+
+      if(avgSetAG > 0)
+      {
+        sumA.x += comDataAG.valueAG.A.x;
+        sumA.y += comDataAG.valueAG.A.y;
+        sumA.z += comDataAG.valueAG.A.z;
+        sumG.x += comDataAG.valueAG.G.x;
+        sumG.y += comDataAG.valueAG.G.y;
+        sumG.z += comDataAG.valueAG.G.z;
+        avgCntAG--;
+
+        if(avgCntAG == 0)
+        {
+          rawDataAG.valueAG.A.x = sumA.x / avgSetAG;
+          rawDataAG.valueAG.A.y = sumA.y / avgSetAG;
+          rawDataAG.valueAG.A.z = sumA.z / avgSetAG;
+          rawDataAG.valueAG.G.x = sumG.x / avgSetAG;
+          rawDataAG.valueAG.G.y = sumG.y / avgSetAG;
+          rawDataAG.valueAG.G.z = sumG.z / avgSetAG;
+          sumA.x = sumA.y = sumA.z = sumG.x = sumG.y = sumG.z = 0;
+          avgCntAG = avgSetAG;
+          newValueAG = true;
+        }
+      }
+      else
+      {
+        rawDataAG.valueAG.A.x = comDataAG.valueAG.A.x;
+        rawDataAG.valueAG.A.y = comDataAG.valueAG.A.y;
+        rawDataAG.valueAG.A.z = comDataAG.valueAG.A.z;
+        rawDataAG.valueAG.G.x = comDataAG.valueAG.G.x;
+        rawDataAG.valueAG.G.y = comDataAG.valueAG.G.y;
+        rawDataAG.valueAG.G.z = comDataAG.valueAG.G.z;
+        newValueAG = true;
+      }
+
+      runState = rsScanAGReq;
+      break;
+
+      // ------------ Magnet ------------
+
+    // ------------------------------------------------------------------------
+    case rsScanMReq:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsScanMReq]++;
+      if(!enableMeasM)
+      {
+        runState = rsScanAGReq;
+        break;
+      }
+
+      twPtr->recByteReg(M_Adr, M_Status, &twiByte);
+      timeOutTwiStatus = twiStatusCycle / runCycle + 1;
+      runState = rsScanMChk;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsScanMChk:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsScanMChk]++;
+      if((twiByte.twiStatus != TwStFin) && ((twiByte.twiStatus & TwStError) == 0))
+      {
+        if(timeOutTwiStatus > 0)
+          timeOutTwiStatus--;
+        else
+        {
+          toCntTwiStatusM++;
+          runState = rsScanMReq;
+        }
+        break;
+      }
+
+      if((twiByte.twiStatus & TwStError) != 0)
+      {
+        if(twiByte.twiStatus == TwStAdrNak)
+          errorCntAdrNakM++;
+        else if(twiByte.twiStatus == TwStDataNak)
+          errorCntDataNakM++;
+        else
+          errorCntOverM++;
+
+        runState = rsScanAGReq;
+        break;
+      }
+
+      if((twiByte.value & 0x08) == 0)
+      {
+        if(timeOutStatusM > 0)
+          timeOutStatusM--;
+        else
+        {
+          timeOutStatusM = toValueStatusM;
+          toCntStatusM++;
+        }
+        runState = rsScanAGReq;    // -> Accel,Gyro
+        break;
+      }
+
+      timeOutStatusM = toValueStatusM;
+      twiByteSeq.len = 6;
+      twPtr->recByteRegSeq(M_Adr, M_Out, &twiByteSeq);
+      timeOutTwiDataM = twiDataCycleM / runCycle + 1;
+      runState = rsFetchM;
+      break;
+
+    // ------------------------------------------------------------------------
+    case rsFetchM:
+    // ------------------------------------------------------------------------
+      runStateCntArray[rsFetchM]++;
+      if((twiByteSeq.twiStatus != TwStFin) && ((twiByte.twiStatus & TwStError) == 0))
+      {
+        if(timeOutTwiDataM > 0)
+        {
+          timeOutTwiDataM--;
+          break;
+        }
+      }
+
+      if( ((twiByteSeq.twiStatus & TwStError) != 0) || (timeOutTwiDataM == 0) )
+      {
+        if(twiByteSeq.twiStatus == TwStAdrNak)
+          errorCntAdrNakM++;
+        else if(twiByteSeq.twiStatus == TwStDataNak)
+          errorCntDataNakM++;
+        else if(twiByteSeq.twiStatus == TwStOverrun)
+          errorCntOverM++;
+        else
+          toCntTwiDataM++;
+
+        twiByteSeq.len = 6;
+        twPtr->recByteRegSeq(AG_Adr, M_Out, &twiByteSeq);
+        timeOutTwiDataM = twiDataCycleM / runCycle + 1;
+        break;
+      }
+
+      for(int i = 0; i < 6; i++)
+        rawDataM.byteArray[i] = byteArray[i];
+
+      if(avgSetM > 0)
+      {
+        sumM.x += rawDataM.valueM.x;
+        sumM.y += rawDataM.valueM.y;
+        sumM.z += rawDataM.valueM.z;
+        avgCntM--;
+
+        if(avgCntM == 0)
+        {
+          rawDataM.valueM.x = sumM.x / avgSetM;
+          rawDataM.valueM.y = sumM.y / avgSetM;
+          rawDataM.valueM.z = sumM.z / avgSetM;
+          sumM.x = sumM.y = sumM.z = 0;
+          avgCntM = avgSetM;
+          newValueM = true;
+        }
+      }
+      else
+      {
+        newValueM = true;
+      }
+
+      runState = rsScanAGReq;
+      break;
+  }
+}
+
+void  SensorLSM9DS1::syncValuesM()
+{
+  newValueM = false;
+}
+
+bool  SensorLSM9DS1::getValuesM(RawDataMPtr rdptr)
+{
+  if(!newValueM) return(false);
+  for(int i = 0; i < 6; i++)
+    rdptr->byteArray[i] = rawDataM.byteArray[i];
+  newValueM = false;
+  return(true);
+}
+
+bool  SensorLSM9DS1::getValuesM(CalValuePtr calPtr)
+{
+  if(!newValueM) return(false);
+
+  calPtr->x = (float) fullScaleM * (float) rawDataM.valueM.x / (float) 32767;
+  calPtr->y = (float) fullScaleM * (float) rawDataM.valueM.y / (float) 32767;
+  calPtr->z = (float) fullScaleM * (float) rawDataM.valueM.z / (float) 32767;
+
+  newValueM = false;
+  return(true);
+}
+
+void  SensorLSM9DS1::syncValuesAG()
+{
+  newValueAG = false;
+}
+
+bool  SensorLSM9DS1::getValuesAG(RawDataAGPtr rdptr)
+{
+  if(!newValueAG) return(false);
+  for(int i = 0; i < 12; i++)
+    rdptr->byteArray[i] = rawDataAG.byteArray[i];
+  newValueAG = false;
+  return(true);
+}
+
+bool  SensorLSM9DS1::getValuesAG(CalValueAGPtr calPtr)
+{
+  if(!newValueAG) return(false);
+
+  calPtr->G.x = (float) fullScaleG * (float) rawDataAG.valueAG.G.x / (float) 32767;
+  calPtr->G.y = (float) fullScaleG * (float) rawDataAG.valueAG.G.y / (float) 32767;
+  calPtr->G.z = (float) fullScaleG * (float) rawDataAG.valueAG.G.z / (float) 32767;
+
+  calPtr->A.x = (float) fullScaleA * (float) rawDataAG.valueAG.A.x / (float) 32767;
+  calPtr->A.y = (float) fullScaleA * (float) rawDataAG.valueAG.A.y / (float) 32767;
+  calPtr->A.z = (float) fullScaleA * (float) rawDataAG.valueAG.A.z / (float) 32767;
+
+  newValueAG = false;
+  return(true);
+}
+
+bool  SensorLSM9DS1::getAvgValuesAG(CalValueAGPtr calPtr)
+{
+  if(!newValueAG) return(false);
+  newValueAG = false;
+
+  if(avgSetAG > 0)
+  {
+    sumA.x += rawDataAG.valueAG.A.x;
+    sumA.y += rawDataAG.valueAG.A.y;
+    sumA.z += rawDataAG.valueAG.A.z;
+    sumG.x += rawDataAG.valueAG.G.x;
+    sumG.y += rawDataAG.valueAG.G.y;
+    sumG.z += rawDataAG.valueAG.G.z;
+    avgCntAG--;
+
+    if(avgCntAG > 0) return(false);
+
+    calPtr->G.x = (float) fullScaleG * (float) (sumG.x / avgSetAG) / (float) 32767;
+    calPtr->G.y = (float) fullScaleG * (float) (sumG.y / avgSetAG) / (float) 32767;
+    calPtr->G.z = (float) fullScaleG * (float) (sumG.z / avgSetAG) / (float) 32767;
+
+    calPtr->A.x = (float) fullScaleA * (float) (sumA.x / avgSetAG) / (float) 32767;
+    calPtr->A.y = (float) fullScaleA * (float) (sumA.y / avgSetAG) / (float) 32767;
+    calPtr->A.z = (float) fullScaleA * (float) (sumA.z / avgSetAG) / (float) 32767;
+
+    avgCntAG = avgSetAG;
+    return(true);
+  }
+
+  calPtr->G.x = (float) fullScaleG * (float) rawDataAG.valueAG.G.x / (float) 32767;
+  calPtr->G.y = (float) fullScaleG * (float) rawDataAG.valueAG.G.y / (float) 32767;
+  calPtr->G.z = (float) fullScaleG * (float) rawDataAG.valueAG.G.z / (float) 32767;
+
+  calPtr->A.x = (float) fullScaleA * (float) rawDataAG.valueAG.A.x / (float) 32767;
+  calPtr->A.y = (float) fullScaleA * (float) rawDataAG.valueAG.A.y / (float) 32767;
+  calPtr->A.z = (float) fullScaleA * (float) rawDataAG.valueAG.A.z / (float) 32767;
+
+  return(true);
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// Ereignisbearbeitung und Interrupts
+// ----------------------------------------------------------------------------
+//
+
+// ----------------------------------------------------------------------------
+//                      D e b u g - H i l f e n
+// ----------------------------------------------------------------------------
+//
+dword SensorLSM9DS1::debGetDword(int code)
+{
+  dword retv;
+
+
+  switch(code)
+  {
+    case 1:
+      retv = toValueStatusAG;
+      break;
+
+    case 2:
+      retv = toValueStatusM;
+      break;
+
+    default:
+      retv = 0;
+      break;
+  }
+  return(retv);
+}
+
+
+dword SensorLSM9DS1::debGetRunState(int code)
+{
+  if(0 <= code < 9)
+    return(runStateCntArray[code]);
+  else
+    return(0);
+}
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.h
new file mode 100644
index 0000000000000000000000000000000000000000..63cb831c96688b30a85397927a14a52dcb6a15f2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SensorLSM9DS1/SensorLSM9DS1.h
@@ -0,0 +1,363 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   SensorLSM9DS1.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef SENSORLSM9DS1_H
+#define SENSORLSM9DS1_H
+
+#include "Arduino.h"
+#include "arduinoDefs.h"
+#include "IntrfTw.h"
+
+// ----------------------------------------------------------------------------
+
+// ------------------------ Acceleration and Gyroscope -------
+#define AG_Adr    0x6B
+// ------------------------ Acceleration and Gyroscope -------
+#define AG_Id     0x0F
+#define AG_Ctrl1  0x10
+#define G_Out     0x18
+#define AG_Ctrl6  0x20
+#define AG_Ctrl8  0x22
+#define AG_Status 0x27
+
+#define AG_Rate(x)      (x << 5)
+#define AG_Odr14_9      0x20
+#define AG_Odr59_5      0x40
+#define AG_Odr119       0x60
+#define AG_Odr238       0x80
+#define AG_Odr476       0xA0
+#define AG_Odr952       0xC0
+
+typedef enum _FreqAG
+{
+  FreqAG_OFF  = 0xFF,
+  FreqAG14_9  = AG_Odr14_9,
+  FreqAG59_5  = AG_Odr59_5,
+  FreqAG119   = AG_Odr119,
+  FreqAG238   = AG_Odr238,
+  FreqAG476   = AG_Odr476,
+  FreqAG952   = AG_Odr952
+} FreqAG;
+
+#define AG_FullScale(x) (x << 3)
+#define A_Fs2g          0x00
+#define A_Fs4g          0x10
+#define A_Fs8g          0x18
+#define A_Fs16g         0x08
+#define G_Fs245         0x00
+#define G_Fs2000        0x18
+#define G_Fs500         0x08
+
+typedef enum _MaxA
+{
+  MaxAcc2g    = A_Fs2g,
+  MaxAcc4g    = A_Fs4g,
+  MaxAcc8g    = A_Fs8g,
+  MaxAcc16g   = A_Fs16g
+} MaxA;
+
+typedef enum _MaxG
+{
+  MaxGyro245dps   = G_Fs245,
+  MaxGyro500dps   = G_Fs500,
+  MaxGyro2000dps  = G_Fs2000
+} MaxG;
+
+#define AG_LowPass(x)   (x)
+#define A_LpAuto        0x00
+#define A_Lp50          0x07
+#define A_Lp105         0x06
+#define A_Lp211         0x05
+#define A_Lp408         0x04
+#define G_LpLL          0x00
+#define G_LpLH          0x01
+#define G_LpHL          0x02
+#define G_LpHH          0x03
+
+// ------------------------ Magnetic Field -------
+#define M_Adr     0x1E
+// ------------------------ Magnetic Field -------
+#define M_Id      0x0F
+#define M_Ctrl1   0x20
+#define M_Ctrl2   0x21
+#define M_Ctrl3   0x22
+#define M_Ctrl4   0x23
+#define M_Ctrl5   0x24
+#define M_Status  0x27
+#define M_Out     0x28
+
+// Control 1
+#define M_Rate(x)       (x << 2)
+#define M_Odr0_625      0x00
+#define M_Odr1_25       0x04
+#define M_Odr2_5        0x08
+#define M_Odr5          0x0C
+#define M_Odr10         0x10
+#define M_Odr20         0x14
+#define M_Odr40         0x18
+#define M_Odr80         0x1C
+
+typedef enum _FreqM
+{
+  FreqM_OFF   = 0xFF,
+  FreqM0_625  = M_Odr0_625,
+  FreqM1_25   = M_Odr1_25,
+  FreqM2_5    = M_Odr2_5,
+  FreqM5      = M_Odr5,
+  FreqM10     = M_Odr10,
+  FreqM20     = M_Odr20,
+  FreqM40     = M_Odr40,
+  FreqM80     = M_Odr80
+} FreqM;
+
+#define M_Temp(x)       (x << 7)
+#define M_TmpOn         0x80
+#define M_TmpOff        0x00
+
+#define Mxy_Power(x)    (x << 6)
+#define Mxy_PmLow       0x00
+#define Mxy_PmMed       0x20
+#define Mxy_PmHigh      0x40
+#define Mxy_PmUhigh     0x60
+
+// Control 2
+#define M_FullScale(x)  (x << 5)
+#define M_Fs4G          0x00
+#define M_Fs8G          0x20
+#define M_Fs12G         0x40
+#define M_Fs16G         0x60
+
+typedef enum _MaxM
+{
+  MaxMag4G      = M_Fs4G,
+  MaxMag8G      = M_Fs8G,
+  MaxMag12G     = M_Fs12G,
+  MaxMag16G     = M_Fs16G
+} MaxM;
+
+
+// Control 3
+#define M_OpMode(x)     (x)
+#define M_Contin        0x00
+#define M_Single        0x01
+#define M_Down          0x10
+
+// Control 4
+#define Mz_Power(x)    (x << 2)
+#define Mz_PmLow       0x00
+#define Mz_PmMed       0x04
+#define Mz_PmHigh      0x08
+#define Mz_PmUhigh     0x0C
+
+
+typedef enum _RunState
+{
+  rsInit,
+  rsScanAGReq,
+  rsWaitAG,
+  rsScanAGChk,
+  rsFetchAG,
+  rsScanMReq,
+  rsScanMChk,
+  rsFetchM
+} RunState;
+
+#define NrOfRunStates 8
+
+typedef struct _RawValue
+{
+  short int   x;
+  short int   y;
+  short int   z;
+} RawValue;
+
+typedef struct _SumValue
+{
+  int   x;
+  int   y;
+  int   z;
+} SumValue, *SumValuePtr;
+
+typedef struct _RawValueAG
+{
+  RawValue  G;
+  RawValue  A;
+} RawValueAG;
+
+typedef union _RawDataAG
+{
+  byte        byteArray[12];
+  RawValueAG  valueAG;
+} RawDataAG, *RawDataAGPtr;
+
+typedef union _RawDataM
+{
+  byte        byteArray[6];
+  RawValue    valueM;
+} RawDataM, *RawDataMPtr;
+
+typedef struct _CalValue
+{
+  float   x;
+  float   y;
+  float   z;
+} CalValue, *CalValuePtr;
+
+typedef struct _CalValueAG
+{
+  CalValue  G;
+  CalValue  A;
+} CalValueAG, *CalValueAGPtr;
+
+typedef struct _SensorErrors
+{
+
+} SensorErrors, *SensorErrorsPtr;
+
+class SensorLSM9DS1
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten und Funktionen
+  // --------------------------------------------------------------------------
+  //
+  IntrfTw     *twPtr;
+  TwiByte     twiByte;
+  TwiByteSeq  twiByteSeq;
+  byte        byteArray[12];
+
+  bool        enableMeasAG;
+  bool        newValueAG;
+  RawDataAG   rawDataAG;
+  RawDataAG   comDataAG;
+
+  bool        enableMeasM;
+  bool        newValueM;
+  RawDataM    rawDataM;
+
+  int         fullScaleA;
+  int         fullScaleG;
+  int         fullScaleM;
+
+  SumValue    sumA;
+  SumValue    sumG;
+  int         avgSetAG;
+  int         avgCntAG;
+
+  SumValue    sumM;
+  int         avgSetM;
+  int         avgCntM;
+
+  dword       timeOutTwiStatus;
+  dword       timeOutTwiDataAG;
+  dword       timeOutTwiDataM;
+
+  dword       timeOutStatusAG;
+  dword       toValueStatusAG;
+  dword       timeOutStatusM;
+  dword       toValueStatusM;
+
+  int         twiCycle;
+  int         twiStatusCycle;
+  int         twiDataCycleAG;
+  int         twiDataCycleM;
+
+  RunState    runState;
+  int         waitCnt;
+  int         runCycle;
+
+  void setTimeOutValues(FreqAG fAG, FreqM fM);
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen der Basis-Klasse
+  // --------------------------------------------------------------------------
+
+  SensorLSM9DS1(IntrfTw *refI2C, int inRunCycle);
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  int resetAG();
+  int resetM();
+  int reset();
+
+  void setScanAG(byte scValueAG, byte scValueA, byte scValueG);
+  // Messparameter für Accel und Gyro
+  // scValueAG = Abtastrate
+  // scValueA  = Vollausschlag und Tiefpass für Beschleunigung
+  // scValueB  = Vollausschlag und Tiefpass für Gyrometer
+
+  void setScanM(byte scValue1, byte scValue2, byte scValue3, byte scValue4);
+  // Messparameter für Magnetfeld
+  // scValue1 = Abtastrate, Temperaturkompensation und XY-Powermode
+  // scValue2 = Vollausschlag
+  // scValue3 = Betriebsart
+  // scValue4 = Z-Powermode
+
+
+  void begin(FreqAG freqAG, int avgAG, MaxA maxA, MaxG maxG, FreqM freqM, int avgM, MaxM maxM);
+  void begin();
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void run();
+  void run0();
+  void run1();
+  void stop();
+  void resume();
+
+  // --------------------------------------------------------------------------
+  // Datenaustausch
+  // --------------------------------------------------------------------------
+  //
+  dword       errorCntOverAG;
+  dword       errorCntAdrNakAG;
+  dword       errorCntDataNakAG;
+
+  dword       errorCntOverM;
+  dword       errorCntAdrNakM;
+  dword       errorCntDataNakM;
+
+  dword       toCntTwiStatusAG;
+  dword       toCntTwiStatusM;
+  dword       toCntTwiDataAG;
+  dword       toCntTwiDataM;
+  dword       toCntStatusAG;
+  dword       toCntStatusM;
+
+  void  syncValuesAG();
+  bool  getValuesAG(RawDataAGPtr rdptr);
+  bool  getValuesAG(CalValueAGPtr calPtr);
+  bool  getAvgValuesAG(CalValueAGPtr calPtr);
+  void  syncValuesM();
+  bool  getValuesM(RawDataMPtr rdptr);
+  bool  getValuesM(CalValuePtr calPtr);
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
+
+  // ----------------------------------------------------------------------------
+  //                      D e b u g - H i l f e n
+  // ----------------------------------------------------------------------------
+  //
+  dword runStateCntArray[NrOfRunStates];
+  dword runStateCntTotal;
+  dword debGetDword(int code);
+  dword debGetRunState(int code);
+
+};
+
+#endif // SENSORLSM9DS1_H
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SensorLSM9DS1/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SensorLSM9DS1/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..6432e5ccb8930ce40504aa4f03e463f2df00fac0
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SensorLSM9DS1/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "SensorLSM9DS1",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapComDue/SoaapComDue.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapComDue/SoaapComDue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b24e6f4f90c3ecc1588b5af5dde88b4b922e8ee7
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapComDue/SoaapComDue.cpp
@@ -0,0 +1,212 @@
+//-----------------------------------------------------------------------------
+// Thema:   Steuerung optischer und akustischer Ausgaben für Perfomer
+// Datei:   SoaapComDue.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   01.April 2022
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zum Zugriff auf den
+// SOAAP-Master über eine serielle Schnittstelle des Arduino DUE.
+//
+
+#include "SoaapComDue.h"
+
+#define next(x) nextState = &SoaapComDue::x
+
+// ----------------------------------------------------------------------------
+// Konstruktoren und Initialisierungen
+// ----------------------------------------------------------------------------
+//
+SoaapComDue::SoaapComDue(USARTClass *serial, SoaapMsg *soaMsg)
+{
+  pCom = serial;
+  pMsg = soaMsg;
+  nextState = &SoaapComDue::runInit;
+
+  nrBytesIn = 0;
+  serInIdx = 0;
+  serInChar = 0;
+  serInCount = 0;
+  slaveAdr = 0;
+  slaveArea = 0;
+  appId = (SoaapApId) 0;
+
+  measIdx = 0;
+  nrMeas = 0;
+  resMeas = 0;
+  slaveIdx = 0;
+  anyNewVal = false;
+}
+
+// --------------------------------------------------------------------------
+// lokale Methoden (Zustandsmaschine)
+// --------------------------------------------------------------------------
+//
+void SoaapComDue::runInit()
+{
+  next(runWaitMsg);
+}
+
+void SoaapComDue::runWaitMsg()
+{
+  nrBytesIn = pCom->available();
+  // Anzahl der über <serial> eingetroffenen Bytes (Zeichen)
+
+  if(nrBytesIn < 1) return;
+  // Beim nächsten Takt wieder in diesen Zustand, wenn kein Zeichen da
+
+  for(serInIdx = 0; serInIdx < nrBytesIn; serInIdx++)
+  {                               // Suchen nach Startzeichen
+    serInChar = pCom->read();
+    if(serInChar < 0x20) break;
+  }
+
+  if(serInIdx == nrBytesIn) return;
+  // Beim nächsten Takt wieder in diesen Zustand, wenn Startzeichen nicht dabei
+
+  slaveArea = serInChar & 0x1F;   // Bereich auskodieren
+
+  serInIdx = 0;     // Index neu setzen für Inhaltszuordnung
+  next(runHeader);
+  // Beim nächsten Takt zum Zustand <runHeader>
+
+}
+
+void SoaapComDue::runHeader()
+{
+    nrBytesIn = pCom->available();
+    // Anzahl der über Serial1 eingetroffenen Bytes (Zeichen)
+
+    if(nrBytesIn < 1) return;
+    // Beim nächsten Takt wieder in diesen Zustand, wenn kein Zeichen da
+
+    serInChar = pCom->read();
+    // einzelnes Zeichen lesen
+
+    if(serInIdx == 0)             // nach der Area folgt die Slaveadresse
+    {
+      slaveAdr = serInChar & 0x1F;               // 1 - 31
+      slaveIdx = slaveAdr;        // vorläufig lineare Adress/Index-Zuordnung
+      serInIdx++;
+      // Beim nächsten Takt wieder in diesen Zustand
+    }
+    else                     // und dann die Anwendungskennung
+    {
+      appId = (SoaapApId) serInChar;
+      measIdx = 0;                      // Index für Messwertunterscheidung
+      serInIdx = 0;                     // Index für Messwertaufbau
+      nrMeas = pMsg->measCnt(appId);   // Anzahl Messwerte im Telegramm
+      resMeas = pMsg->measRes(appId);  // Auflösung der Messwerte in Zeichen
+      next(runValues);
+      // Beim nächsten Takt zum Zustand <runValues>
+    }
+}
+
+void SoaapComDue::runValues()
+{
+  int i;
+
+  do
+  {
+    nrBytesIn = pCom->available();
+    // Anzahl der über Serial1 eingetroffenen Bytes (Zeichen)
+
+    if(nrBytesIn < 1) return;
+    // Beim nächsten Takt wieder in diesen Zustand, wenn kein Zeichen da
+
+    for(i = 0; i < nrBytesIn; i++)
+    {
+      tmpBuffer[serInIdx++] = pCom->read();
+      // einzelnes Zeichen lesen
+
+      if(serInIdx == resMeas) break;
+      // Alle Zeichen vom Messwert da, also raus
+    }
+
+    if(serInIdx < resMeas) return;
+    // Wenn noch nicht ale Zeichen vom Messwert erfasst, dann von vorn
+
+    slValList[slaveIdx].measList[measIdx++] = pMsg->asc2meas(tmpBuffer);
+    // Zeichenkette in Messwert wandeln und speichern
+
+    if(measIdx == nrMeas) break;
+    // Falls mehr als ein Telegramm eingetroffen ist
+    // muss hier ein Ausstieg erfolgen
+
+    serInIdx = 0;   // Nächste Zeichenfolge
+  }
+  while (pCom->available() > 0);
+  // Die Taktzeit der Zustandsmaschine ist größer, als die
+  // Übertragungszeit von einem Zeichen.
+  // Deshalb werden in einem Zustandstakt alle inzwischen eingetroffenen
+  // Zeichen bearbeitet.
+
+  if(measIdx < nrMeas) return;
+  // Im Zustand bleiben, bis alle Messwerte gewandelt sind
+
+  slValList[slaveIdx].newVal = true;
+  anyNewVal = true;
+
+  next(runWaitMsg);
+}
+
+// --------------------------------------------------------------------------
+// lokale Methoden (Hilfsfunktionen)
+// --------------------------------------------------------------------------
+//
+
+// Erster Slave (kleinste Adresse) mit Daten
+//
+int   SoaapComDue::getSlDataAvail()
+{
+  for(int i = 1; i <= ScdNrOfSlaves; i++)
+    if(slValList[i].newVal)
+      return(i);
+  return(0);
+}
+
+// ----------------------------------------------------------------------------
+// Anwenderschnittstelle (Funktionen/Methoden)
+// ----------------------------------------------------------------------------
+//
+
+// (zyklischer) Aufruf zum Ablauf
+//
+void SoaapComDue::run()
+{
+  if(nextState != NULL)
+    (this->*nextState)();
+}
+
+// Daten von irgendeinem Slave verfügbar
+//
+int   SoaapComDue::anyDataAvail()
+{
+  if(!anyNewVal) return(0);
+  else return(getSlDataAvail());
+}
+
+// Daten von bestimmtem Slave verfügbar
+//
+bool  SoaapComDue::slDataAvail(int slAdr)
+{
+  return(slValList[getSlIdxAdr(slAdr)].newVal);
+}
+
+// Daten von einem bestimmten Slave abholen
+//
+int   SoaapComDue::getData(int slAdr, pMeasValues pMeas)
+{
+  int slIdx = getSlIdxAdr(slAdr);
+  for(int i = 0; i < 8; i++)
+    pMeas->defShort[i] = slValList[slIdx].measList[i];
+  slValList[slIdx].newVal = false;
+  anyNewVal = false;
+  for(int i = 1; i <= ScdNrOfSlaves; i++)
+    if(slValList[i].newVal) anyNewVal = true;
+  return(0);
+}
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapComDue/SoaapComDue.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapComDue/SoaapComDue.h
new file mode 100644
index 0000000000000000000000000000000000000000..990faa3710733dedfd4819f254c11b8900f15d65
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapComDue/SoaapComDue.h
@@ -0,0 +1,132 @@
+//-----------------------------------------------------------------------------
+// Thema:   Steuerung optischer und akustischer Ausgaben für Perfomer
+// Datei:   SoaapComDue.h
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   01.April 2022
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zum Zugriff auf den
+// SOAAP-BLE-Master über eine serielle Schnittstelle des Arduino DUE.
+//
+
+#ifndef SoaapComDue_h
+#define SoaapComDue_h
+
+#define ScdNrOfSlaves     6
+
+#include "USARTClass.h"
+#include "SoaapMsg.h"
+
+#ifndef byte
+#define byte unsigned char
+#endif
+
+
+class SoaapComDue
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // --------------------------------------------------------------------------
+  //
+  SoaapComDue(USARTClass *serial, SoaapMsg *soaMsg);
+
+  // --------------------------------------------------------------------------
+  // öffentliche Datentypen
+  // --------------------------------------------------------------------------
+  //
+  typedef union
+  {
+    short   defShort[9];
+    short   maxShort[13];
+    float   maxFloat[6];
+  } MeasValues, *pMeasValues;
+
+private:
+  // --------------------------------------------------------------------------
+  // lokale Datentypen
+  // --------------------------------------------------------------------------
+  //
+
+  typedef void (SoaapComDue::*CbVector)(void);
+  typedef struct
+  {
+    int         slaveArea;
+    int         slaveAdr;
+    SoaapApId   apId;
+    bool        newVal;
+    short       measList[13];
+  } SlaveValues, *pSlaveValues;
+
+private:
+  // --------------------------------------------------------------------------
+  // lokale Variablen
+  // --------------------------------------------------------------------------
+  //
+  USARTClass *pCom;
+  SoaapMsg   *pMsg;
+  CbVector    nextState;
+
+  int         nrBytesIn;          // Antahl aktuell empfangener Zeichen
+  int         serInCount;         // Zähler für empfangene Zeichen
+  int         serInIdx;           // Index für besonderes Zeichen
+  byte        serInChar;          // Einzelnes empfangenes Zeichen
+  int         slaveAdr;           // Adresse des Soaap-Slave
+  int         slaveArea;          // Quellennetzwerk-Info, Bereich, o.ä.
+  SoaapApId   appId;              // Anwendungskennung, Datentyp, o.ä.
+
+  int         measIdx;            // Index für den aktuellen Messwert
+  int         nrMeas;             // Anzahl der Messwerte im Telegramm
+  int         resMeas;            // Auflösung der Messwerte in Zeichen
+  bool        anyNewVal;          // Neuer Wert von beliebigem Slave
+
+  SlaveValues slValList[ScdNrOfSlaves + 1]; // Vorläufige Liste aller Messwerte
+  int         slaveIdx;           // Index für lokale Slaveverwaltung
+
+  byte        tmpBuffer[128];     // Zwischenspeicher für empfangene Zeichen
+
+  // --------------------------------------------------------------------------
+  // Inline-Methoden
+  // --------------------------------------------------------------------------
+  //
+
+  // Index von Slave best. Adresse für Datenliste
+  //
+  int  getSlIdxAdr(int slAdr)
+  {
+    // Zur Zeit sind Index und Slaveadresse identisch (1-6)
+    // Das wir später bei freier Zuordnung angepasst
+    return(slAdr);
+  }
+
+  // --------------------------------------------------------------------------
+  // lokale Methoden (Zustandsmaschine)
+  // --------------------------------------------------------------------------
+  //
+  void runInit();
+  void runWaitMsg();
+  void runHeader();
+  void runValues();
+
+  // --------------------------------------------------------------------------
+  // lokale Methoden (Hilfsfunktionen)
+  // --------------------------------------------------------------------------
+  //
+  int   getSlDataAvail();
+
+public:
+  // --------------------------------------------------------------------------
+  // Anwenderschnittstelle (Funktionen)
+  // --------------------------------------------------------------------------
+  //
+  void run();                     // (zyklischer) Aufruf zum Ablauf
+  int   anyDataAvail();           // Daten von irgendeinem Slave verfügbar
+  bool  slDataAvail(int slAdr);   // Daten von bestimmtem Slave verfügbar
+  int   getData(int slAdr, pMeasValues pMeas);
+  // Daten von einem bestimmten Slave abholen
+
+};
+
+#endif // SoaapComDue_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapComDue/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapComDue/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..d2cf1518adba3b9cb3a57d0eca8963fbceca345c
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapComDue/library.json
@@ -0,0 +1,4 @@
+{
+    "name": "SoaapComDue",
+    "version": "0.0.0+20220804174235"
+  }
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapMsg/SoaapMsg.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapMsg/SoaapMsg.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f3f29704b3b1d5e02528071b0527804940435bd
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapMsg/SoaapMsg.cpp
@@ -0,0 +1,159 @@
+//-----------------------------------------------------------------------------
+// Thema:   Steuerung optischer und akustischer Ausgaben für Perfomer
+// Datei:   SoaapMsg.h
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   18. März 2022
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Generierung
+// von Meldungen und Telegrammen, die im Rahmen des SOAAP-Projektes
+// eingesetzt werden.
+//
+
+#include "SoaapMsg.h"
+
+// ----------------------------------------------------------------------------
+// Konstruktoren und Initialisierungen
+// ----------------------------------------------------------------------------
+//
+SoaapMsg::SoaapMsg()
+{
+
+}
+
+// ----------------------------------------------------------------------------
+// Anwenderschnittstelle (Funktionen)
+// ----------------------------------------------------------------------------
+//
+
+// Erstellen eines ASCII-Telegramms zum Übertragen der Messwerte
+//
+int   SoaapMsg::getMsgA(int area, int slvNr, SoaapApId appId, char *dest, byte *meas)
+{
+  int   msgIdx = 0;
+  int   measIdx;
+  int   measLen;
+  byte  measByte;
+  char  measChar;
+
+  dest[msgIdx++]  = (char) (area | 0x10);
+  dest[msgIdx++]  = (char) (slvNr | 0x60);
+  dest[msgIdx++]  = (char) (appId);
+
+  switch(appId)
+  {
+    case saiDefaultMeas:
+      measLen = 18;
+      break;
+
+    case saiDefaultMeasCtrl:
+      measLen = 18;
+      break;
+
+   case saiMaximalMeas:
+      measLen = 26;
+      break;
+  }
+
+  for(measIdx = 0; measIdx < measLen; measIdx++)
+  {
+    measByte = meas[measIdx];
+
+    // Erst das niederwertige Nibble als Hex-Ascii eintragen
+    //
+    measChar = (measByte & 0x0F) | 0x30;
+    if (measChar > 0x39) measChar += 7;
+    dest[msgIdx++] = measChar;
+
+    // dann das höherwertige Nibble
+    //
+    measChar = (measByte >> 4) | 0x30;
+    if (measChar > 0x39) measChar += 7;
+    dest[msgIdx++] = measChar;
+  }
+
+  if(appId == saiDefaultMeasCtrl)
+  {
+    measByte = meas[20];
+
+    // Erst das niederwertige Nibble als Hex-Ascii eintragen
+    //
+    measChar = (measByte & 0x0F) | 0x30;
+    if (measChar > 0x39) measChar += 7;
+    dest[msgIdx++] = measChar;
+
+    // dann das höherwertige Nibble
+    //
+    measChar = (measByte >> 4) | 0x30;
+    if (measChar > 0x39) measChar += 7;
+    dest[msgIdx++] = measChar;
+  }
+
+  dest[msgIdx] = '\0';
+  return(msgIdx);
+}
+
+// Umwandeln eines Messwert aus ASCII-Telegramm in Integer
+//
+short  SoaapMsg::asc2meas(byte *ascList)
+{
+  unsigned short retv;
+
+  retv = getVal(ascList[0]);
+  retv += getVal(ascList[1]) << 4;
+  retv += getVal(ascList[2]) << 8;
+  retv += getVal(ascList[3]) << 12;
+
+  return((short) retv);
+}
+
+// Auflösung der Messwerte in Zeichen (Bytes)
+//
+int   SoaapMsg::measRes(SoaapApId appId)
+{
+  int retv = 0;
+
+  switch(appId)
+  {
+    case saiDefaultMeas:
+      retv = 4;
+      break;
+
+    case saiDefaultMeasCtrl:
+      retv = 4;
+      break;
+
+    case saiMaximalMeas:
+      retv = 4;
+      break;
+  }
+
+  return(retv);
+}
+
+// Anzahl der Messwerte im Telegramm
+//
+int   SoaapMsg::measCnt(SoaapApId appId)
+{
+  int retv = 0;
+
+  switch(appId)
+  {
+    case saiDefaultMeas:
+      retv = 9;
+      break;
+
+    case saiDefaultMeasCtrl:
+      retv = 9;
+      break;
+
+    case saiMaximalMeas:
+      retv = 13;
+      break;
+  }
+
+  return(retv);
+}
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapMsg/SoaapMsg.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapMsg/SoaapMsg.h
new file mode 100644
index 0000000000000000000000000000000000000000..20df5732381c353181e02ce74cf3cf193789c5a0
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapMsg/SoaapMsg.h
@@ -0,0 +1,73 @@
+//-----------------------------------------------------------------------------
+// Thema:   Steuerung optischer und akustischer Ausgaben für Perfomer
+// Datei:   SoaapMsg.h
+// Editor:  Robert Patzke
+// URI/URL: www.hs-hannover.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   18. März 2022
+//
+// Diese Bibliothek (Klassse) enthält diverse Ressourcen zur Generierung
+// von Meldungen und Telegrammen, die im Rahmen des SOAAP-Projektes
+// eingesetzt werden.
+//
+
+#ifndef SoaapMsg_h
+#define SoaapMsg_h
+
+#include "arduinoDefs.h"
+
+typedef enum
+{
+  saiDefaultMeas = 0x68,
+  saiMaximalMeas = 0x69,
+  saiDefaultMeasCtrl = 0x6A
+} SoaapApId;
+
+class SoaapMsg
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // --------------------------------------------------------------------------
+  //
+  SoaapMsg();
+
+private:
+  // --------------------------------------------------------------------------
+  // lokale Variablen
+  // --------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Inline-Methoden
+  // --------------------------------------------------------------------------
+  //
+  int getVal(char hexAsc)
+  {
+    if(hexAsc < 0x39) return(hexAsc - 0x30);
+    else return(hexAsc - 0x37);
+  }
+
+
+public:
+  // --------------------------------------------------------------------------
+  // Anwenderschnittstelle (Funktionen)
+  // --------------------------------------------------------------------------
+  //
+
+  int   getMsgA(int area, int slvNr, SoaapApId appId, char *dest, byte *meas);
+  // Erstellen eines ASCII-Telegramms zum Übertragen der Messwerte
+
+  short asc2meas(byte *ascList);
+  // Umwandeln eines Messwert aus ASCII-Telegramm in Integer
+
+  int   measRes(SoaapApId appId);
+  // Auflösung der Messwerte in Zeichen (Bytes)
+
+  int   measCnt(SoaapApId appId);
+  // Anzahl der Messwerte
+
+};
+
+#endif // SoaapMsg_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapMsg/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapMsg/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..86be2b961f0f6f6dae95ed22fadc55f7a1c58826
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/SoaapMsg/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "SoaapMsg",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/StateMachine/StateMachine.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/StateMachine/StateMachine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c1f78d3b83eabbc30463d78e693b470e345e140
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/StateMachine/StateMachine.cpp
@@ -0,0 +1,480 @@
+// ---------------------------------------------------------------------------
+// File:        StateMachine.cpp
+// Editors:     Robert Patzke,
+// Start:       07. February 2018
+// Last change: 22. February 2021
+// URI/URL:     www.mfp-portal.de, homeautomation.x-api.de
+// Licence:     Creative Commons CC-BY-SA
+// ---------------------------------------------------------------------------
+//
+
+#include "StateMachine.h"
+
+// ---------------------------------------------------------------------------
+// Constructors and initialisations
+// ---------------------------------------------------------------------------
+//
+
+int  StateMachine::StateMachine_InstCounter;
+
+StateMachine::StateMachine(){;} // @suppress("Class members should be properly initialized")
+
+StateMachine::StateMachine(StatePtr firstState, StatePtr anyState, int cycle)
+{
+  begin(firstState, anyState, cycle);
+}
+
+StateMachine::StateMachine(StatePtr firstState, StatePtr anyState, int cycle, MicsecFuPtr micsecFu)
+{
+  begin(firstState, anyState, cycle, micsecFu);
+}
+
+void StateMachine::begin(StatePtr firstState, StatePtr anyState, int cycle)
+{
+  begin(firstState, anyState, cycle, NULL);
+}
+
+void StateMachine::begin(StatePtr firstState, StatePtr anyState, int cycle, MicsecFuPtr micsecFu)
+{
+  nextState     = firstState;
+  doAlways      = anyState;
+  cycleTime     = cycle;
+  frequency     = 1000 / cycle;
+  delay         = 0;
+  delaySet      = 0;
+  repeatDelay   = false;
+  userStatus    = 0;
+
+  StateMachine_InstCounter++;
+  instNumber    = StateMachine_InstCounter;
+  micsFuPtr     = micsecFu;
+}
+
+// ---------------------------------------------------------------------------
+// run      State enter function, has to be cyclic called
+// ---------------------------------------------------------------------------
+//
+void StateMachine::run()
+{
+  unsigned long startMics = 0, diffMics;
+
+  runCounter++;
+
+  if(timeOutCounter > 0)
+    timeOutCounter--;
+
+  if(timeMeasureOn)
+    timeMeasureCounter++;
+
+  if(doAlways != NULL)
+    doAlways();
+
+  if(delay > 0)
+  {
+    delay--;
+    return;
+  }
+
+  if(repeatDelay)
+    delay = delaySet;
+
+  if(useProgList)
+  {
+    if(progIndex == progEndIdx)
+    {
+      if(loopProgList)
+      {
+        progIndex = 0;
+        nextState = progList[progIndex];
+        progIndex++;
+      }
+      else
+      {
+        useProgList = false;
+        nextState = finProgState;
+      }
+    }
+    else
+    {
+      nextState = progList[progIndex];
+      progIndex++;
+    }
+  }
+
+  if(nextState != NULL)
+  {
+    if(micsFuPtr != NULL)
+      startMics = micsFuPtr();
+
+    nextState();
+
+    if(micsFuPtr != NULL)
+    {
+      diffMics = micsFuPtr() - startMics;
+      curStateRuntime = diffMics;
+
+      if(diffMics > maxStateRuntime[0])
+      {
+        maxStateRuntime[0]  = diffMics;
+        maxRuntimeNumber[0] = curStateNumber;
+      }
+      else if(diffMics > maxStateRuntime[1])
+      {
+        if(curStateNumber != maxRuntimeNumber[0])
+        {
+          maxStateRuntime[1]  = diffMics;
+          maxRuntimeNumber[1] = curStateNumber;
+        }
+      }
+      else if(diffMics > maxStateRuntime[2])
+      {
+        if(curStateNumber != maxRuntimeNumber[1])
+        {
+          maxStateRuntime[2]  = diffMics;
+          maxRuntimeNumber[2] = curStateNumber;
+        }
+      }
+      else if(diffMics > maxStateRuntime[3])
+      {
+        if(curStateNumber != maxRuntimeNumber[2])
+        {
+          maxStateRuntime[3]  = diffMics;
+          maxRuntimeNumber[3] = curStateNumber;
+        }
+      }
+    }
+  }
+  else
+    noStateCounter++;
+
+}
+
+// ---------------------------------------------------------------------------
+// service functions/methods for manipulating the state machine
+// ---------------------------------------------------------------------------
+//
+
+// checking a state for staying (not enter new state)
+//
+bool StateMachine::stayHere()
+{
+  if(repeatState > 0)
+  {
+    repeatState--;
+    if(repeatState == 0)
+    {
+      repeatDelay = false;
+    }
+    return(true);
+  }
+
+  firstEnterToggle = true;
+  return(false);
+}
+
+// setting delay before next state
+//
+void StateMachine::setDelay(int delayTime)
+{
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+}
+
+// setting internal speed of the state machine
+// can only be slower than the calling frequency
+//
+void StateMachine::setSpeed(int freq)
+{
+  delaySet      = delay = frequency / freq;
+  repeatDelay   = true;
+}
+
+// setting future state to be called by run
+//
+void StateMachine::enter()
+{
+  if(stayHere()) return;
+
+  pastState = nextState;
+  nextState = futureState;
+}
+
+// setting next state to be called by run
+//
+void StateMachine::enter(StatePtr next)
+{
+  if(stayHere()) return;
+
+  pastState = nextState;
+  nextState = next;
+}
+
+// setting next state with delay (before)
+//
+void StateMachine::enter(StatePtr next, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState = nextState;
+  nextState = next;
+}
+
+// setting next state with repetition
+//
+void StateMachine::enterRep(StatePtr next, int count)
+{
+  if(stayHere()) return;
+
+  repeatState   = count;
+  pastState     = nextState;
+  nextState     = next;
+}
+
+// setting next state with repetition and delay
+//
+void StateMachine::enterRep(StatePtr next, int count, int delayTime)
+{
+  if(stayHere()) return;
+
+  delaySet = delay = (delayTime * frequency) / 1000;
+  repeatDelay = true;
+
+  repeatState   = count;
+  pastState     = nextState;
+  nextState     = next;
+}
+
+// setting state and state after
+//
+void StateMachine::enterVia(StatePtr next, StatePtr then)
+{
+  if(stayHere()) return;
+
+  pastState     = nextState;
+  nextState     = next;
+  futureState   = then;
+}
+
+// calling state
+//
+void StateMachine::call(StatePtr next)
+{
+  if(stayHere()) return;
+
+  pastState     = nextState;
+  futureState   = nextState;
+  nextState     = next;
+}
+
+// setting state and state after with delay
+//
+void StateMachine::enterVia(StatePtr next, StatePtr after, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState     = nextState;
+  nextState     = next;
+  futureState   = after;
+}
+
+// calling state
+//
+void StateMachine::call(StatePtr next, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState     = nextState;
+  futureState   = nextState;
+  nextState     = next;
+}
+
+
+// setting state to state list (program)
+//
+void StateMachine::enterList(StatePtr fin)
+{
+  if(stayHere()) return;
+
+  pastState     = nextState;
+  useProgList   = true;
+  progIndex     = 0;
+  finProgState  = fin;
+}
+
+// setting state to state list (program)and delay
+//
+void StateMachine::enterList(StatePtr fin, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState     = nextState;
+  useProgList   = true;
+  progIndex     = 0;
+  finProgState  = fin;
+}
+
+// setting state to state list (program) at a position
+//
+void StateMachine::enterListAt(StatePtr fin, int index)
+{
+  if(stayHere()) return;
+
+  pastState     = nextState;
+  useProgList   = true;
+  progIndex     = index;
+  finProgState  = fin;
+}
+
+// setting state to state list (program)at a position and delay
+//
+void StateMachine::enterListAt(StatePtr fin, int index, int delayTime)
+{
+  if(stayHere()) return;
+
+  delay = (delayTime * frequency) / 1000;
+  repeatDelay = false;
+
+  pastState     = nextState;
+  useProgList   = true;
+  progIndex     = index;
+  finProgState  = fin;
+}
+
+// detecting the first call of a state
+//
+bool StateMachine::firstEnter()
+{
+  if(!firstEnterToggle)
+    return(false);
+  firstEnterToggle = false;
+  return(true);
+}
+
+// reset first enter detector
+//
+void StateMachine::resetEnter()
+{
+  firstEnterToggle = true;
+}
+
+// counting local cycles
+//
+bool StateMachine::cycle(int cnt)
+{
+  if(callCycleCnt <= 0)
+  {
+    callCycleCnt = cnt;
+    return(true);
+  }
+  callCycleCnt--;
+  return(false);
+}
+//
+bool StateMachine::cycleSec()
+{
+  if(callCycleCnt <= 0)
+  {
+    callCycleCnt = frequency;
+    return(true);
+  }
+  callCycleCnt--;
+  return(false);
+}
+
+// Alternativly returning true and false
+//
+bool StateMachine::toggle()
+{
+  markToggle = !markToggle;
+  return(markToggle);
+}
+
+// Doing only once
+//
+bool StateMachine::oneShot()
+{
+  if(!markOneShot) return(false);
+
+  markOneShot = false;
+  return (true);
+}
+
+void StateMachine::setOneShot()
+{
+  markOneShot = true;
+}
+
+
+// Setable number of returning TRUE
+//
+void  StateMachine::setCondCounter(unsigned int condVal)
+{
+  condCounter = condVal;
+}
+
+bool  StateMachine::condOpen()
+{
+  if(condCounter == 0)
+    return(false);
+  condCounter--;
+  return(true);
+}
+
+// set the time-out value (milliseconds)
+//
+void StateMachine::setTimeOut(int toValue)
+{
+  timeOutCounter = (toValue * frequency) / 1000;
+}
+
+// check the time-out counter
+//
+bool StateMachine::timeOut()
+{
+  if(timeOutCounter > 0)
+    return(false);
+  return(true);
+}
+
+// start time measurement
+//
+void StateMachine::startTimeMeasure()
+{
+  timeMeasureCounter = 0;
+  timeMeasureOn = true;
+}
+
+int StateMachine::getTimeMeasure(bool stop)
+{
+  if(stop)
+    timeMeasureOn = false;
+  return(cycleTime * timeMeasureCounter);
+}
+
+unsigned long StateMachine::getExtTimeMeasure(bool stop)
+{
+  if(stop)
+    timeMeasureOn = false;
+  return(cycleTime * timeMeasureCounter);
+}
+
+// ---------------------------------------------------------------------------
+// Debug and statistic functions/methods
+// ---------------------------------------------------------------------------
+//
+int StateMachine::getDelay()
+{
+  return(delay);
+}
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/StateMachine/StateMachine.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/StateMachine/StateMachine.h
new file mode 100644
index 0000000000000000000000000000000000000000..b5a6ecea89a1a4a81795bf2992e52dd58bb350d2
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/StateMachine/StateMachine.h
@@ -0,0 +1,171 @@
+// ---------------------------------------------------------------------------
+// File:        StateMachine.cpp
+// Editors:     Robert Patzke,
+// Start:       07. February 2018
+// Last change: 07. February 2018
+// URI/URL:     www.mfp-portal.de, homeautomation.x-api.de
+// Licence:     Creative Commons CC-BY-SA
+// ---------------------------------------------------------------------------
+//
+
+#include    "stdlib.h"
+
+
+#ifndef _StateMachine_h
+#define _StateMachine_h
+// ---------------------------------------------------------------------------
+
+#define NrOfSteps       32
+
+#define AUTBREAK(x,y)   { x.enter(y); return; }
+
+// ---------------------------------------------------------------------------
+// class StateMachine
+// ---------------------------------------------------------------------------
+//
+
+class StateMachine
+{
+  // -------------------------------------------------------------------------
+  // class specific data types
+  // -------------------------------------------------------------------------
+  //
+  typedef void (*StatePtr)(void);
+  typedef unsigned long (*MicsecFuPtr)(void);
+
+private:
+  // -------------------------------------------------------------------------
+  // local variables
+  // -------------------------------------------------------------------------
+  //
+  int       delay;              // Setting of delay for next state
+  int       delaySet;           // Setup value for repeated delays
+  bool      repeatDelay;        // If true, every state is delayed (speed set)
+  int       repeatState;        // Controlled repeating a state
+  bool      useVarState;        // breaking the fixed sequence of states by
+                                // using a variable state (in futureState)
+
+  bool        useProgList;            // control progList usage
+  bool        loopProgList;           // looping proglist
+  StatePtr    progList[NrOfSteps];    // dynamically created state run list
+  int         progIndex;              // Program counter (index to next state)
+  int         progEndIdx;             // Index to next empty progList entry
+  StatePtr    finProgState;           // State after using state list
+  MicsecFuPtr micsFuPtr;              // Pointer to micsec function
+
+  bool      firstEnterToggle;       // Is set to true when state changes
+  int       timeOutCounter;         // automatic decremented counter
+
+  bool            timeMeasureOn;          // control of the measurement counter
+  unsigned long   timeMeasureCounter;     // triggered automatic incremented counter
+
+  int       callCycleCnt;           // For cycles inside a state
+  bool      markToggle;             // For bit complements
+  bool      markOneShot;            // for doing only one time
+
+  unsigned int  condCounter;        // Counter for questionable conditions
+
+  // -------------------------------------------------------------------------
+  // local functions/methods
+  // -------------------------------------------------------------------------
+  //
+  bool stayHere();
+
+public:
+  // -------------------------------------------------------------------------
+  // public variables
+  // -------------------------------------------------------------------------
+  //
+  StatePtr  nextState;          // Pointer for indirect calling next state
+  StatePtr  pastState;          // Pointer of the past state
+  StatePtr  futureState;        // Pointer to a future state (see useVarState)
+  StatePtr  doAlways;           // Pointer to a always called state
+  int       cycleTime;          // Cycle time in milliseconds
+  int       frequency;          // Frequency in Hertz (1/s)
+  int       userStatus;         // A number presenting the visible state
+
+  // statistic information
+  //
+  static int   StateMachine_InstCounter;
+
+  unsigned int    noStateCounter;       // Counter for empty running of state machine
+  unsigned int    instNumber;           // Number of this instance
+  unsigned int    runCounter;           // Counter for running states
+  unsigned int    curStateNumber;       // Number of current state
+
+  unsigned long   curStateRuntime;      // run time of latest state
+  unsigned long   maxStateRuntime[4];   // Maximum run time of a state
+  unsigned long   maxRuntimeNumber[4];  // Number of the state of maximum runtime
+
+  // error and debug support
+  //
+  int   userError;
+
+  // -------------------------------------------------------------------------
+  // constructors and initialisations
+  // -------------------------------------------------------------------------
+  //
+  StateMachine();
+  StateMachine(StatePtr firstState, StatePtr anyState, int cycle);
+  void begin(StatePtr firstState, StatePtr anyState, int cycle);
+  StateMachine(StatePtr firstState, StatePtr anyState, int cycle, MicsecFuPtr micsecFu);
+  void begin(StatePtr firstState, StatePtr anyState, int cycle, MicsecFuPtr micsecFu);
+
+  // -------------------------------------------------------------------------
+  // user functions
+  // -------------------------------------------------------------------------
+  //
+  void      run();                                  // has to be cyclic called
+  void      setDelay(int delayTime);                // delay before next state
+  void      setSpeed(int freq);                     // internal run frequency
+
+  void      enter();                                // set next to future state
+  void      enter(StatePtr state);                  // set next state to run
+  void      enter(StatePtr state, int delayTime);   // ... delayed
+
+  void      enterRep(StatePtr state, int count);    // repeat next state
+  void      enterRep(StatePtr state, int count, int delayTime);
+
+  void      call(StatePtr state);                   // set next state and return
+  void      call(StatePtr state, int delayTime);    // ... delayed
+
+  void      enterVia(StatePtr next, StatePtr future);       // next and then
+  void      enterVia(StatePtr next, StatePtr future, int delayTime);
+
+  void      enterList(StatePtr fin);
+  void      enterList(StatePtr fin, int delayTime);
+
+  void      enterListAt(StatePtr fin, int index);
+  void      enterListAt(StatePtr fin, int index, int delayTime);
+
+  bool      firstEnter();       // true only, if the state is first entered
+  void      resetEnter();       // reset first enter mark
+  bool      cycle(int cnt);     // true only, if called <cnt> times
+  bool      cycleSec();         // true only, if a second passed
+  bool      toggle();           // alternating return true and false
+  bool      oneShot();          // only one time true for a call
+  void      setOneShot();       // preparing oneShot to be true
+
+  void      setTimeOut(int toValue);        // Set time-out counter
+  bool      timeOut();                      // Check time-out counter
+  void      startTimeMeasure();             // Start time measurement
+  int       getTimeMeasure(bool stop);      // Time in milliseconds
+
+  unsigned long getExtTimeMeasure(bool stop);     // Time in milliseconds
+
+  void      setCondCounter(unsigned int cntVal);  // Set condition counter
+  bool      condOpen();                           // Ask for open conditions
+
+  // -------------------------------------------------------------------------
+  // debug functions
+  // -------------------------------------------------------------------------
+  //
+  int       getDelay();
+
+};
+
+
+
+
+// ---------------------------------------------------------------------------
+#endif
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/StateMachine/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/StateMachine/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..4dbee447df0f4ef48684a8d78288826ff419108f
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/StateMachine/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "StateMachine",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfBuf.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfBuf.h
new file mode 100644
index 0000000000000000000000000000000000000000..c2f41d77dacb2618fee37685820740222e70b8b3
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfBuf.h
@@ -0,0 +1,48 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfBuf.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   22. November 2021
+//
+// Eine Schnittstelle zu Puffern (speziell Ringpuffer für Kommunikation)
+//
+
+#ifndef IntrfBuf_h
+#define IntrfBuf_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+
+
+class IntrfBuf
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  virtual bool  getByteSnd(byte *dest);   // Byte aus Puffer zum Senden holen
+                                          // Rückgabe FALSE: Puffer leer
+
+  virtual void  putByteRec(byte b);       // Byte vom Empfang an Puffer geben
+
+  virtual int   putSeq(byte *msg, int n); // Bytefolge an Puffer übergeben
+
+};
+
+// ----------------------------------------------------------------------------
+#endif  // IntrfBuf_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfGpio.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfGpio.h
new file mode 100644
index 0000000000000000000000000000000000000000..d37fdf6765d077ac1bc20944080dc257f55e0a8a
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfGpio.h
@@ -0,0 +1,122 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfGpio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   04. April 2022
+//
+// Eine Schnittstelle zu den unterschiedlichen Ports in Mikrocontrollern
+//
+
+#ifndef IntrfGpio_h
+#define IntrfGpio_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+
+typedef enum _ifPortNumber
+{
+  ifPort0,
+  ifPort1,
+  ifPort2,
+  ifPort3,
+  ifPort4,
+  ifPort5,
+  ifPort6,
+  ifPort7,
+  ifPort8,
+  ifPort9
+} ifPortNumber;
+
+typedef enum
+{
+  GEnoError,
+  GEcdictPar
+} GpioError;
+
+typedef struct _GpioMask
+{
+  dword       port;
+  dword       pins;
+} GpioMask, *GpioMaskPtr;
+
+typedef struct _GpioExtMask
+{
+  dword         port;
+  dword         pins;
+  _GpioExtMask  *next;
+} GpioExtMask, *GpioExtMaskPtr;
+
+typedef struct _GpioRef
+{
+  dword     *ioPtr;
+  dword     pins;
+} GpioRef, *GpioRefPtr;
+
+typedef struct _GpioExtRef
+{
+  dword       *ioPtr;
+  dword       pins;
+  _GpioExtRef *next;
+} GpioExtRef, *GpioExtRefPtr;
+
+typedef struct _GpioExtVal
+{
+  dword       value;
+  _GpioExtVal *next;
+} GpioExtVal, *GpioExtValPtr;
+
+// Spezifikation der Schnittstellentreiber
+//
+#define IfDrvInput          0x0000
+#define IfDrvOutput         0x0001
+#define IfDrvStrongHigh     0x0002
+#define IfDrvStrongLow      0x0004
+#define IfDrvOpenDrain      0x0008
+#define IfDrvOpenSource     0x0010
+#define IfDrvPullUp         0x0020
+#define IfDrvPullDown       0x0040
+#define IfDrvPullStrong     0x0080
+
+typedef enum
+{
+  ArdD2D5,
+  ArdA0A3,
+  ArdA4A5,
+  ArdA0A5,
+  ArdA4A7,
+  ArdA0A7
+} ArdMask;
+
+class IntrfGpio
+{
+public:
+
+  //virtual ~IntrfGpio();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual GpioError config(int nr, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  virtual GpioError config(int nrFrom, int nrTo, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  virtual GpioError config(GpioExtMask mask, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  virtual GpioError configArd(ArdMask ardMask, unsigned int cnfBits);
+
+  // --------------------------------------------------------------------------
+  // Anwendungsfunktionen
+  // --------------------------------------------------------------------------
+  //
+  virtual void      read(GpioExtRefPtr refPtr, GpioExtValPtr valPtr);
+  virtual dword     readArd(ArdMask ardMask);
+
+  virtual void      write(GpioExtRefPtr refPtr, GpioExtValPtr valPtr);
+  virtual void      writeArd(ArdMask ardMask, dword value);
+  virtual void      set(GpioExtRefPtr refPtr);
+  virtual void      clr(GpioExtRefPtr refPtr);
+};
+
+// ----------------------------------------------------------------------------
+#endif //IntrfGpio_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfRadio.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfRadio.h
new file mode 100644
index 0000000000000000000000000000000000000000..470277ab4f365581507365d1f412a47683463662
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfRadio.h
@@ -0,0 +1,154 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfRadio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   9. Mai 2021
+//
+// Eine Schnittstelle zu den unterschiedlichen Transceivern in Mikrocontrollern
+// oder Boards mit Mikrocontrollern und Radio-Transceivern
+//
+
+#ifndef IntrfRadio_h
+#define IntrfRadio_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+#include "bleSpec.h"
+
+typedef struct _TxState
+{
+  unsigned int  prgLoopPrep;
+  unsigned int  evtLoopRampUp;
+  unsigned int  evtLoopTrans;
+  byte  *       txBufferPtr;
+} TxState, *TxStatePtr;
+
+typedef struct  _Channel
+{
+  int   idx;
+  int   freq;
+} Channel, *ChannelPtr;
+
+// Zustand des Datenempfangs (Bit)
+//
+#define RECSTAT_ADDRESS   0x0001
+#define RECSTAT_PAYLOAD   0x0002
+#define RECSTAT_END       0x0004
+#define RECSTAT_DISABLED  0x0008
+#define RECSTAT_CRCOK     0x0010
+
+// Modi für das Senden von Telegrammen
+//
+typedef enum _TxMode
+{
+  txmBase,      // Einzelne Sendung, Endezustand DISABLED
+  txmRepStart,  // Wiederholte Sendung Start, Endezustand END
+  txmRepCont,   // Wiederholte Sendung Fortsetzung, Endezustand END
+  txmRepEnd,    // Wiederholte Sendung Ende, Endezustand DISABLED
+  txmReadPrep,  // Einzelne Sendung mit Empfangsvorbereitung, Endezustand READY
+  txmRead,      // Einzelne Sendung und Empfang, Endezustand END
+  txmPoll,      // Einzelne Sendung und Empfang, Endezustand DISABLED
+  txmReadS,     // Einzelne sendung und Empfang mit Daten, Endezustand END
+  txmRespE,     // Empfang für spezifische Antwort (leeres Polling)
+  txmResp       // Empfang für spezifische Antwort (Datenübertragung)
+} TxMode;
+//
+#define NrOfTxModes   10
+
+// Protokollspezifische Adresseninhalte und Festlegungen
+//
+#define PollPduSize   8
+#define PollAdrSize   6
+
+// len = PduMem[1]
+#define BLE_LEN       pduMem[1]
+// Adr[1] = PduMem[3]
+#define BLE_ADR1      pduMem[3]
+
+#define SOAAP_NAK     0x40
+#define SOAAP_EADR    0x80
+
+// Modeabhängige Statistikdaten
+//
+typedef struct _TxStatistics
+{
+  TxMode      mode;
+  dword       interrupts;
+  dword       recs;
+  dword       sendings;
+  dword       aliens;
+  dword       wrongs;
+  dword       pollAcks;
+  dword       pollNaks;
+  dword       crcErrors;
+  dword       intErrors;
+  byte        memDumpRec[16];
+  byte        memDumpSnd[16];
+} TxStatistics, *TxStatisticsPtr;
+
+class IntrfRadio
+{
+public:
+  // Kanalfrequenzen (Offsets zur Basisfrequenz) und Whitening-Preset
+  // Die ersten 3 Kanäle sind Bewerbungskanäle.
+  // Daran anschließend sind die Kanäle grob nach Frequenz einsortiert.
+  // Diese Liste kann zur Laufzeit an Störungen angepasst werden und wird aufsteigend angewendet
+  //
+  Channel channelList[40] =
+  {
+      {37, 2} , {38,26} , {39,80} , { 1, 6} , { 3,10} , { 5,14} , { 7,18} , { 9,22} ,
+      {12,30} , {14,34} , {16,38} , {18,42} , {20,46} , {22,50} , {24,54} , {26,58} ,
+      {28,62} , {30,66} , {32,70} , {34,74} , {35,76} , { 2, 8} , { 4,12} , { 6,16} ,
+      { 8,20} , {33,72} , {31,68} , {13,32} , {15,36} , {17,40} , {19,44} , {21,48} ,
+      {23,52} , {25,56} , {27,60} , {29,64} , {11,28} , {10,24} , { 0, 4} , {36,78}
+  };
+
+  //virtual ~IntrfRadio();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual void  begin();
+  virtual void  setAccessAddress(dword addr);
+  virtual void  setPacketParms(blePduType type);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  virtual void  setChannel(int chnr);         // Schalten physikalischer Kanal
+  virtual int   sendSync(bcPduPtr inPduPtr, TxStatePtr refState);
+
+  virtual void  send(bcPduPtr inPduPtr, TxMode txMode);
+  virtual void  send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, bool newValues);
+  // Senden (und/oder Empfang) eines Telegramms in einem festgelegten Modus
+
+  virtual void  disable(TxMode txMode);       // Funk AUS für Betriebswechsel
+  virtual bool  disabled(TxMode txMode);      // Abfrage, ob ausgeschaltet
+  virtual void  cont(TxMode txMode);          // aktuellen Vorgang fortsetzen
+  virtual bool  fin(TxMode txMode, bool *err);  // Abfrage ob aktueller Vorgang beendet
+// virtual int   getRecData(bcPduPtr data, TxMode txMode, int max); // Lennard: Deaktiviert
+
+  virtual int   startRec();                   // Datenempfang starten
+  virtual int   contRec();                    // Datenempfang fortsetzen
+  virtual int   endRec();                     // Datenempfang beenden
+  virtual int   checkRec();                   // Zustand Datenempfang feststellen
+  virtual int   getRecData(bcPduPtr data, int max);  // Empfangene Daten lesen
+
+  virtual void  setPower(int DBm);            // Leistung des Senders in DBm
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  virtual int   getStatistics(TxStatisticsPtr dest);
+  virtual int   getState();                   // Chip-abhängiger Funk-Status
+
+};
+
+// ----------------------------------------------------------------------------
+#endif  // IntrfRadio_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfSerial.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfSerial.h
new file mode 100644
index 0000000000000000000000000000000000000000..909a810a3282ef0e1ee36e79286bd5c4df0bb929
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfSerial.h
@@ -0,0 +1,101 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfSerial.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   17. November 2021
+//
+// Eine Schnittstelle zu den seriellen Schnittstellen in Mikrocontrollern
+// oder Boards mit Mikrocontrollern und seriellen schnittstellen
+//
+
+#ifndef IntrfSerial_h
+#define IntrfSerial_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+#include "IntrfBuf.h"
+
+typedef enum _SerSpeed
+{
+  Baud1200,
+  Baud2400,
+  Baud4800,
+  Baud9600,
+  Baud14400,
+  Baud19200,
+  Baud28800,
+  Baud31250,
+  Baud38400,
+  Baud56000,
+  Baud57600,
+  Baud76800,
+  Baud115200,
+  Baud230400,
+  Baud250000,
+  Baud460800,
+  Baud921600,
+  Baud1Meg
+} SerSpeed;
+
+typedef enum _SerType
+{
+  stStd,      // Typischer Ausgang ca. 2 mA
+  stPow,      // Starker Ausgang ca. 10 mA
+  stCur       // Open Collector/Drain ca. 10 mA Stromschleife
+} SerType;
+
+typedef struct _SerParams
+{
+  int         inst;           // Nummer (Index) der Ser-Instanz
+  int         txdPort;        // Nummer (Index) des Port fuer TX
+  int         txdPin;         // Nummer (Index) des Pin fuer TX
+  int         rxdPort;        // Nummer (Index) des Port fuer RX
+  int         rxdPin;         // Nummer (Index) des Pin fuer RX
+  SerSpeed    speed;          // Bitrate (Baud)
+  SerType     type;           // Ausgang
+} SerParams, *SerParamsPtr;
+
+typedef enum _SerError
+{
+  SEnoError
+} SerError;
+
+
+class IntrfSerial
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual void  begin(SerParamsPtr serParPtr, IntrfBuf * bufferIf);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  virtual void resuSend();    // Fortsetzen des Interrupt-Sendebetriebs
+  virtual void startSend();   // Starten des Sendebetriebs
+  virtual void stopSend();    // Anhalten des Sendebetriebs
+
+  virtual void startRec();    // Starten des Empfangsbetriebs
+  virtual void stopRec();     // Anhalten des Empfangsbetriebs
+
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  virtual bool condSend(byte c);  // Bedingtes Senden eines Zeichens
+
+  virtual int   getLastError();   // Letzten Fehler lesen (Bits)
+  virtual int   getAnyError();    // Alle vorgekommenen Fehlerbits
+  virtual dword getErrCount();    // Anzahl der Fehler lesen
+
+};
+
+// ----------------------------------------------------------------------------
+#endif  // IntrfRadio_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfTimer.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfTimer.h
new file mode 100644
index 0000000000000000000000000000000000000000..2777f5ba7b80b1116baa9030c452037dc4507952
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfTimer.h
@@ -0,0 +1,55 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfTimer.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   29. Juni 2021
+//
+// Eine Schnittstelle zu den unterschiedlichen Timern in Mikrocontrollern
+//
+
+#ifndef IntrfTimer_h
+#define IntrfTimer_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+
+typedef enum _ifTimerNumber
+{
+  ifTimer0,
+  ifTimer1,
+  ifTimer2,
+  ifTimer3,
+  ifTimer4,
+  ifTimer5,
+  ifTimer6,
+  ifTimer7,
+  ifTimer8,
+  ifTimer9
+} ifTimerNumber;
+
+class IntrfTimer
+{
+public:
+
+  //virtual ~IntrfTimer();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual void  setMilli(ifTimerNumber timNr, int milliSec, int repeat);
+  //virtual void  setMilli(ifTimerNumber timNr, int milliSec, int repeat, dword ISR);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  virtual bool  milli();        // Abfrage des Timer, <true> wenn abgelaufen
+
+};
+
+// ----------------------------------------------------------------------------
+#endif //IntrfTimer_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfTw.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfTw.h
new file mode 100644
index 0000000000000000000000000000000000000000..f0d97b622e98f8f48ee8f066912caf1b4723bc89
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/IntrfTw.h
@@ -0,0 +1,125 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   IntrfTw.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   3. Juni 2021
+//
+// Eine Schnittstelle zu den unterschiedlichen I2C Schnittstellen
+// oder Boards mit geeigneten Mikrocontrollern
+//
+
+#ifndef IntrfTw_h
+#define IntrfTw_h
+// ----------------------------------------------------------------------------
+
+#include "arduinoDefs.h"
+
+typedef enum _TwiDevType
+{
+  TwiMaster,
+  TwiSlave
+} TwiDevType;
+
+typedef enum _TwiSpeed
+{
+  Twi100k,      // Standard, sollte unterstützt werden
+  Twi250k,
+  Twi400k       // Schnell, sollte unterstützt werden
+} TwiSpeed;
+
+typedef struct _TwiParams
+{
+  int         inst;           // Nummer (Index) der Twi-Instanz
+  TwiDevType  type;           // Auswahl Master/Slave
+  int         clkPort;        // Nummer (Index) des Port fuer Takt
+  int         clkPin;         // Nummer (Index) des Pin fuer Takt
+  int         dataPort;       // Nummer (Index) des Port fuer Daten
+  int         dataPin;        // Nummer (Index) des Pin fuer Daten
+  TwiSpeed    speed;
+} TwiParams, *TwiParamsPtr;
+
+typedef enum _TwiError
+{
+  TEnoError
+} TwiError;
+
+typedef enum _TwiStatus
+{
+  TwStUnborn,
+  TwStRdReq,
+  TwStWrReq,
+  TwStSent,
+  TwStRecvd,
+  TwStFin     = 0x0080,
+  TwStError   = 0x0100,
+  TwStOverrun = 0x0101,
+  TwStAdrNak  = 0x0102,
+  TwStDataNak = 0x0104
+} TwiStatus;
+
+typedef struct _TwiByte
+{
+  TwiStatus   twiStatus;
+  byte        value;
+} TwiByte, *TwiBytePtr;
+
+typedef struct _TwiWord
+{
+  TwiStatus   twiStatus;
+  word        value;
+} TwiWord, *TwiWordPtr;
+
+typedef struct _TwiByteSeq
+{
+  TwiStatus   twiStatus;
+  int         len;
+  byte        *valueRef;
+} TwiByteSeq, *TwiByteSeqPtr;
+
+
+class IntrfTw
+{
+public:
+  // --------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // --------------------------------------------------------------------------
+  //
+  virtual TwiError begin(TwiParamsPtr inParPtr);
+
+  //virtual ~IntrfTw();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  virtual void getParams(TwiParamsPtr parPtr);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Datenaustausch
+  // --------------------------------------------------------------------------
+  //
+  // asynchrone Kommunikation, Zustand in TwiByte.twiStatus
+  //
+  virtual TwiError sendByte(int adr, TwiBytePtr refByte);
+  virtual TwiError sendByteReg(int adr, int reg, TwiBytePtr refByte);
+  virtual TwiError recByteReg(int adr, int reg, TwiBytePtr refByte);
+  virtual TwiError recByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq);
+
+  // synchrone Kommunikation
+  //
+  virtual TwiStatus writeByteReg(int adr, int reg, byte value);
+  virtual int       readByteReg(int adr, int reg);
+  virtual TwiStatus readByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq);
+
+};
+
+// ----------------------------------------------------------------------------
+#endif  // IntrfTw_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/SoaapBleMaster.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/SoaapBleMaster.h
new file mode 100644
index 0000000000000000000000000000000000000000..98bd22eb99c0839cf9f5ad554dd116b21c0afd81
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/SoaapBleMaster.h
@@ -0,0 +1,63 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleMaster.h
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                        P o l l i n g - M a s t e r
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. November 2021
+// Letzte Bearbeitung: 15. März 2022
+//
+
+#ifndef SoaapBleMaster_h
+#define SoaapBleMaster_h
+
+// Vordefinitionen, Festlegungen zur Kompilierung
+//
+#define DebugTerminal
+// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden
+// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist
+
+//#define TEST001
+// Ausgaben an serielle schnittstelle zur Prüfung der ap-Zustandsmaschine
+
+#include  "LoopCheck.h"
+#include  "StateMachine.h"
+#include  "nRF52840Radio.h"
+#include  "BlePoll.h"
+#include  "ComRingBuf.h"
+#include  "nRF52840Ser.h"
+#include  "SoaapMsg.h"
+#include  "Monitor.h"
+
+// ----------------------------------------------------------------------------
+// Vorwärtsreferenzen
+// ----------------------------------------------------------------------------
+//
+void ctrlIdle();
+void ctrlInit();
+void sendCtrl();
+void checkCtrl();
+
+void apInit();
+void apWaitDE();
+void apWaitMeas();
+void apProcMeas();
+
+
+#ifdef DebugTerminal
+// ----------------------
+void smInit() ;
+void smCheckJobs() ;
+void smDebDword() ;
+void smCtrlPolling() ;
+void smWaitPolling() ;
+void smReadPollValues() ;
+void smCheckSer();
+// ----------------------
+#endif
+
+#endif /* SoaapBleMaster_h */
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/SoaapBleSlave.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/SoaapBleSlave.h
new file mode 100644
index 0000000000000000000000000000000000000000..f3ae7f7500126e35f19524b4188a3044d43dfaf4
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/SoaapBleSlave.h
@@ -0,0 +1,43 @@
+#ifndef SoaapBleSlave_h
+#define SoaapBleSlave_h
+
+#include  "LoopCheck.h"
+#include  "StateMachine.h"
+#include  "nRF52840Radio.h"
+#include  "BlePoll.h"
+#include  "ComRingBuf.h"
+#include  "nRF52840Ser.h"
+#include  "SoaapMsg.h"
+#include  "Monitor.h"
+#include "nRF52840Twi.h"
+#include "SensorLSM9DS1.h"
+#include "nRF52840Gpio.h"
+
+//#define SlaveACM1
+bool sendData(PlpType plpType, byte *dest);
+bool getValues(PlpType plpType, byte *dest);
+void smInit();
+void smCheckJobs();
+void smCheckSens();
+
+void smDebDword();
+void smCtrlPolling();
+void smWaitPolling();
+void smSensReset1();
+void smSensReset2();
+
+void smSensGetValues1();
+void smSensGetValues2();
+void smSensGetValues3();
+void smSensGetValues4();
+void smSensGetValues5();
+void smSensGetValues6();
+void smSensGetValues7();
+
+void smSensGetSoaapValues();
+void smSensDebugValues();
+
+void smSensGetErrors();
+void smSensGetTimeOuts();
+void smSensGetRunCounts();
+#endif
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/arduinoDefs.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/arduinoDefs.h
new file mode 100644
index 0000000000000000000000000000000000000000..4830c5d860683336800903c177b10c53fcb73736
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/arduinoDefs.h
@@ -0,0 +1,53 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Definitions instead Arduino
+// Datei:   arduinoDefs.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+// These definitions shall encapsulate the Arduino environment
+// The file should be included instead of Arduino.h for arbitrary environments
+//
+
+#ifndef _arduinoDefs_h
+#define _arduinoDefs_h
+
+// ---------------------------------------------------------------------------
+// Simple type definitions and settings
+// ---------------------------------------------------------------------------
+//
+#undef  byte
+#undef  word
+#undef  dword
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned long
+
+#ifdef smnLinGcc64
+
+#undef  byte
+#undef  word
+#undef  dword
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned int
+
+#endif
+
+// ---------------------------------------------------------------------------
+// Complex type definitions
+// ---------------------------------------------------------------------------
+// The following types are more complex definitions with Arduino.
+// But here simple types are used if possible, because we only care for the
+// environment that is needed by Social Manufacturing Network
+//
+
+#ifndef IPAddress
+  #define IPAddress   byte *
+#endif
+
+
+#endif  // _arduinoDefs_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/bleSpec.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/bleSpec.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4993a39fee05fa5162fc888acf0804e5fc59254
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/bleSpec.h
@@ -0,0 +1,86 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   bleSpec.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   8. Mai 2021
+//
+// Der Inhalt dieser Datei ist der Blootooth Spezifikation 5.2 entnommen
+// bzw. daran angelehnt.
+// Insbesondere dem Teil 6, Low Energy Controller
+//
+
+#ifndef bleSpec_h
+#define bleSpec_h
+// ----------------------------------------------------------------------------
+
+#ifndef octet
+typedef unsigned char octet;
+#endif
+
+#define VersionBTS  52
+#define TypeBTS     BLE
+
+// ----------------------------------------------------------------------------
+// Festlegungen für die Bewerbungskanäle (Advertizing Physical Channels)
+// ----------------------------------------------------------------------------
+
+// Basisfrequenz in MHz
+#define BaseFrequency   2400
+
+// Zugriffsadresse (Access Address)
+#define AdvAccAddr  0x8E89BED6
+
+// CRC-Polynom
+#define PolynomCRC  0x0100065B
+
+// CRC-Startwert
+#define AdvStartCRC 0x555555
+
+// Geräteadresse
+typedef octet  BD_ADR[6];
+
+// Telegrammtypen (PDU Types)
+#define ADV_IND           0x0
+#define ADV_DIRECT_IND    0x1
+#define ADV_NONCONN_IND   0x2
+#define SCAN_REQ          0x3
+#define SCAN_RSP          0x4
+#define CONNECT_IND       0x5
+#define ADV_SCAN_IND      0x6
+
+// Kennzeichnung Art der Geräteadresse (Device Address Mark, TxAdd = 1, random)
+#define DevAdrType  0x2
+
+// Telegrammkopf ohne Längenbyte
+#define HeadS0B     ((ADV_NONCONN_IND << 4) | DevAdrType)
+#define HeadS0BS    ((ADV_SCAN_IND << 4) | DevAdrType)
+
+// Datenstruktur für das zu sendende Telegramm
+// bei der Bewerbung (Advertising)
+//
+typedef struct _bcPdu         // Beacon - PDU
+{
+  byte  head;       // Header = PDU-Typ und Adresskennung (S0 bei nRF52840)
+  byte  len;        // Länge des Telegramms inkl. Adresse (LENGTH bei nRF52840)
+  byte  adr0;       // niedrigstwertiges Adressbyte (S1 bei nRF52840)
+  byte  adr1;       //
+  byte  adr2;       //      Das ist die Geräteadresse, die hier wahlfrei ist
+  byte  adr3;       //      Sie wird zur Identifikation des Gerätes verwendet
+  byte  adr4;       //
+  byte  adr5;       // höchstwertiges Addressbyte
+  byte  data[31];   // Nutzdaten (maximale Anzahl nach BLE-Spez.)
+} bcPdu, *bcPduPtr;
+
+// Telegrammtypen
+//
+typedef enum  _blePduType
+{
+  bptAdv,           // Standard-Bewerbungstelegramm
+  bptAux
+} blePduType;
+
+// ----------------------------------------------------------------------------
+#endif  // bleSpec_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/environment.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/environment.h
new file mode 100644
index 0000000000000000000000000000000000000000..311c3331bd39a97884ba12b85375b08a418813d0
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/environment.h
@@ -0,0 +1,126 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   environment.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef _environment_h
+#define _environment_h
+
+#ifdef  smnDEFBYBUILD
+
+// Alternative Festlegungen durch Settings in der Build-Umgebung der IDE
+// Das erspart die Verwaltung mehrerer/unterschiedlicher environment.h Dateien
+// in den Projekten
+//
+  #ifdef smnUBUNTU_ECLIPSE
+  // Meine Entwicklungs- und Testumgebung auf dem Notebook unter UBUNTU
+  // für Sketche, die auf dem PC laufen (u.a. zum Debuggen)
+
+    #define smnSimLinux
+    #define smnNotebook
+    #define smnLINUX
+    #define smnDebugLinuxConsole
+
+  #endif
+
+  #ifdef smnWIN32_VS
+  // Meine Entwicklungs- und Testumgebung auf dem Notebook unter Windows
+  // für Sketche, die auf dem PC laufen (u.a. zum Debuggen)
+
+    #define smnSimWindows
+    #define smnNotebook
+    #define smnWIN32
+    #define smnDebugWindowsConsole
+
+  #endif
+
+  #ifdef smnSLOELIN
+  // Mit Sloeber auf Ubuntu/Linux für Entwicklungen zum ESP32
+  //
+
+    #define smnDebugArduino
+    #define smnSloeber
+    #define smnESP32_DEV
+    #define smnESP32
+    #define smnSerial Serial
+  #endif
+
+  #ifdef smnSLOEDUE
+  // Mit Sloeber auf Ubuntu/Linux für Entwicklungen zum Arduino Due
+  //
+
+    #define smnDebugArduino
+    #define smnSloeber
+    #define smnArduinoDUE
+    #define smnArduinoShieldEth
+    #define smnSAM3X
+    #define smnSerial Serial
+  #endif
+
+  #ifdef smnNANOBLE33
+    #define smnDebugArduino
+    #define smnSloeber
+    #define smnArduinoNanoBLE33
+    #define smnNRF52840
+    #define smnSerial Serial
+  #endif
+
+  #ifdef smnSLOESAMD21
+    #define smnDebugArduino
+    #define smnSloeber
+    #define smnArduinoZeroSamD21
+    #define smnSAMD21G18
+    #define smnSD21MINI
+    #define smnSerial SerialUSB
+  #endif
+
+#else
+
+// Die Definitionen werden hier in den meisten Fällen grundsetzlich ausgewertet,
+// nicht über spezifische Werte.
+// Die Abfrage geschieht also mit #ifdef
+// Daraus folgt hier eine Liste der Möglichkeiten, die beliebig erweitert werden kann.
+// Die Auswahl erfolgt schließlich über aus- bzw. einkommentieren.
+//
+
+// Übergeordnete Festlegungen
+// ---------------------------------------------------------------------------
+//
+#define smnDebugArduino
+//#define smnDebugLinuxConsole
+//
+
+// IDE, Editor, etc.
+// ---------------------------------------------------------------------------
+//
+//#define smnSimLinux
+#define smnSloeber
+//#define smnArduinoIDE
+//#define smnPlatformIO
+
+// Hardware, Boards, etc.
+// ---------------------------------------------------------------------------
+//
+//#define smnNotebook
+//#define smnESP32_DEV
+#define smnNodeMCU10
+//#define smnArduinoDUE
+//#define smnArduinoShieldEth
+//#define smnArduinoShieldWiFi
+#define smnSerial Serial
+
+// Prozessoren, Microcontroller, Betriebssysteme, etc.
+// ---------------------------------------------------------------------------
+//
+//#define smnLINUX
+//#define smnESP32
+#define smnESP8266
+//#define smnSAM3X
+
+#endif  // smnDEFBYBUILD
+
+#endif  // _environment_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..9e3641f6fb0e38c5e74b3c3cee96651efbb2fdaa
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "environment",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/socManNetUser.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/socManNetUser.h
new file mode 100644
index 0000000000000000000000000000000000000000..4809a3b98de3da0b84f1f25ba7cda8af91bb2672
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/environment/socManNetUser.h
@@ -0,0 +1,315 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Broadcast Socket Interface
+// Datei:   socManNetUser.h
+// Editor:  Igor Farber, Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef _socManNetUser_h
+#define _socManNetUser_h
+
+#define smnMULTIBOARDS
+
+#define smnBOARD001
+//#define smnBOARD002
+//#define smnBOARD003
+//#define smnBOARD004
+//#define smnBOARD005
+//#define smnBOARD006
+
+
+
+#ifndef smnMyNet
+// ***************************************************************************
+// define smnMyNet in project properties (Arduino) with -DsmnMyNet
+// to use your own network definition file included at the end of this file
+
+
+//---------------------------------------------------------------------------//
+//-------------------------------------------------------------------------
+// MAC-Adresse des Ethernet-Shield
+//-------------------------------------------------------------------------
+#ifdef  smnMULTIBOARDS
+
+  #ifdef  smnBOARD001
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x1b
+    #define LOCAL_MAC_ADR_B5 0x84
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-1b-84"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD002
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x63
+    #define LOCAL_MAC_ADR_B5 0xb0
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-63-b0"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD003
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x5b
+    #define LOCAL_MAC_ADR_B5 0xe1
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-5b-e1"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD004
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x5b
+    #define LOCAL_MAC_ADR_B5 0x8f
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-62-d0"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD005
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x62
+    #define LOCAL_MAC_ADR_B5 0xd0
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-62-d0"
+    // MAC-Adresse als String
+  #endif
+
+  #ifdef  smnBOARD006
+    #define LOCAL_MAC_ADR_B0 0x90
+    #define LOCAL_MAC_ADR_B1 0xa2
+    #define LOCAL_MAC_ADR_B2 0xda
+    #define LOCAL_MAC_ADR_B3 0x0f
+    #define LOCAL_MAC_ADR_B4 0x62
+    #define LOCAL_MAC_ADR_B5 0xd0
+    // MAC-Adresse
+
+    #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-62-d0"
+    // MAC-Adresse als String
+  #endif
+
+#else
+  #define LOCAL_MAC_ADR_B0 0x90
+  #define LOCAL_MAC_ADR_B1 0xa2
+  #define LOCAL_MAC_ADR_B2 0xda
+  #define LOCAL_MAC_ADR_B3 0x0f
+  #define LOCAL_MAC_ADR_B4 0x62
+  #define LOCAL_MAC_ADR_B5 0xd0
+  // MAC-Adresse
+
+  #define LOCAL_MAC_ADR_STR (char *) "90-a2-da-0f-62-d0"
+  // MAC-Adresse als String
+#endif
+
+#define LOCAL_PORT      4100
+// Portnummer lokal
+
+#define BROADCAST_PORT  4100
+// Portnummer Rundruf
+
+#define CONFIG_PORT     4001
+
+//-------------------------------------------------------------------------
+// Sub-Netz-Maske
+//-------------------------------------------------------------------------
+#define SUB_NET_MASK_B0 255
+#define SUB_NET_MASK_B1 255
+#define SUB_NET_MASK_B2 255
+#define SUB_NET_MASK_B3 0
+
+//----------------------------------------------------------------------------
+// IP-Adresse, ist auf das verwendete Netzwerk anzupassen (kein DHCP)
+//----------------------------------------------------------------------------
+
+// Das Netzwerk an sich
+#define LOCAL_IP_B0 192
+#define LOCAL_IP_B1 168
+#define LOCAL_IP_B2 99
+
+#define BROADCAST_IP_B0 192
+#define BROADCAST_IP_B1 168
+#define BROADCAST_IP_B2 99
+#define BROADCAST_IP_B3 255
+
+#ifdef smnMULTIBOARDS
+
+  #ifdef smnBOARD001
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 201
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.201"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD002
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 202
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.202"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD003
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 203
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.203"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD004
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 204
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.204"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD005
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 205
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.205"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+  #ifdef smnBOARD006
+
+    // IP-Lokal
+    // ----------------------------------------------
+    //
+    #define LOCAL_IP_B3 206
+    #define LOCAL_IP_ADR_STR (char *) "192.168.99.205"
+
+    // IP-Broadcast
+    // ----------------------------------------------
+    //
+    #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+  #endif
+
+
+#else
+
+  // IP-Lokal
+  // ----------------------------------------------
+  //
+  #define LOCAL_IP_B3 205
+  #define LOCAL_IP_ADR_STR (char *) "192.168.99.205"
+
+  // IP-Broadcast
+  // ----------------------------------------------
+  //
+  #define BROADCAST_IP_B3 255
+  #define BROADCAST_IP_ADR_STR (char *) "192.168.99.255"
+
+#endif
+
+// IP-Gateway
+// ----------------------------------------------
+//
+#define GATEWAY_IP_B0 192
+#define GATEWAY_IP_B1 168
+#define GATEWAY_IP_B2 99
+#define GATEWAY_IP_B3 1
+
+
+/******************************************************************************
+ * Netzwerkname
+ * Passwort
+ */
+#define SMNSSID "MPZ-Labor"    //Netzwerk Name
+#define SMNPASS "MPZMPZMPZ"    //Netzwerk Passwort
+
+// IP-primaryDNS
+// ----------------------------------------------
+//
+#define PRIMDNS_IP_B0   8
+#define PRIMDNS_IP_B1   8
+#define PRIMDNS_IP_B2   8
+#define PRIMDNS_IP_B3   8
+
+// IP-secondaryDNS
+// ----------------------------------------------
+//
+#define SECDNS_IP_B0    8
+#define SECDNS_IP_B1    8
+#define SECDNS_IP_B2    4
+#define SECDNS_IP_B3    4
+
+#else
+// ***************************************************************************
+  #undef _socManNetUser_h
+  #include MyNetFile
+  // Define MyNetFile in Project-Properties with -DMyNetFile=\"xxxxx\"
+  // and xxxxx being your filename.
+  // Define also smnMyNet with -DsmnMyNet to enter this include directive
+
+#endif // smnMyNet
+// ***************************************************************************
+
+//---------------------------------------------------------------------------//
+#endif // _socManNetUser_h
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/main.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dc884bde144955acdd20fe68907119e60539e262
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/main.cpp
@@ -0,0 +1,855 @@
+// ----------------------------------------------------------------------------
+//                              SoaapBleSlave.ino
+// Beispielhafte Anwendung SOAAP / Steuerung optischer und akustischer Ausgaben
+//      Kommunikation über BLE-Funkanäle mit Bewerbungstelegrammen
+//                           P o l l i n g - S l a v e
+// ----------------------------------------------------------------------------
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   1. November 2021
+// Letzte Bearbeitung: 1. November 2021
+//
+#include "Arduino.h"
+
+#include "SoaapBleSlave.h"
+
+#define SlaveADR1
+#define DebugTerminal
+
+#ifdef SlaveADR1
+#define SlaveADR 1
+#define StartMsg "%@TestBleSlave (Adr=1), Version 20220424 "
+#endif
+
+#ifdef SlaveADR4
+#define SlaveADR 4
+#define StartMsg "%@TestBleSlave (Adr=4), Version 20220424 "
+#endif
+
+LoopCheck     lc;
+// Eine statische Instanz der Klasse LoopCheck
+// Darüber wird das Zeitverhalten gesteuert (Software-Timer) und geprüft
+
+#ifdef DebugTerminal
+Monitor       mon(modeEcho | modeNl,0,&lc);
+// Eine statische Instanz (mit Konstruktordaten) der Klasse Monitor
+// Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert
+// Unter Linux werden hier GtkTerm (siehe Internet) und
+// ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt.
+// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeignet,
+// weil damit keine direkte Kommunikation (getipptes Zeichen sofort gesendet)
+// möglich ist.
+// ----- Parameter ------------------------------------------------------------
+// <mode Echo>  Alle eintreffenden Zeichen werden sofort zurückgesendet
+// <mode NL>    Vor der Ausgabe des Prompt (M>) erfolgt CR/LF
+// <0>          Für Speicherzugriffe wird von 32 Bit ARM ausgegangen
+// <&lc>        Für Zeitüberwachungen und entsprechende statisctische Daten
+//              greift die Monitor-Klasse auf die LoopCheck-Klasse zu
+#endif
+
+nRF52840Radio bleCom;
+// Eine statische Instanz der Klasse nRF52840Radio
+// Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und
+// Empfangen von BLE-Beacons angesprochen.
+
+#define bleCycle 250
+BlePoll       blePoll((IntrfRadio *) &bleCom, micros);
+// Eine statische Instanz der Klasse BlePoll
+// Darüber werden das Polling des Masters als auch die Antworten der Slaves
+// gesteuert. Es können Geräte entwickelt werden, die nur Master oder Slave
+// sind und solche mit Doppelfunktion, wenn kein expliziter Master
+// eingesetzt und das Netzwerk über Spontan-Master quasi dezentral
+// betrieben werden soll.
+// ----- Parameter ------------------------------------------------------------
+// <&bleCom>    Die Klasse (vom angenommenen Typ IntrfRadio), die die Daten-
+//              übertragung abwickelt. Hier wird eine Instanz von nRF52840Radio
+//              angebunden. Für andere Hardware kann eine entsprechende Klasse
+//              verwendet werden, die von IntrfRadio abgeleitet wurde.
+// <micros>     Eine Funktion, die die verstrichene Zeit in Mikrosekunden gibt.
+//              Damit werden Zeiten (z.B. Time-Out) berechnet.
+//              Wird hier der Wert NULL übergeben, dann werden die Zeiten aus
+//              dem Aufrufzyklus (bleCycleTime) in Mikrosekunden berechnet,
+//              was hier einer Auflösung von 500 Mikrosekunden entspricht.
+
+#ifdef DebugTerminal
+#define smCycleTime 5
+void smInit();  // Vorwärtsreferenz auf die weiter unten definierte Funktion
+StateMachine  sm(smInit, NULL, smCycleTime);
+// Eine statische Instanz für die Zustandsmaschine, die hier für allgemeine
+// Steuerungen, Überwachungen und zum Debugging verwendet wird
+// ----- Parameter ------------------------------------------------------------
+// <smInit>       Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände
+//                werden in den weiteren Zustandsfunktionen eingesetzt.
+// <NULL>         Hier kann eine weitere Zustandsfunktion angegeben werden,
+//                die dann grundsätzlich vor dem Verzweigen in einen Zustand
+//                aufgerufen wird.
+// <smCycleTime>  Die Zukluszeit (Takt) der Zustandsmaschine in Millisekunden
+#endif
+
+nRF52840Twi twi;
+// Eine statische Instanz der Klasse nRF52840Twi
+// Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und
+// Empfangen von I2C (TWI) Botschaften aufgerufen.
+
+
+#define SensorCycle   500
+SensorLSM9DS1 sens((IntrfTw *) &twi, SensorCycle);
+// Eine statische Instanz der Klasse SensorLSM9DS1 zum Zugriff
+// auf den Sensor LSM9DS1 über den I2C-Bus (TWI)
+// ----- Parameter ------------------------------------------------------------
+// <&twi>   Die Klasse (vom angenommenen Typ IntrfTw), die die Datenüber-
+//          tragung auf I2C abwickelt. Hier wird eine Instanz von nRF52840Twi
+//          angebunden. Für andere Hardware kann eine entsprechende Klasse
+//          verwendet werden, die von IntrfTw abgeleitet wurde.
+//
+// <SensorCycle>  Der Zugriff auf den Sensor erfolgt mit einer Zustands-
+//                maschine, deren Takt über die Periodenzeit SensorCycle
+//                in Mikrosekunden definiert ist. Siehe dazu entsprechenden
+//                Timeraufruf in LOOP.
+
+nRF52840Gpio  gpio;
+// Zugriff auf die Anschlüsse des Board
+
+bool getValues(PlpType plpType, byte *dest);
+// Vorwärtsreferenz für Datenübergabe
+
+bool xchgCtrl(PlpType plpType, byte *dest, byte *src, int sSize);
+// Vorwärtsreferenz für Steuerungsaustausch
+
+void setup()
+{
+  TwiParams   twiPar;       // Parameter für den I2C-Bus
+
+  gpio.configArd(ArdA0A3, IfDrvInput | IfDrvPullUp);
+
+#ifdef DebugTerminal
+  mon.config(6);    // 6 Anzeigekanäle, die von ArduinoMonTerm aufgebaut werden
+
+  for(int i = 0; i < 6; i++)
+  {
+    if(i < 3)
+      mon.config(i+1,'C',16000,-16000,NULL);    // Kanalnummer, Typ, Maxwert, Minwert
+    else
+      mon.config(i+1,'C',4000,-4000,NULL);
+  }
+#endif
+
+  bleCom.begin();           // Initialisierung der Datenübertragung
+  //bleCom.setPower(0x008);   // Maximale Sendeleistung bei nRF52840
+  bleCom.setPower(0x0FC);   // Reduzierte Sendeleistung beim Schreibtisch-Test
+
+  blePoll.begin(BlePoll::ctSLAVE, SlaveADR, BlePoll::atSOAAP, 10000);
+  // Initialisierung des Polling mit folgenden Parametern:
+  // <BlePoll::ctSLAVE>     Es wird ein Slave eingerichtet
+  // <SlaveADR>             Adresse (Nummer) des Slave
+  // <BlePoll::atSOAAP>     Spezielle Anwendung SOAAP
+  // <10000>                INT-Watchdog-Timeout in Mikrosekunden
+
+  blePoll.setCbDataPtr(getValues);
+  blePoll.setCbCtrlPtr(xchgCtrl);
+  // Callbacks für Datenübergabe setzen
+
+  //blePoll.stopSR();
+  // Kein Empfangsbetrieb
+
+  // Spezifische Parameter für den I2C-Bus am Arduino Nano 33 BLE
+  //
+  twiPar.inst     = 0;          // 1. Instanz der I2C
+  twiPar.type     = TwiMaster;  // Auswahl Master/slave
+  twiPar.clkPort  = 0;          // Takt über Port 0 (P0)
+  twiPar.clkPin   = 15;         // Takt an Pin 15 (P0.15)
+  twiPar.dataPort = 0;          // Daten über Port 0 (P0)
+  twiPar.dataPin  = 14;         // Daten an Pin 14 (P0.14)
+  twiPar.speed    = Twi100k;    // Taktfrequenz
+
+  twi.begin(&twiPar); // Initialisierung des I2C-Bus
+
+  sens.begin(FreqAG119, 12, MaxAcc4g, MaxGyro2000dps, FreqM20, 10, MaxMag16G);
+  // Initialisierung der Sensorabfrage mit folgenden Parametern
+  //
+  // <FreqAG119>  Beschleunigungssensoren und Gyroskop mit 119 Hz abgefragt
+  //
+  // <12>         Vor der Wertübergabe wird der Mittelwert über 12 Messungen
+  //              gebildet. Die Messfrequenz beträgt daher ca. 10 Hz.
+  //
+  // <MaxAcc4g>   Der Maximalausschlag der Beschleunigung ist 4g
+  //
+  // <MaxGyro2000dps> Maximalausschlag des Gyro ist 2000 Grad/s
+  //
+  // <FreqM40>    Der Magnetfeldsensor wird mit 20 Hz abgetastet
+  //
+  // <8>          Mittelwertbildung über 10 Messwerte, also 2 Hz
+  //
+  // <MaxMag16G>  Der Maximalwert entspricht 16 Gauss
+
+  sens.syncValuesAG();
+  sens.syncValuesM();
+  // Rücksetzen des Ready-Bit für Messwertübergabe
+}
+
+#ifdef DebugTerminal
+char  runView[4] = {'|','/','-','\\'};
+int   runViewIdx = 0;
+#endif
+
+void loop()
+{
+  lc.begin();
+  // --------------------------------------------------------------------------
+
+#ifdef DebugTerminal
+  // Der Monitor wird ständig aufgerufen und stellt damit eine grundsätzliche
+  // Belastung dar. Das ist für die Entwicklung auch vorgesehen.
+  // Es entsteht dadurch eine Reserve für den produktiven Einsatz.
+  //
+  mon.run();
+#endif
+
+  // Alle 500 Mikrosekunden erfolgt der Aufruf des Ble-Polling
+  //
+  if(lc.timerMicro(lcTimer0, bleCycle, 0))
+    blePoll.run();
+  // ----- Parameter der Software-Timer ---------------------------------------
+  // <lcTimer0>   Id/Nummer des Timer, zur Zeit werden bis 10 Timer unterstützt
+  //              lcTimer0 bis lcTimer9 (einstellbar in LoopCheck.h)
+  // <bleCycleTime>   Ablaufzeit in Einheit des Timer-Typ (Micro/Milli)
+  //                  hier in Mikrosekunden (timerMicro)
+  // <0>          Anzahl der Wiederholungen, 0 = unbegrenzt
+
+  // Alle 500 Mikrosekunden erfolgt der Aufruf der Sensorzustandsmaschine
+  //
+  if(lc.timerMicro(lcTimer1, SensorCycle, 0))
+    sens.run();
+
+#ifdef DebugTerminal
+  // Alle 5 Millisekunden wird die Zustandsmaschine für
+  // betriebliche Abläufe aufgerufen
+  //
+  if(lc.timerMilli(lcTimer2, smCycleTime, 0))
+  {
+    sm.run();
+  }
+
+  // Jede halbe Sekunde erfolgt die Ausgabe der Version
+  //
+  if(lc.timerMilli(lcTimer3, 500, 0))
+  {
+    if(!mon.cFlag[0])
+    {
+      mon.print((char *) StartMsg);
+      mon.cprintcr(runView[runViewIdx]);
+      runViewIdx++;
+      if(runViewIdx > 3) runViewIdx = 0;
+    }
+  }
+#endif
+  // --------------------------------------------------------------------------
+  lc.end();
+}
+
+// ----------------------------------------------------------------------------
+// Übergabe der Daten an die BLE-Kommunikation
+// ----------------------------------------------------------------------------
+//
+RawDataAG   rawDataAG;
+RawDataM    rawDataM;
+
+bool getValues(PlpType plpType, byte *dest)
+{
+  bool  newData;
+  int   si,di;
+
+  memset(rawDataAG.byteArray,0,12);
+
+  newData = sens.getValuesAG(&rawDataAG);
+
+  si = di = 0;
+  if(newData)
+  {
+    switch(plpType)
+    {
+      case plptMeas6:
+        for(si = 0; si < 12; si++)
+          dest[di++] = rawDataAG.byteArray[si];
+        break;
+
+      case plptMeas9Ctrl4:
+        sens.getValuesM(&rawDataM);
+
+        for(si = 0; si < 12; si++)
+          dest[di++] = rawDataAG.byteArray[si];
+        for(si = 0; si < 6; si++)
+          dest[di++] = rawDataM.byteArray[si];
+        break;
+    }
+  }
+  return(newData);
+}
+
+int  procSize;
+byte procData[32];
+byte procPath;
+byte procCnt;
+
+
+bool xchgCtrl(PlpType plpType, byte *dest, byte *src, int sSize)
+{
+  int   si,di;
+  bool  retv;
+
+  si = di = 0;
+  retv = false;
+
+  switch(plpType)
+  {
+    case plptMeas9Ctrl4:
+      for(si = 0; si < sSize; si++)
+        procData[si] = src[si];
+        procSize = sSize;
+        dest[di++] = procPath;
+        dest[di++] = procCnt;
+        dest[di++] = (byte) (gpio.readArd(ArdA0A3) & 0x0F);
+        dest[di++] = 0xAB;
+      
+      retv = true;
+      break;
+  }
+
+  return(retv);
+}
+
+#ifdef DebugTerminal
+// ****************************************************************************
+// Z u s t a n d s m a s c h i n e
+// ****************************************************************************
+//
+
+dword       debDword;
+byte        tmpByteArray[256];
+CalValueAG  calData;
+CalValue    calValue;
+
+
+void smInit()
+{
+  sm.enter(smCheckJobs);
+}
+
+// ----------------------------------------------------------------------------
+// Abfrage der Monitorschalter
+// ----------------------------------------------------------------------------
+//
+
+void smCheckJobs()
+{
+  if(mon.cFlag[1] && !mon.busy)
+    sm.enter(smDebDword);
+  else if(mon.cFlag[2] && !mon.busy)
+    sm.enter(smCtrlPolling);
+  else if(mon.cFlag[3] && !mon.busy)
+    sm.enter(smCheckSens);
+  /*
+  else if(mon.cFlag[4] && !mon.busy)
+    sm.enter(smCheckSens);
+  */
+}
+
+
+// ----------------------------------------------------------------------------
+// Debug-Informationen
+// ----------------------------------------------------------------------------
+//
+
+void smDebDword()
+{
+  int idx;
+
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "DebDword[");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  if(mon.lastKeyIn >= 0x30 && mon.lastKeyIn <= 0x39)
+  {
+    idx = mon.lastKeyIn & 0x0F;
+    mon.print(idx);
+    mon.print((char *) "]=");
+    debDword = blePoll.debGetDword(idx);
+    mon.println(debDword);
+    sm.resetEnter();
+  }
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[1] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+// ----------------------------------------------------------------------------
+// Steuern des Polling-Prozesses
+// ----------------------------------------------------------------------------
+// Es ist sowohl die Master- als auch die Slave-Funktion vorgesehen
+//
+
+TxStatistics txStatistics;
+
+void smCtrlPolling()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "polling ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  // --------------------------------------------------------------------------
+  if(mon.lastKeyIn == 'P' || mon.lastKeyIn == 'p')
+  {
+    if(blePoll.stoppedEP())
+    {
+      blePoll.resumeEP();
+      mon.println((char *) "fortgesetzt");
+      sm.resetEnter();
+    }
+    else
+    {
+    blePoll.stopEP();
+    sm.enter(smWaitPolling);
+    }
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'S' || mon.lastKeyIn == 's')
+  {
+    mon.print((char *) "Sendepuffer = ");
+    bleCom.getPduSent(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'R' || mon.lastKeyIn == 'r')
+  {
+    mon.print((char *) "Radiopuffer = ");
+    bleCom.getPduMem(tmpByteArray, 0, 10);
+    mon.println(tmpByteArray, 10, ' ');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'T' || mon.lastKeyIn == 't')
+  {
+    mon.print((char *) "TxStat [");
+    dword bleStat = blePoll.getStatistics(&txStatistics);
+    mon.print(bleStat);
+    mon.print((char *) "] ");
+    mon.print(txStatistics.mode); mon.cprint(' ');
+    mon.print(txStatistics.interrupts); mon.cprint(' ');
+    mon.print(txStatistics.recs); mon.cprint(' ');
+    mon.print(txStatistics.sendings); mon.cprint(' ');
+    mon.print(txStatistics.aliens); mon.cprint(' ');
+    mon.print(txStatistics.wrongs); mon.cprint(' ');
+    mon.print(txStatistics.pollAcks); mon.cprint(' ');
+    mon.print(txStatistics.pollNaks); mon.cprint(' ');
+    mon.print(txStatistics.crcErrors); mon.print("  r[ ");
+    mon.print(txStatistics.memDumpRec,8,' '); mon.print("]  s[ ");
+    mon.print(txStatistics.memDumpSnd,16,' '); mon.cprintln(']');
+    sm.resetEnter();
+  }
+
+
+  else
+  {
+    if(mon.lastKeyIn == ' ')
+    {
+      mon.cFlag[2] = false;
+      mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+      sm.enter(smCheckJobs);
+    }
+  }
+}
+
+void smWaitPolling()
+{
+  if(!blePoll.stoppedEP()) return;
+
+  mon.println((char *) "angehalten");
+  sm.enter(smCtrlPolling);
+}
+
+// ----------------------------------------------------------------------------
+// (4) Testen der Sensorzugriffe
+// ----------------------------------------------------------------------------
+//
+
+char charOut[2];
+
+void smCheckSens()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "Sensorzugriff ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  charOut[0] = mon.lastKeyIn;
+  charOut[1] = '\0';
+  mon.println(charOut);
+
+  if(mon.lastKeyIn == '0' || mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[3] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+  else if(mon.lastKeyIn == '1')
+    sm.enter(smSensReset1);
+  else if(mon.lastKeyIn == '2')
+    sm.enter(smSensReset2);
+  else if(mon.lastKeyIn == '3')
+    sm.enter(smSensGetValues1);
+  else if(mon.lastKeyIn == '4')
+    sm.enter(smSensGetValues2);
+  else if(mon.lastKeyIn == '5')
+    sm.enter(smSensGetValues3);
+  else if(mon.lastKeyIn == '6')
+    sm.enter(smSensGetValues4);
+  else if(mon.lastKeyIn == '7')
+    sm.enter(smSensGetValues5);
+  else if(mon.lastKeyIn == '8')
+    sm.enter(smSensGetValues6);
+  else if(mon.lastKeyIn == 'c')
+    sm.enter(smSensDebugValues);
+  else if(mon.lastKeyIn == 'e')
+    sm.enter(smSensGetErrors);
+  else if(mon.lastKeyIn == 'r')
+    sm.enter(smSensGetRunCounts);
+  else if(mon.lastKeyIn == 's')
+    sm.enter(smSensGetSoaapValues);
+  else if(mon.lastKeyIn == 't')
+    sm.enter(smSensGetTimeOuts);
+  else
+    sm.resetEnter();
+  mon.lastKeyIn = ':';
+}
+
+void smSensReset1()
+{
+  int retv = sens.resetAG();
+  //int retv = twi.writeByteReg(0x6B, 0x22, 0x05);
+  mon.print((char *) "resetAG = ");
+  mon.println(retv);
+  sm.enter(smCheckSens);
+}
+
+void smSensReset2()
+{
+  int retv = sens.resetM();
+  //int retv = twi.writeByteReg(0x1E, 0x21, 0x0C);
+  mon.print((char *) "resetM = ");
+  mon.println(retv);
+  sm.enter(smCheckSens);
+}
+
+void smSensGetValues1()
+{
+  if(sm.firstEnter())
+    sens.syncValuesAG();
+
+  if(!sens.getValuesAG(&rawDataAG)) return;
+
+  mon.print((char *) "ValueA = ");
+  mon.print(rawDataAG.valueAG.A.x);
+  mon.print((char *) " ");
+  mon.print(rawDataAG.valueAG.A.y);
+  mon.print((char *) " ");
+  mon.println(rawDataAG.valueAG.A.z);
+  sm.enter(smCheckSens);
+}
+
+char  outValue[64];
+
+void smSensGetValues2()
+{
+  if(sm.firstEnter())
+    sens.syncValuesAG();
+
+  if(!sens.getValuesAG(&calData)) return;
+
+  mon.print((char *) "ValueA = ");
+  sprintf(outValue,"%f ",calData.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%f ",calData.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%f ",calData.A.z);
+  mon.println(outValue);
+  sm.enter(smCheckSens);
+}
+
+void smSensGetValues3()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+  }
+
+  if(!sens.getValuesAG(&calData)) return;
+
+  mon.print((char *) "Values A = ");
+  sprintf(outValue,"%+5.3f ",calData.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calData.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calData.A.z);
+  mon.println(outValue);
+
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+void smSensGetValues4()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+  }
+
+  if(!sens.getValuesAG(&calData)) return;
+
+  mon.print((char *) "Values AG = ");
+  sprintf(outValue,"%+5.3f ",calData.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calData.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f   ",calData.A.z);
+  mon.print(outValue);
+
+  sprintf(outValue,"%+5.1f ",calData.G.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.1f ",calData.G.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.1f ",calData.G.z);
+  mon.println(outValue);
+
+
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+void smSensGetValues5()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+    sm.setTimeOut(1000);
+  }
+
+  if(sm.timeOut())
+  {
+    mon.println((char *) " Time Out");
+    sm.enter(smCheckSens);
+    return;
+  }
+
+  if(!sens.getValuesAG(&calData)) return;
+  sm.setTimeOut(1000);
+
+  mon.print((char *) "Values AGM = ");
+
+  sprintf(outValue,"%+5.3f ",calData.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calData.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f   ",calData.A.z);
+  mon.print(outValue);
+
+  sprintf(outValue,"%+5.1f ",calData.G.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.1f ",calData.G.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.1f   ",calData.G.z);
+  mon.print(outValue);
+
+  sens.getValuesM(&calValue);
+
+  sprintf(outValue,"%+5.3f ",calValue.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calValue.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calValue.z);
+  mon.println(outValue);
+
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+void smSensGetValues6()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+    sm.setTimeOut(1000);
+  }
+
+  if(sm.timeOut())
+  {
+    mon.println((char *) " Time Out");
+    sm.enter(smCheckSens);
+    return;
+  }
+
+  if(!sens.getValuesAG(&rawDataAG)) return;
+  sm.setTimeOut(1000);
+
+  mon.print((char *) "Values AGM = ");
+
+  sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"%4X   ",(unsigned short) rawDataAG.valueAG.A.z);
+  mon.print(outValue);
+
+  sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.G.x);
+  mon.print(outValue);
+  sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.G.y);
+  mon.print(outValue);
+  sprintf(outValue,"%4X   ",(unsigned short) rawDataAG.valueAG.G.z);
+  mon.println(outValue);
+
+  /*
+  sens.getValuesM(&calValue);
+
+  sprintf(outValue,"%+5.3f ",calValue.x);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calValue.y);
+  mon.print(outValue);
+  sprintf(outValue,"%+5.3f ",calValue.z);
+  mon.println(outValue);
+  */
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+
+void smSensGetValues7()
+{
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    mon.lastKeyIn = ':';
+    sm.setTimeOut(1000);
+  }
+
+  if(sm.timeOut())
+  {
+    mon.println((char *) " Time Out");
+    sm.enter(smCheckSens);
+    return;
+  }
+
+  if(!sens.getValuesAG(&rawDataAG)) return;
+  sm.setTimeOut(1000);
+
+  mon.print((char *) "%~Values AGM = $");
+
+  sprintf(outValue,"#@%04X$",(unsigned short) rawDataAG.valueAG.A.x);
+  mon.print(outValue);
+  sprintf(outValue,"#A%04X$",(unsigned short) rawDataAG.valueAG.A.y);
+  mon.print(outValue);
+  sprintf(outValue,"#B%04X$",(unsigned short) rawDataAG.valueAG.A.z);
+  mon.print(outValue);
+
+  sprintf(outValue,"#C%04X$",(unsigned short) rawDataAG.valueAG.G.x);
+  mon.print(outValue);
+  sprintf(outValue,"#D%04X$",(unsigned short) rawDataAG.valueAG.G.y);
+  mon.print(outValue);
+  sprintf(outValue,"#E%04X$",(unsigned short) rawDataAG.valueAG.G.z);
+  mon.print(outValue);
+
+  if(mon.lastKeyIn == ' ')
+    sm.enter(smCheckSens);
+}
+
+
+void smSensGetSoaapValues()
+{
+  sm.enter(smSensGetValues7);
+}
+
+void smSensDebugValues()
+{
+  mon.print((char *) "Werte: toValueStatusAG=");
+  mon.print(sens.debGetDword(1));
+  mon.print((char *) "  toValueStatusM=");
+  mon.println(sens.debGetDword(2));
+  sm.enter(smCheckSens);
+}
+
+
+void smSensGetErrors()
+{
+  mon.print((char *) "Errors AG: AdrNak=");
+  mon.print(sens.errorCntAdrNakAG);
+  mon.print((char *) "  DataNak=");
+  mon.print(sens.errorCntDataNakAG);
+  mon.print((char *) "  Overrun=");
+  mon.print(sens.errorCntOverAG);
+
+  mon.print((char *) "  M: AdrNak=");
+  mon.print(sens.errorCntAdrNakM);
+  mon.print((char *) "  DataNak=");
+  mon.print(sens.errorCntDataNakM);
+  mon.print((char *) "  Overrun=");
+  mon.println(sens.errorCntOverM);
+  sm.enter(smCheckSens);
+}
+
+void smSensGetTimeOuts()
+{
+  mon.print((char *) "TimeOuts AG: TwiStat=");
+  mon.print(sens.toCntTwiStatusAG);
+  mon.print((char *) "  TwiData=");
+  mon.print(sens.toCntTwiDataAG);
+  mon.print((char *) "  Status=");
+  mon.print(sens.toCntStatusAG);
+
+  mon.print((char *) "  M: TwiStat=");
+  mon.print(sens.toCntTwiStatusM);
+  mon.print((char *) "  TwiData=");
+  mon.print(sens.toCntTwiDataM);
+  mon.print((char *) "  Status=");
+  mon.println(sens.toCntStatusM);
+  sm.enter(smCheckSens);
+}
+
+void smSensGetRunCounts()
+{
+  mon.print((char *) "RunCounts: ");
+  for(int i = 0; i < NrOfRunStates; i++)
+  {
+    mon.print((char *) " ");
+    mon.print(sens.runStateCntArray[i]);
+  }
+  mon.print((char *) "  Total=");
+  mon.println(sens.runStateCntTotal);
+  sm.enter(smCheckSens);
+}
+#endif // DebugTerminal
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Gpio/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Gpio/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..a099c0c6f9c5ede5584dbf9ab24da0199b348548
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Gpio/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Gpio",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Gpio/nRF52840Gpio.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Gpio/nRF52840Gpio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..47a25ddebcff11a2d9ef003cf83ddf1be250d057
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Gpio/nRF52840Gpio.cpp
@@ -0,0 +1,353 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Gpio.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   29. Juni 2021
+//
+
+#include "nRF52840Gpio.h"
+
+  // --------------------------------------------------------------------------
+  // Konstruktoren
+  // --------------------------------------------------------------------------
+  //
+  nRF52840Gpio::nRF52840Gpio()
+  {
+    gpioPtr = NULL;
+  }
+
+
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+
+dword     nRF52840Gpio::getCnfValue(unsigned int cnfBits)
+{
+  dword tmpMask = 0;
+
+  if(cnfBits & IfDrvPullUp) tmpMask |= GpioPinCnf_PULL(GpioPullUp);
+  if(cnfBits & IfDrvPullDown) tmpMask |= GpioPinCnf_PULL(GpioPullDown);
+
+  if((cnfBits & IfDrvOutput))     // Ausgang **********************************
+  {
+    tmpMask |= GpioPinCnf_DIR;
+
+    if(cnfBits & IfDrvStrongHigh)       // StrongHigh = H1
+    {
+      if(cnfBits & IfDrvOpenSource)     // OpenSource = D0
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveD0H1);
+      else if(cnfBits & IfDrvStrongLow) // StrongLow = H0
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveH0H1);
+      else
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveS0H1);
+    }
+    else if(cnfBits & IfDrvStrongLow)   // StrongLow = H0
+    {
+      if(cnfBits & IfDrvOpenDrain)      // OpenDrain = D1
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveH0D1);
+      else
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveH0S1);
+    }
+    else
+    {
+      if(cnfBits & IfDrvOpenSource)     // OpenSource = D0
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveD0S1);
+      else if(cnfBits & IfDrvOpenDrain) // OpenDrain = D1
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveS0D1);
+      else
+        tmpMask |= GpioPinCnf_DRIVE(GpioDriveS0S1);
+    }
+  }
+  else                            // Eingang **********************************
+  {
+    tmpMask &= 0xFFFFFFFC;
+  }
+
+  return(tmpMask);
+}
+
+GpioError nRF52840Gpio::config(int nrFrom, int nrTo, unsigned int cnfBits, GpioExtRefPtr refPtr)
+{
+  GpioError retv = GEnoError;
+  int       portNum;
+  int       pinNum;
+  dword     tmpMask;
+  dword     cnfValue;
+
+  tmpMask = IfDrvOpenDrain | IfDrvOpenSource;
+  if((cnfBits & tmpMask) == tmpMask) return (GEcdictPar);
+
+  tmpMask = IfDrvPullDown | IfDrvPullUp;
+  if((cnfBits & tmpMask) == tmpMask) return (GEcdictPar);
+
+  cnfValue  = getCnfValue(cnfBits);
+  tmpMask   = 0;
+
+  // Bedienen des angegebenen Bereiches
+  //
+  for(int i = nrFrom; i <= nrTo; i++)
+  {
+    portNum = (i & 0x0E0) >> 5;
+    pinNum  =  i & 0x01F;
+
+    tmpMask |= (1 << i);
+
+    if(portNum == 0)
+      gpioPtr = NrfGpioPtr0;
+    else
+      gpioPtr = NrfGpioPtr1;
+
+      gpioPtr->PIN_CNF[pinNum] = cnfValue;
+  }
+
+  refPtr->ioPtr = (dword *) gpioPtr;
+  refPtr->pins  = tmpMask;
+
+  return(retv);
+}
+
+GpioError nRF52840Gpio::config(int nr, unsigned int cnfBits, GpioExtRefPtr refPtr)
+{
+  return(config(nr,nr,cnfBits, refPtr));
+}
+
+GpioError nRF52840Gpio::config(GpioExtMask mask, unsigned int cnfBits, GpioExtRefPtr refPtr)
+{
+  GpioError retv = GEnoError;
+  dword     cnfVal;
+
+  cnfVal = IfDrvOpenDrain | IfDrvOpenSource;
+  if((cnfBits & cnfVal) == cnfVal) return (GEcdictPar);
+
+  cnfVal = IfDrvPullDown | IfDrvPullUp;
+  if((cnfBits & cnfVal) == cnfVal) return (GEcdictPar);
+
+  cnfVal = getCnfValue(cnfBits);
+
+  // Bedienen des angegebenen Bereiches
+  //
+  dword chkMask = 1;
+
+  for(int i = 0; i < 32; i++)
+  {
+    if(mask.port == 0)
+      gpioPtr = NrfGpioPtr0;
+    else
+      gpioPtr = NrfGpioPtr1;
+
+    if(mask.pins & chkMask)
+      gpioPtr->PIN_CNF[i] = cnfVal;
+
+    chkMask <<= 1;
+  }
+
+  if(refPtr != NULL)
+  {
+    refPtr->ioPtr = (dword *) gpioPtr;
+    refPtr->pins  = mask.pins;
+  }
+
+  return(retv);
+}
+
+GpioError nRF52840Gpio::configArd(ArdMask ardMask, unsigned int cnfBits)
+{
+  GpioExtMask  ioMask;
+
+  switch(ardMask)
+  {
+    case ArdA0A3:
+      ioMask.port = 0;
+      ioMask.pins = ArdA0Mask | ArdA1Mask | ArdA2Mask | ArdA3Mask;
+      break;
+
+    case ArdA4A7:
+      ioMask.port = 0;
+      ioMask.pins = ArdA4Mask | ArdA5Mask | ArdA6Mask | ArdA7Mask;
+      break;
+
+    case ArdA0A7:
+      ioMask.port = 0;
+      ioMask.pins = ArdA0Mask | ArdA1Mask | ArdA2Mask | ArdA3Mask |
+                    ArdA4Mask | ArdA5Mask | ArdA6Mask | ArdA7Mask;
+      break;
+
+    case ArdD2D5:
+      ioMask.port = 1;
+      ioMask.pins = ArdD2Mask | ArdD3Mask | ArdD4Mask | ArdD5Mask;
+      break;
+  }
+
+  return config(ioMask, cnfBits, NULL);
+}
+
+
+
+  // --------------------------------------------------------------------------
+  // Anwendungsfunktionen
+  // --------------------------------------------------------------------------
+  //
+void      nRF52840Gpio::read(GpioExtRefPtr ioRefPtr, GpioExtValPtr valPtr)
+{
+  gpioPtr = (nrfGpioPtr) ioRefPtr->ioPtr;
+  valPtr->value = gpioPtr->IN;
+}
+
+dword     nRF52840Gpio::readArd(ArdMask ardMask)
+{
+  dword   inVal;
+  dword   retVal;
+
+  retVal = 0;
+
+  switch(ardMask)
+  {
+    case ArdA0A3:
+      inVal = NrfGpioPtr0->IN;
+      if(inVal & ArdA0Mask) retVal |= 0x01;
+      if(inVal & ArdA1Mask) retVal |= 0x02;
+      if(inVal & ArdA2Mask) retVal |= 0x04;
+      if(inVal & ArdA3Mask) retVal |= 0x08;
+      break;
+
+    case ArdA4A7:
+      inVal = NrfGpioPtr0->IN;
+      if(inVal & ArdA4Mask) retVal |= 0x01;
+      if(inVal & ArdA5Mask) retVal |= 0x02;
+      if(inVal & ArdA6Mask) retVal |= 0x04;
+      if(inVal & ArdA7Mask) retVal |= 0x08;
+      break;
+
+    case ArdA0A7:
+      inVal = NrfGpioPtr0->IN;
+      if(inVal & ArdA0Mask) retVal |= 0x01;
+      if(inVal & ArdA1Mask) retVal |= 0x02;
+      if(inVal & ArdA2Mask) retVal |= 0x04;
+      if(inVal & ArdA3Mask) retVal |= 0x08;
+      if(inVal & ArdA4Mask) retVal |= 0x10;
+      if(inVal & ArdA5Mask) retVal |= 0x20;
+      if(inVal & ArdA6Mask) retVal |= 0x40;
+      if(inVal & ArdA7Mask) retVal |= 0x80;
+      break;
+
+    case ArdD2D5:
+      inVal = NrfGpioPtr1->IN;
+      if(inVal & ArdD2Mask) retVal |= 0x01;
+      if(inVal & ArdD3Mask) retVal |= 0x02;
+      if(inVal & ArdD4Mask) retVal |= 0x04;
+      if(inVal & ArdD5Mask) retVal |= 0x08;
+      break;
+  }
+
+  return(retVal);
+}
+
+
+void      nRF52840Gpio::write(GpioExtRefPtr refPtr, GpioExtValPtr valPtr)
+{
+  ((nrfGpioPtr) refPtr->ioPtr)->OUTSET = valPtr->value & refPtr->pins;
+  ((nrfGpioPtr) refPtr->ioPtr)->OUTCLR = ~valPtr->value & refPtr->pins;
+  if(refPtr->next == NULL) return;
+  ((nrfGpioPtr) refPtr->next->ioPtr)->OUTSET = valPtr->next->value & refPtr->next->pins;
+  ((nrfGpioPtr) refPtr->next->ioPtr)->OUTCLR = ~valPtr->next->value & refPtr->next->pins;
+}
+
+void      nRF52840Gpio::set(GpioExtRefPtr refPtr)
+{
+  ((nrfGpioPtr) refPtr->ioPtr)->OUTSET = refPtr->pins;
+  if(refPtr->next == NULL) return;
+  ((nrfGpioPtr) refPtr->next->ioPtr)->OUTSET = refPtr->next->pins;
+}
+
+void      nRF52840Gpio::clr(GpioExtRefPtr refPtr)
+{
+  ((nrfGpioPtr) refPtr->ioPtr)->OUTCLR = refPtr->pins;
+  if(refPtr->next == NULL) return;
+  ((nrfGpioPtr) refPtr->next->ioPtr)->OUTCLR = refPtr->next->pins;
+}
+
+
+
+void      nRF52840Gpio::writeArd(ArdMask ardMask, dword value)
+{
+  dword   set0 = 0, set1 = 0;
+  dword   clr0 = 0, clr1 = 0;
+
+  switch(ardMask)
+  {
+    case ArdA0A3:
+      if(value & 0x01) set0 |= ArdA0Mask;
+      else clr0 |= ArdA0Mask;
+      if(value & 0x02) set0 |= ArdA1Mask;
+      else clr0 |= ArdA1Mask;
+      if(value & 0x04) set0 |= ArdA2Mask;
+      else clr0 |= ArdA2Mask;
+      if(value & 0x08) set0 |= ArdA3Mask;
+      else clr0 |= ArdA3Mask;
+
+      NrfGpioPtr0->OUTSET = set0;
+      NrfGpioPtr0->OUTCLR = clr0;
+      break;
+
+    case ArdA4A7:
+      if(value & 0x01) set0 |= ArdA4Mask;
+      else clr0 |= ArdA4Mask;
+      if(value & 0x02) set0 |= ArdA5Mask;
+      else clr0 |= ArdA5Mask;
+      if(value & 0x04) set0 |= ArdA6Mask;
+      else clr0 |= ArdA6Mask;
+      if(value & 0x08) set0 |= ArdA7Mask;
+      else clr0 |= ArdA7Mask;
+
+      NrfGpioPtr0->OUTSET = set0;
+      NrfGpioPtr0->OUTCLR = clr0;
+      break;
+
+    case ArdA0A7:
+      if(value & 0x01) set0 |= ArdA0Mask;
+      else clr0 |= ArdA0Mask;
+      if(value & 0x02) set0 |= ArdA1Mask;
+      else clr0 |= ArdA1Mask;
+      if(value & 0x04) set0 |= ArdA2Mask;
+      else clr0 |= ArdA2Mask;
+      if(value & 0x08) set0 |= ArdA3Mask;
+      else clr0 |= ArdA3Mask;
+      if(value & 0x01) set0 |= ArdA4Mask;
+      else clr0 |= ArdA4Mask;
+      if(value & 0x02) set0 |= ArdA5Mask;
+      else clr0 |= ArdA5Mask;
+      if(value & 0x04) set0 |= ArdA6Mask;
+      else clr0 |= ArdA6Mask;
+      if(value & 0x08) set0 |= ArdA7Mask;
+      else clr0 |= ArdA7Mask;
+
+      NrfGpioPtr0->OUTSET = set0;
+      NrfGpioPtr0->OUTCLR = clr0;
+      break;
+
+    case ArdD2D5:
+      if(value & 0x01) set1 |= ArdD2Mask;
+      else clr1 |= ArdD2Mask;
+      if(value & 0x02) set1 |= ArdD3Mask;
+      else clr1 |= ArdD3Mask;
+      if(value & 0x04) set1 |= ArdD4Mask;
+      else clr1 |= ArdD4Mask;
+      if(value & 0x08) set1 |= ArdD5Mask;
+      else clr1 |= ArdD5Mask;
+
+      NrfGpioPtr1->OUTSET = set1;
+      NrfGpioPtr1->OUTCLR = clr1;
+      break;
+  }
+}
+
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Gpio/nRF52840Gpio.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Gpio/nRF52840Gpio.h
new file mode 100644
index 0000000000000000000000000000000000000000..addf5ad533ddfecabd2c540824238c278a117998
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Gpio/nRF52840Gpio.h
@@ -0,0 +1,181 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Gpio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+// Datum:   29. Juni 2021
+//
+
+#ifndef NRF52840GPIO_H
+#define NRF52840GPIO_H
+
+#include "Arduino.h"
+#include "arduinoDefs.h"
+#include "IntrfGpio.h"
+
+#ifndef nrfGpioDef
+// ----------------------------------------------------------------------------
+typedef struct _nrfGpio
+{
+  volatile  dword Reserve01;                // 000
+  volatile  dword OUT;                      // 004
+  volatile  dword OUTSET;                   // 008
+  volatile  dword OUTCLR;                   // 00C
+  volatile  dword IN;                       // 010
+  volatile  dword DIR;                      // 014
+  volatile  dword DIRSET;                   // 018
+  volatile  dword DIRCLR;                   // 01C
+  volatile  dword LATCH;                    // 020
+  volatile  dword DETECTMODE;               // 024
+  volatile  dword Reserve02[118];           // 026
+  volatile  dword PIN_CNF[32];              // 200
+} nrfGpio, *nrfGpioPtr;
+
+#define NrfGpioBase   0x50000000
+#define NrfGpioBase0  0x50000500
+#define NrfGpioPtr0   ((nrfGpioPtr) NrfGpioBase0)
+#define NrfGpioBase1  0x50000800
+#define NrfGpioPtr1   ((nrfGpioPtr) NrfGpioBase1)
+
+#define GpioPinCnf_DIR        ((dword) 0x00000001)
+
+#define GpioPinCnf_INPUT      ((dword) 0x00000001 << 1)
+
+#define GpioPinCnf_PULL(x)    ((dword) x << 2)
+#define GpioPullDown          1
+#define GpioPullUp            3
+
+#define GpioPinCnf_DRIVE(x)   ((dword) x << 8)
+#define GpioDriveS0S1         0
+#define GpioDriveH0S1         1
+#define GpioDriveS0H1         2
+#define GpioDriveH0H1         3
+#define GpioDriveD0S1         4
+#define GpioDriveD0H1         5
+#define GpioDriveS0D1         6
+#define GpioDriveH0D1         7
+
+#define GpioPinCnf_SENSE(x)   ((dword) x << 16)
+#define GpioSenseHigh         2
+#define GpioSenseLow          3
+
+#define nrfGpioDef
+// ----------------------------------------------------------------------------
+#endif
+
+#define P0(x) (x)
+#define P1(x) (32+x)
+
+#ifdef smnNANOBLE33
+// ----------------------------------------------------------------------------
+#define ArdA0Bit    4
+#define ArdA1Bit    5
+#define ArdA2Bit    30
+#define ArdA3Bit    29
+#define ArdA4Bit    31
+#define ArdA5Bit    2
+#define ArdA6Bit    28
+#define ArdA7Bit    3
+
+#define ArdA0   P0(4)
+#define ArdA1   P0(5)
+#define ArdA2   P0(30)
+#define ArdA3   P0(29)
+#define ArdA4   P0(31)
+#define ArdA5   P0(2)
+#define ArdA6   P0(28)
+#define ArdA7   P0(3)
+
+#define ArdA0Mask   (1 << 4)
+#define ArdA1Mask   (1 << 5)
+#define ArdA2Mask   (1 << 30)
+#define ArdA3Mask   (1 << 29)
+#define ArdA4Mask   (1 << 31)
+#define ArdA5Mask   (1 << 2)
+#define ArdA6Mask   (1 << 28)
+#define ArdA7Mask   (1 << 3)
+
+
+#define ArdD2       P1(11)
+#define ArdD3       P1(12)
+#define ArdD4       P1(15)
+#define ArdD5       P1(13)
+#define ArdD6       P0(14)
+#define ArdD7       P0(23)
+#define ArdD8       P1(21)
+#define ArdD9       P0(27)
+#define ArdD10      P1(2)
+#define ArdD11      P1(1)
+#define ArdD12      P1(8)
+#define ArdD13      P0(13)
+
+#define ArdD2Mask   (1 << 11)
+#define ArdD3Mask   (1 << 12)
+#define ArdD4Mask   (1 << 15)
+#define ArdD5Mask   (1 << 13)
+#define ArdD6Mask   (1 << 14)
+#define ArdD7Mask   (1 << 23)
+#define ArdD8Mask   (1 << 21)
+#define ArdD9Mask   (1 << 27)
+#define ArdD10Mask  (1 << 2)
+#define ArdD11Mask  (1 << 1)
+#define ArdD12Mask  (1 << 8)
+#define ArdD13Mask  (1 << 13)
+
+// ----------------------------------------------------------------------------
+#endif
+
+class nRF52840Gpio : IntrfGpio
+{
+private:
+  // --------------------------------------------------------------------------
+  // lokale Variablen
+  // --------------------------------------------------------------------------
+  //
+  nrfGpioPtr  gpioPtr;
+
+public:
+  // --------------------------------------------------------------------------
+  // Konstruktoren
+  // --------------------------------------------------------------------------
+  //
+  nRF52840Gpio();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  dword     getCnfValue(unsigned int cnfBits);
+  GpioError config(int nr, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  GpioError config(int nrFrom, int nrTo, unsigned int cnfBits, GpioExtRefPtr refPtr);
+  GpioError config(GpioExtMask mask, unsigned int cnfBits, GpioExtRefPtr refPtr);
+
+  GpioError configArd(ArdMask ardMask, unsigned int cnfBits);
+
+  // --------------------------------------------------------------------------
+  // Anwendungsfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void      read(GpioExtRefPtr ioRef, GpioExtValPtr valPtr);
+  dword     readArd(ArdMask ardMask);
+
+  void      write(GpioExtRefPtr refPtr, GpioExtValPtr valPtr);
+  void      writeArd(ArdMask ardMask, dword value);
+  void      set(GpioExtRefPtr refPtr);
+  void      clr(GpioExtRefPtr refPtr);
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Debugging und globale Variablen
+  // --------------------------------------------------------------------------
+  //
+
+};
+
+#endif //NRF52840GPIO_H
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Radio/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Radio/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..a18f8f0f08e3ee567cac8bd59e8774c14b3effe7
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Radio/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Radio",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Radio/nRF52840Radio.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Radio/nRF52840Radio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5639480f98f812bc2170a24674d34534dd95d5e6
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Radio/nRF52840Radio.cpp
@@ -0,0 +1,943 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Radio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#include "Arduino.h"
+#include "nRF52840Radio.h"
+#include <string.h>
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+
+nRF52840Radio::nRF52840Radio()
+{
+  NrfRadioPtr->TASKS_DISABLE;   // Sender/Empfänger abgeschaltet
+#ifdef nrfPowerDCDCEN
+  *nrfPowerDCDCEN = 1;
+#endif
+#ifdef nrfClockTASKS_HFCLKSTART
+  *nrfClockTASKS_HFCLKSTART = 1;
+#endif
+  NrfRadioPtr->POWER = 0;
+  NrfRadioPtr->POWER = 1;
+
+  irqCounter = 0;
+  trfMode = txmBase;
+  statisticPtr = NULL;
+  recMode = true;
+  pmPtr = (bcPduPtr) pduMem;
+  psPtr = (bcPduPtr) pduSentS;
+  pePtr = (bcPduPtr) pduSentE;
+  eadM = false;
+  nakM = false;
+  comFin = false;
+  comError = false;
+  newValues = false;
+
+  memset(statList,0,NrOfTxModes * sizeof(TxStatistics));
+}
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+
+// Allgemeine Vorbereitungen
+//
+void  nRF52840Radio::begin()
+{
+  instPtr0 = this;      // Verzweigung im statischen Bereich setzen
+
+  NrfRadioPtr->INTENCLR = 0xFFFFFFFF;   // Vorsichtshalber keine Interrupts
+
+  // Interruptvektor setzen
+  //
+  __NVIC_SetVector((IRQn_Type) 1, (dword) nRF52840Radio::irqHandler0);
+  __NVIC_SetPriority((IRQn_Type) 1, 1);
+  __NVIC_EnableIRQ((IRQn_Type) 1);
+}
+
+// Setzen der Zugriffsadresse
+//
+void  nRF52840Radio::setAccessAddress(dword addr)
+{
+  dword prefix = addr >> 24;
+  dword base = addr << 8;
+
+  cfgData.base0   = NrfRadioPtr->BASE0        = base;
+  cfgData.prefix0 = NrfRadioPtr->PREFIX0      = prefix;
+  cfgData.txAddr  = NrfRadioPtr->TXADDRESS    = 0;
+  cfgData.rxAddr  = NrfRadioPtr->RXADDRESSES  = 0x01;
+}
+
+// Telegrammparameter setzen
+//
+void  nRF52840Radio::setPacketParms(blePduType type)
+{
+  switch(type)
+  {
+    case bptAdv:
+      cfgData.pCnf0     = NrfRadioPtr->PCNF0        = PCNF0_LFLEN(8) | PCNF0_S0LEN(1) | PCNF0_S1LEN(0);
+      cfgData.pCnf1     = NrfRadioPtr->PCNF1        = PCNF1_MAXLEN(42) | PCNF1_BALEN(3) | PCNF1_WHITEEN(1);
+      cfgData.modeCnf0  = NrfRadioPtr->MODECNF0     = 1;
+      cfgData.crcCnf    = NrfRadioPtr->CRCCNF       = CRCCNF_LEN(3) | CRCCNF_SKIPADDR(1);
+      cfgData.crcPoly   = NrfRadioPtr->CRCPOLY      = PolynomCRC;
+      cfgData.crcInit   = NrfRadioPtr->CRCINIT      = AdvStartCRC;
+      cfgData.packetPtr = NrfRadioPtr->PACKETPTR    = (dword) pduMem;
+      cfgData.mode      = NrfRadioPtr->MODE         = 3;
+      cfgData.dacnf     = NrfRadioPtr->DACNF        = 0x0FF00;
+      break;
+
+    case bptAux:
+      break;
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+// Steuerfunktionen und gezielte Prozessorzugriffe
+// ----------------------------------------------------------------------------
+
+// Schalten des Bewerbungskanals
+//
+void nRF52840Radio::setChannel(int nr)
+{
+  cfgData.frequency = NrfRadioPtr->FREQUENCY = channelList[nr].freq;
+  cfgData.whiteInit = NrfRadioPtr->DATAWHITEIV = channelList[nr].idx;
+}
+
+// ----------------------------------------------------------------------------
+//                      S e n d e n
+// ----------------------------------------------------------------------------
+
+// Einstellen der Sendeleistung
+//
+void  nRF52840Radio::setPower(int DBm)
+{
+  cfgData.txPower = NrfRadioPtr->TXPOWER = DBm;
+}
+// Senden eines Telegramms
+// Es wird davon ausgeganen, das der Radio-Zustand = DISABLED ist
+//
+int nRF52840Radio::sendSync(bcPduPtr inPduPtr, TxStatePtr refState)
+{
+  int   retv = 0;
+  NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+  NrfRadioPtr->EVENTS_READY = 0;
+  NrfRadioPtr->EVENTS_END = 0;
+  memcpy((void *)pduMem, (void *)inPduPtr, sizeof(bcPdu));  // Daten kopieren
+  if(refState != NULL)
+    refState->prgLoopPrep = retv = 3 + sizeof(bcPdu);
+  NrfRadioPtr->TASKS_TXEN = 1;                  // Starten des Anlaufes
+  while(NrfRadioPtr->EVENTS_READY != 1) retv++; // Warten bis angelaufen
+  if(refState != NULL)
+    refState->evtLoopRampUp = retv - 3;
+  NrfRadioPtr->TASKS_START = 1;                 // Starten des Sendevorgangs
+  while(NrfRadioPtr->EVENTS_END != 1) retv++;   // Warten bis gesendet
+  NrfRadioPtr->TASKS_DISABLE = 1;               // Sender abschalten
+  if(refState != NULL)
+  {
+    refState->evtLoopTrans = retv - refState->evtLoopRampUp;
+    refState->txBufferPtr = pduMem;
+  }
+  return(retv);
+}
+
+void  nRF52840Radio::send(bcPduPtr inPduPtr, TxMode txMode)
+{
+  send(inPduPtr, NULL, txMode, false);
+}
+
+void  nRF52840Radio::send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, bool inNewValues)
+{
+  NrfRadioPtr->INTENCLR         = 0xFFFFFFFF;
+  NrfRadioPtr->EVENTS_READY     = 0;
+  NrfRadioPtr->EVENTS_END       = 0;
+  NrfRadioPtr->EVENTS_DISABLED  = 0;
+  NrfRadioPtr->EVENTS_RXREADY   = 0;
+  NrfRadioPtr->EVENTS_TXREADY   = 0;
+  NrfRadioPtr->EVENTS_ADDRESS   = 0;
+
+  // TODO
+  // Das muss Alles noch einmal überarbeitet werden.
+  // Hier stecken zu viele Redundanzen drin, Altlast aus diversen Tests mit der Hardware
+
+  memcpy((void *)pduMem, (void *)inPduPtrE, sizeof(bcPdu));    // Daten in Funkpuffer kopieren
+
+  memcpy((void *)pduSentE, (void *)inPduPtrE, sizeof(bcPdu));  // Daten in extra Puffer kopieren
+  // Die übergebenen Daten werden in einen Extrapuffer kopiert zur Entkopplung für eventuelle
+  // lokale Modifikationen
+
+  if(inPduPtrS != NULL)                             // Falls Daten für eine Antwort gegeben sind
+    memcpy((void *)pduSentS, (void *)inPduPtrS, sizeof(bcPdu));// Daten in extra Puffer kopieren
+  // Die übergebenen Daten werden in einen Extrapuffer kopiert zur Entkopplung für eventuelle
+  // lokale Modifikationen
+
+  comFin    = false;
+  comError  = false;
+  newValues = inNewValues;
+
+  trfMode = txMode;
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+  statisticPtr = &statList[(int) txMode];
+  statisticPtr->mode = txMode;
+  memset(statisticPtr->memDumpRec,0,16);
+  memset(statisticPtr->memDumpSnd,0,16);
+#endif
+
+  switch(txMode)
+  {
+    case txmPoll:
+      recMode = false;
+      NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN | NrfScRXREADY_START;
+      NrfRadioPtr->INTENSET = NrfIntRXREADY;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmResp:
+    case txmRespE:
+      recMode = true;
+      NrfRadioPtr->SHORTS = NrfScREADY_START;
+      NrfRadioPtr->INTENSET = NrfIntEND;
+      NrfRadioPtr->TASKS_RXEN = 1;
+      break;
+
+    case txmBase:
+      NrfRadioPtr->SHORTS = NrfScREADY_START | NrfScEND_DISABLE;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmRepStart:
+      NrfRadioPtr->SHORTS = NrfScREADY_START;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmRepCont:
+      NrfRadioPtr->SHORTS = 0;
+      NrfRadioPtr->TASKS_START = 1;
+      break;
+
+    case txmRepEnd:
+      NrfRadioPtr->SHORTS = NrfScEND_DISABLE;
+      NrfRadioPtr->TASKS_START = 1;
+      break;
+
+    case txmReadPrep:
+      NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmReadS:
+      NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN | NrfScRXREADY_START;
+      NrfRadioPtr->INTENSET = NrfIntADDRESS;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+
+    case txmRead:
+      NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN | NrfScRXREADY_START;
+      NrfRadioPtr->INTENSET = NrfIntADDRESS | NrfIntEND;
+      NrfRadioPtr->TASKS_TXEN = 1;
+      break;
+  }
+}
+
+void nRF52840Radio::disable(TxMode txMode)
+{
+  switch(txMode)
+   {
+     case txmBase:
+       break;
+
+     case txmRepStart:
+       break;
+
+     case txmRepCont:
+       break;
+
+     case txmRepEnd:
+       break;
+
+     case txmReadPrep:
+       break;
+
+     case txmRead:
+       NrfRadioPtr->TASKS_DISABLE = 1;
+       break;
+
+     case txmPoll:
+       NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+       NrfRadioPtr->EVENTS_DISABLED = 0;
+       NrfRadioPtr->TASKS_DISABLE = 1;
+       break;
+
+     case txmResp:
+     case txmRespE:
+       NrfRadioPtr->TASKS_DISABLE = 1;
+       break;
+   }
+  NrfRadioPtr->SHORTS = 0;
+}
+
+bool nRF52840Radio::disabled(TxMode txMode)
+{
+  bool retv = false;
+
+  switch(txMode)
+   {
+     case txmBase:
+       break;
+
+     case txmRepStart:
+       break;
+
+     case txmRepCont:
+       break;
+
+     case txmRepEnd:
+       break;
+
+     case txmReadPrep:
+       break;
+
+     case txmRead:
+     case txmPoll:
+       if(NrfRadioPtr->EVENTS_DISABLED == 1)
+       {
+         NrfRadioPtr->EVENTS_DISABLED = 0;
+         retv = true;
+       }
+       else
+       {
+         if(NrfRadioPtr->STATE == NrfStDISABLED)
+           retv = true;
+       }
+       break;
+
+     case txmResp:
+     case txmRespE:
+       if(NrfRadioPtr->EVENTS_DISABLED == 1)
+       {
+         NrfRadioPtr->EVENTS_DISABLED = 0;
+         retv = true;
+       }
+       else
+       {
+         if(NrfRadioPtr->STATE == NrfStDISABLED)
+           retv = true;
+       }
+       break;
+   }
+  return(retv);
+}
+
+bool nRF52840Radio::fin(TxMode txMode, bool *crcErr)
+{
+  bool retv = false;
+
+  *crcErr = comError;
+
+  switch(txMode)
+   {
+     case txmBase:
+       break;
+
+     case txmRepStart:
+       break;
+
+     case txmRepCont:
+       break;
+
+     case txmRepEnd:
+       break;
+
+     case txmReadPrep:
+       break;
+
+     case txmReadS:
+       retv = comFin;
+       break;
+
+     case txmRead:
+       /*
+       if(NrfRadioPtr->EVENTS_END == 1)
+       {
+         NrfRadioPtr->EVENTS_END = 0;
+         retv = true;
+       }
+       else
+       {
+         if(NrfRadioPtr->STATE == NrfStRXIDLE)
+           retv = true;
+       }
+       */
+       retv = comFin;
+       break;
+
+     case txmPoll:
+       retv = comFin;
+       break;
+
+     case txmResp:
+       retv = comFin;
+       break;
+
+     case txmRespE:
+       if(NrfRadioPtr->STATE == NrfStDISABLED && !recMode)
+         retv = true;
+       break;
+   }
+  return(retv);
+}
+
+void nRF52840Radio::cont(TxMode txMode)
+{
+  switch(txMode)
+   {
+     case txmBase:
+       break;
+
+     case txmRepStart:
+       break;
+
+     case txmRepCont:
+       break;
+
+     case txmRepEnd:
+       break;
+
+     case txmReadPrep:
+       break;
+
+     case txmRead:
+       comFin = false;
+       NrfRadioPtr->TASKS_START = 1;
+       break;
+   }
+}
+
+int   nRF52840Radio::getRecData(bcPduPtr data, TxMode txMode, int max)
+{
+  byte *bPtr = (byte *) data;
+  int retv = 0;
+
+  switch(txMode)
+  {
+    case txmResp:
+      data->head = pduSentE[0];
+      retv = data->len  = pduSentE[1];
+
+      for(int i = 2; i < (retv + 2); i++)
+      {
+        if(i == max) break;
+        bPtr[i] = pduSentE[i];
+      }
+
+      break;
+
+    case txmBase:
+      break;
+
+    case txmRepStart:
+      break;
+
+    case txmRepCont:
+      break;
+
+    case txmRepEnd:
+      break;
+
+    case txmReadPrep:
+      break;
+
+    case txmRead:
+      break;
+  }
+
+
+  return(retv);
+}
+
+
+
+// ----------------------------------------------------------------------------
+//                      E m p f a n g e n
+// ----------------------------------------------------------------------------
+
+// Starten des Datenempfangs
+//
+int nRF52840Radio::startRec()
+{
+  int   retv;
+  NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+  NrfRadioPtr->EVENTS_READY = 0;
+  NrfRadioPtr->EVENTS_END = 0;
+  NrfRadioPtr->EVENTS_ADDRESS = 0;
+  NrfRadioPtr->EVENTS_PAYLOAD = 0;
+  NrfRadioPtr->EVENTS_CRCOK = 0;
+  NrfRadioPtr->EVENTS_CRCERROR = 0;
+  NrfRadioPtr->TASKS_RXEN = 1;                  // Anlauf Empfänger starten
+  retv = 8;
+  while(NrfRadioPtr->EVENTS_READY != 1) retv++; // Warten bis angelaufen
+  NrfRadioPtr->TASKS_START = 1;                 // Starten des Empfangs
+  return(retv + 1);
+}
+
+// Fortsetzen des Datenempfangs
+//
+int nRF52840Radio::contRec()
+{
+  NrfRadioPtr->EVENTS_END = 0;
+  NrfRadioPtr->EVENTS_ADDRESS = 0;
+  NrfRadioPtr->EVENTS_PAYLOAD = 0;
+  NrfRadioPtr->EVENTS_CRCOK = 0;
+  NrfRadioPtr->EVENTS_CRCERROR = 0;
+  NrfRadioPtr->TASKS_START = 1;                 // Starten des Empfangs
+  return(6);
+}
+
+// Beenden des Datenempfangs
+//
+int nRF52840Radio::endRec()
+{
+  int   retv;
+  NrfRadioPtr->EVENTS_DISABLED = 0;
+  NrfRadioPtr->EVENTS_END = 0;
+  NrfRadioPtr->EVENTS_ADDRESS = 0;
+  NrfRadioPtr->EVENTS_PAYLOAD = 0;
+  NrfRadioPtr->EVENTS_CRCOK = 0;
+  NrfRadioPtr->EVENTS_CRCERROR = 0;
+  NrfRadioPtr->TASKS_DISABLE = 1;               // Anlauf Empfänger beenden
+  retv = 7;
+  while(NrfRadioPtr->EVENTS_DISABLED != 1) retv++; // Warten bis abgelaufen
+  return(retv);
+}
+
+// Empfangszustand abfragen
+//
+int nRF52840Radio::checkRec()
+{
+  int retv = 0;
+
+  if(NrfRadioPtr->EVENTS_ADDRESS != 0)
+    retv |= RECSTAT_ADDRESS;
+
+  if(NrfRadioPtr->EVENTS_PAYLOAD != 0)
+    retv |= RECSTAT_PAYLOAD;
+
+  if(NrfRadioPtr->EVENTS_END != 0)
+    retv |= RECSTAT_END;
+
+  if(NrfRadioPtr->CRCSTATUS != 0)
+    retv |= RECSTAT_CRCOK;
+
+  if(NrfRadioPtr->EVENTS_DISABLED != 0)
+    retv |= RECSTAT_DISABLED;
+
+  return(retv);
+}
+
+int   nRF52840Radio::getRecData(bcPduPtr data, int max)
+{
+  int retv;
+  byte *bPtr = (byte *) data;
+
+  data->head = pduMem[0];
+  retv = data->len  = pduMem[1];
+
+  for(int i = 2; i < (retv + 2); i++)
+  {
+    if(i == max) break;
+    bPtr[i] = pduMem[i];
+  }
+
+  return(retv);
+}
+
+// ----------------------------------------------------------------------------
+// Interruptverarbeitung
+// ----------------------------------------------------------------------------
+//
+
+nRF52840Radio *nRF52840Radio::instPtr0 = NULL;
+
+void nRF52840Radio::irqHandler0()
+{
+  if(instPtr0 == NULL) return;
+  instPtr0->irqCounter++;
+  instPtr0->irqHandler();
+}
+
+void nRF52840Radio::irqHandler()
+{
+  statisticPtr->interrupts++;
+
+  switch(trfMode)
+  {
+    // ------------------------------------------------------------------------
+    case txmRead:               // Empty Polling für Master
+    // ------------------------------------------------------------------------
+
+      if((NrfRadioPtr->STATE & 0x08) != 0)  // Noch im Sendemodus
+      { // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_ADDRESS == 1)  // AC-Adr gesendet
+        {
+          NrfRadioPtr->EVENTS_ADDRESS = 0;    // nur quittieren
+        }
+
+        if(NrfRadioPtr->EVENTS_END == 1)      // Senden fertig
+        {
+          NrfRadioPtr->EVENTS_END = 0;        // nur quittieren
+          statisticPtr->sendings++;
+          memcpy(statisticPtr->memDumpSnd,pduMem,8);
+        }
+      }
+      else                                  // im Empfangsmodus
+      { // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_ADDRESS == 1)  // AC-Adr empfangen
+        {
+          NrfRadioPtr->EVENTS_ADDRESS = 0;    // quittieren
+          NrfRadioPtr->SHORTS = 0;            // Direktverbindungen löschen
+        }
+
+        if(NrfRadioPtr->EVENTS_END == 1)      // Empfang fertig
+        {
+          NrfRadioPtr->EVENTS_END = 0;        // nur quittieren
+          comFin = true;
+          statisticPtr->recs++;
+          memcpy(statisticPtr->memDumpRec,pduMem,8);
+        }
+      }
+
+      break;
+
+    // ------------------------------------------------------------------------
+    case txmPoll:     // Empty Polling und Datenempfang für Master -> DISABLED
+    // ------------------------------------------------------------------------
+      if(NrfRadioPtr->EVENTS_RXREADY == 1)    // Empfang aktiviert
+      {
+        NrfRadioPtr->EVENTS_RXREADY = 0;      // Int quittieren
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+        statisticPtr->sendings++;
+        memcpy(statisticPtr->memDumpSnd,pduMem,8);
+#endif
+        NrfRadioPtr->EVENTS_DISABLED = 0;     // Neu erwartet, zurücksetzen
+        NrfRadioPtr->SHORTS = NrfScEND_DISABLE | NrfScRXREADY_START;
+        NrfRadioPtr->INTENSET = NrfIntDISABLED;
+        recMode = true;
+      }
+
+      if(NrfRadioPtr->EVENTS_DISABLED == 1)   // Empfang beendet
+      {
+        NrfRadioPtr->EVENTS_DISABLED = 0;     // Int quittieren
+        comFin = true;
+        if(NrfRadioPtr->CRCSTATUS == 0)
+          comError = true;
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+        statisticPtr->recs++;
+        if(comError) statisticPtr->crcErrors++;
+        memcpy(statisticPtr->memDumpRec,pduMem,16);
+        if(!recMode)
+        {
+          // Das darf nicht passieren, sonst neue Int-Verarbeitung erforderlich
+          statisticPtr->intErrors++;
+        }
+#endif
+      }
+      break;
+
+    // ------------------------------------------------------------------------
+    case txmReadS:              // Datenübertragung für Master (Slave->Master)
+    // ------------------------------------------------------------------------
+
+      if(NrfRadioPtr->EVENTS_ADDRESS == 1)    // AC-Adr gesendet
+      {
+        NrfRadioPtr->EVENTS_ADDRESS = 0;      // quittieren
+
+        if((NrfRadioPtr->STATE & 0x08) != 0)  // im Sendezustand
+          break;                              // nichts weiter
+        // --------------------------------------------------------------------
+        else                                  // Im Empfangszustand
+        {
+          NrfRadioPtr->SHORTS = NrfScEND_DISABLE; // automatisch abschalten
+          NrfRadioPtr->INTENCLR = 0xFFFFFFFF;     // und nur noch DISABLED
+          NrfRadioPtr->INTENSET = NrfIntDISABLED; // Interrupt freischalten
+        }
+      }
+
+      if(NrfRadioPtr->EVENTS_DISABLED == 1)   // Übertragung fertig
+      {
+        NrfRadioPtr->EVENTS_DISABLED = 0;     // quittieren
+        comFin = true;
+      }
+
+
+      break;
+
+    // ----------------------------------------------------------------------
+    case txmRespE:              // Empty Polling für Slave
+    // ----------------------------------------------------------------------
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_END == 1)        // Übertragung beendet
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_END = 0;          // Event quittieren
+
+          if(recMode)                           // im Empfangsmodus
+          { // ----------------------------------------------------------------
+            NrfRadioPtr->SHORTS = 0;            // keine direkte Kopplung mehr
+
+            statisticPtr->recs++;
+            memcpy(statisticPtr->memDumpRec,pduMem,8);
+
+            // ----------------------------------------------------------------
+            // Reaktion
+            // ----------------------------------------------------------------
+            //
+            if((pduSentE[5] == pduMem[5]) && (pduSentE[6] == pduMem[6]) && (pduSentE[7] == pduMem[7]))
+            {
+              // Die richtige Protokollumgebung (z.B. Soaap)
+              //
+              if(pduSentE[2] != pduMem[2])
+              {
+                // aber die falsche Adresse
+                // Datenempfang fortsetzen
+                statisticPtr->wrongs++;
+                NrfRadioPtr->TASKS_START = 1;
+              }
+              else
+              { // richtige Adresse, Antwort schicken
+                // ------------------------------------------------------------
+                statisticPtr->pollNaks++;
+
+                // zunächst alle Funk-Interrupts sperren
+                NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+
+                // Interrupt freigeben für "Abgeschaltet"
+                NrfRadioPtr->INTENSET = NrfIntDISABLED;
+
+                // Empfangsbetrieb abschalten
+                NrfRadioPtr->TASKS_DISABLE = 1;
+              }
+
+            }
+            else
+            {
+              // Fremde Umgebung (nicht akzeptierte PDU)
+              // Datenempfang fortsetzen
+              statisticPtr->aliens++;
+              NrfRadioPtr->TASKS_START = 1;
+            }
+          }
+          else                                      // im Sendemodus
+          { // ----------------------------------------------------------------
+
+
+          }
+        }
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_DISABLED == 1)       // ausgeschaltet
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_DISABLED = 0;         // quittieren
+
+          if(recMode)
+          {
+            // zunächst alle Funk-Interrupts sperren
+            NrfRadioPtr->INTENCLR = 0xFFFFFFFF;
+
+            // Interrupt freigeben für "Abgeschaltet"
+            NrfRadioPtr->INTENSET = NrfIntDISABLED;
+
+            // Kopplung automatisch starten und abschalten nach Ende
+            NrfRadioPtr->SHORTS = NrfScREADY_START | NrfScEND_DISABLE;
+
+            NrfRadioPtr->TASKS_TXEN = 1;             // Sender einschalten
+            recMode = false;
+
+            // Daten in Funkpuffer kopieren
+            memcpy((void *)pduMem, (void *)pduSentE, sizeof(bcPdu));
+          }
+          else
+          {
+            NrfRadioPtr->SHORTS = 0;
+            statisticPtr->sendings++;
+          }
+        }
+
+        break;
+
+      // ----------------------------------------------------------------------
+      case txmResp:               // Datenübertragung Slave
+      // ----------------------------------------------------------------------
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_END == 1)        // Übertragung beendet
+                                                // Polling-Daten empfangen
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_END = 0;          // Event quittieren
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+          statisticPtr->recs++;
+          memcpy(statisticPtr->memDumpRec,pduMem,8);
+#endif
+
+          if((pduSentE[5] != pduMem[5]) || (pduSentE[6] != pduMem[6]) || (pduSentE[7] != pduMem[7]))
+          {
+            // Das empfangene Telegramm gehört nicht zum eigenen Netzwerk
+            //
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+            statisticPtr->aliens++;
+#endif
+            NrfRadioPtr->SHORTS = 0;            // Keine Direktverbindungen
+            NrfRadioPtr->TASKS_START = 1;       // Datenempfang fortsetzen
+            break;
+          }
+
+          if((pduSentE[2] != pduMem[2]) || ((pduSentE[3] & 0x3F) != (pduMem[3] & 0x3F)))
+          {
+            // Das empfangene Telegramm ist für einen anderen Slave oder Bereich
+            //
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+            statisticPtr->wrongs++;
+#endif
+            NrfRadioPtr->SHORTS = 0;            // Keine Direktverbindungen
+            NrfRadioPtr->TASKS_START = 1;       // Datenempfang fortsetzen
+            break;
+            // TODO
+            // Hier wird das Protokoll noch erweitert zum Belauschen anderer Slaves
+          }
+
+          eadM = ((pduMem[3] & SOAAP_EADR) != 0); // Merker für Empfangspolling
+          nakM = ((pduMem[3] & SOAAP_NAK) != 0);  // Merker für NAK-Polling
+
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+          if(nakM)
+            statisticPtr->pollNaks++;
+          else
+            statisticPtr->pollAcks++;
+#endif
+          if(eadM)
+          {
+            // Empfangsaufforderung
+            // Eadr-Nak-Daten in Funkpuffer kopieren
+            //
+            memcpy((void *)pduMem, (void *)pduSentE, sizeof(bcPdu));
+          }
+          else
+          {
+            // Sendeaufforderung
+            // Polling-Steuerdaten in Empfangspuffer und
+            // Sadr-Ack-Daten in Funkpuffer kopieren
+            //
+            memcpy((void *)pduSentE, (void *)pduMem, sizeof(bcPdu));
+            memcpy((void *)pduMem, (void *)pduSentS, sizeof(bcPdu));
+          }
+
+          // Setzen der Direktverbinder auf vollständigen Durchlauf bis Ende der Sendung
+          // ACHTUNG! Freigegebene Interrupts treten auf, auch wenn sie zu einer
+          //          Direktverbindung gehören.
+          //
+          NrfRadioPtr->SHORTS = NrfScDISABLED_TXEN | NrfScREADY_START | NrfScEND_DISABLE;
+          NrfRadioPtr->EVENTS_READY = 0;        // Evt. hängendes Ereignis löschen
+          NrfRadioPtr->INTENSET = NrfIntREADY;  // Int zur Vorbereitung des Sendeabschlusses
+          NrfRadioPtr->TASKS_DISABLE = 1;       // Abschalten des Empfangsbetriebs
+          break;
+        }
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_READY == 1)      // Bereit zum Senden
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_READY = 0;        // Event quittieren
+
+          // Vorbereiten auf das Ende der Sendung mit Abschalten
+          // NrfScREADY_START | NrfScEND_DISABLE sind weiter wirksam
+          //
+          NrfRadioPtr->SHORTS = NrfScREADY_START | NrfScEND_DISABLE;
+          NrfRadioPtr->EVENTS_DISABLED = 0;       // Evt. hängendes Ereignis löschen
+          recMode = false;
+          NrfRadioPtr->INTENSET = NrfIntDISABLED; // Int zum Sendeabschluss
+          break;
+        }
+
+        // --------------------------------------------------------------------
+        if(NrfRadioPtr->EVENTS_DISABLED == 1)   // Sendevorgang beendet
+        // --------------------------------------------------------------------
+        {
+          NrfRadioPtr->EVENTS_DISABLED = 0;     // Event quittieren
+          comFin = true;
+#if (defined smnDEBUG  && defined nRF52840RadioDEB)
+          statisticPtr->sendings++;
+          memcpy(statisticPtr->memDumpSnd,pduMem,16);
+#endif
+        }
+
+        break;
+
+  }
+}
+
+// --------------------------------------------------------------------------
+// Datenzugriffe
+// --------------------------------------------------------------------------
+//
+int   nRF52840Radio::getStatistics(TxStatisticsPtr dest)
+{
+  int retv = 0;
+
+  *dest = *statisticPtr;
+  return(retv);
+}
+
+int nRF52840Radio::getState()
+{
+  return(NrfRadioPtr->STATE);
+}
+
+// ----------------------------------------------------------------------------
+//                      D e b u g - H i l f e n
+// ----------------------------------------------------------------------------
+//
+int   nRF52840Radio::getPduMem(byte *dest, int start, int end)
+{
+  int i,j;
+
+  j = 0;
+
+  for(i = start; i < end; i++)
+  {
+    dest[j++] = pduMem[i];
+  }
+  return(j);
+}
+
+int   nRF52840Radio::getPduSent(byte *dest, int start, int end)
+{
+  int i,j;
+
+  j = 0;
+
+  for(i = start; i < end; i++)
+  {
+    dest[j++] = pduSentE[i];
+  }
+  return(j);
+}
+
+
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Radio/nRF52840Radio.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Radio/nRF52840Radio.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e61246043b8b3bd78928b3e33e31f81e180d011
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Radio/nRF52840Radio.h
@@ -0,0 +1,313 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Radio.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef NRF52840RADIO_H
+#define NRF52840RADIO_H
+
+#include "arduinoDefs.h"
+#include "bleSpec.h"
+#include "IntrfRadio.h"
+
+#define nRF52840RadioDEB
+
+// ----------------------------------------------------------------------------
+
+typedef struct _NRF_RADIO_Type
+{
+  volatile  dword  TASKS_TXEN;
+  volatile  dword  TASKS_RXEN;
+  volatile  dword  TASKS_START;
+  volatile  dword  TASKS_STOP;
+  volatile  dword  TASKS_DISABLE;
+  volatile  dword  TASKS_RSSISTART;
+  volatile  dword  TASKS_RSSISTOP;
+  volatile  dword  TASKS_BCSTART;
+  volatile  dword  TASKS_BCSTOP;
+  volatile  dword  TASKS_EDSTART;
+  volatile  dword  TASKS_EDSTOP;
+  volatile  dword  TASKS_CCASTART;
+  volatile  dword  TASKS_CCASTOP;
+  volatile  dword  RESERVED0[51];
+  volatile  dword  EVENTS_READY;
+  volatile  dword  EVENTS_ADDRESS;
+  volatile  dword  EVENTS_PAYLOAD;
+  volatile  dword  EVENTS_END;
+  volatile  dword  EVENTS_DISABLED;
+  volatile  dword  EVENTS_DEVMATCH;
+  volatile  dword  EVENTS_DEVMISS;
+  volatile  dword  EVENTS_RSSIEND;
+  volatile  dword  RESERVED1[2];
+  volatile  dword  EVENTS_BCMATCH;
+  volatile  dword  RESERVED2;
+  volatile  dword  EVENTS_CRCOK;
+  volatile  dword  EVENTS_CRCERROR;
+  volatile  dword  EVENTS_FRAMESTART;
+  volatile  dword  EVENTS_EDEND;
+  volatile  dword  EVENTS_EDSTOPPED;
+  volatile  dword  EVENTS_CCAIDLE;
+  volatile  dword  EVENTS_CCABUSY;
+  volatile  dword  EVENTS_CCASTOPPED;
+  volatile  dword  EVENTS_RATEBOOST;
+  volatile  dword  EVENTS_TXREADY;
+  volatile  dword  EVENTS_RXREADY;
+  volatile  dword  EVENTS_MHRMATCH;
+  volatile  dword  RESERVED3[2];
+  volatile  dword  EVENTS_SYNC;
+  volatile  dword  EVENTS_PHYEND;
+  volatile  dword  RESERVED4[36];
+  volatile  dword  SHORTS;
+  volatile  dword  RESERVED5[64];
+  volatile  dword  INTENSET;
+  volatile  dword  INTENCLR;
+  volatile  dword  RESERVED6[61];
+  volatile  dword  CRCSTATUS;
+  volatile  dword  RESERVED7;
+  volatile  dword  RXMATCH;
+  volatile  dword  RXCRC;
+  volatile  dword  DAI;
+  volatile  dword  PDUSTAT;
+  volatile  dword  RESERVED8[59];
+  volatile  dword  PACKETPTR;
+  volatile  dword  FREQUENCY;
+  volatile  dword  TXPOWER;
+  volatile  dword  MODE;
+  volatile  dword  PCNF0;
+  volatile  dword  PCNF1;
+  volatile  dword  BASE0;
+  volatile  dword  BASE1;
+  volatile  dword  PREFIX0;
+  volatile  dword  PREFIX1;
+  volatile  dword  TXADDRESS;
+  volatile  dword  RXADDRESSES;
+  volatile  dword  CRCCNF;
+  volatile  dword  CRCPOLY;
+  volatile  dword  CRCINIT;
+  volatile  dword  RESERVED9;
+  volatile  dword  TIFS;
+  volatile  dword  RSSISAMPLE;
+  volatile  dword  RESERVED10;
+  volatile  dword  STATE;
+  volatile  dword  DATAWHITEIV;
+  volatile  dword  RESERVED11[2];
+  volatile  dword  BCC;
+  volatile  dword  RESERVED12[39];
+  volatile  dword  DAB[8];
+  volatile  dword  DAP[8];
+  volatile  dword  DACNF;
+  volatile  dword  MHRMATCHCONF;
+  volatile  dword  MHRMATCHMAS;
+  volatile  dword  RESERVED13;
+  volatile  dword  MODECNF0;
+  volatile  dword  RESERVED14[3];
+  volatile  dword  SFD;
+  volatile  dword  EDCNT;
+  volatile  dword  EDSAMPLE;
+  volatile  dword  CCACTRL;
+  volatile  dword  RESERVED15[611];
+  volatile  dword  POWER;
+} *nrfRadioPtr;
+
+
+
+#define NrfRadioBase    0x40001000
+#define NrfRadioPtr     ((nrfRadioPtr) NrfRadioBase)
+
+#ifndef NrfPowerBase
+#define NrfPowerBase    0x40000000
+#define nrfPowerDCDCEN  ((dword *) 0x40000578)
+#endif
+
+#ifndef NrfClockBase
+#define NrfClockBase    0x40000000
+#define nrfClockTASKS_HFCLKSTART  ((dword *) 0x40000000)
+#endif
+
+// Direktverbindungen (shortcuts) zwischen events und Tasks
+//
+#define NrfScREADY_START    0x00000001
+#define NrfScEND_DISABLE    0x00000002
+#define NrfScDISABLED_TXEN  0x00000004
+#define NrfScDISABLED_RXEN  0x00000008
+#define NrfScTXREADY_START  0x00040000
+#define NrfScRXREADY_START  0x00080000
+
+// Interrupts
+//
+#define NrfIntREADY         0x00000001
+#define NrfIntADDRESS       0x00000002
+#define NrfIntPAYLOAD       0x00000004
+#define NrfIntEND           0x00000008
+#define NrfIntDISABLED      0x00000010
+#define NrfIntRSSIEND       0x00000080
+#define NrfIntTXREADY       0x00200000
+#define NrfIntRXREADY       0x00400000
+
+// Zustände
+//
+#define NrfStDISABLED       0
+#define NrfStRXRU           1
+#define NrfStRXIDLE         2
+#define NrfStRX             3
+#define NrfStRXDISABLE      4
+#define NrfStTXRU           9
+#define NrfStTXIDLE         10
+#define NrfStTX             11
+#define NrfStTXDISABLE      12
+
+// Festlegungen für die Paketkonfigurationsregister
+//
+
+#define PCNF0_LFLEN(x)    x
+// Anzahl der Bits im Längenfeld (0-15)
+
+#define PCNF0_S0LEN(x)    (x << 8)
+// Länge des Header0 (S0) in Bytes (0 oder 1)
+
+#define PCNF0_S1LEN(x)    (x << 16)
+// Länge des S1-Feldes in Bit (0 bis 15)
+
+#define PCNF1_MAXLEN(x)   x
+// Maximale Telegrammlänge (0 bis 255)
+
+#define PCNF1_BALEN(x)    (x << 16)
+// Basislänge der Zugriffsadresse (Access Address, 2-4)
+
+#define PCNF1_WHITEEN(x)  (x << 25)
+// Whitening (Bitmischung) Ein/Aus (1/0)
+
+// Festlegungen für die CRC-Generierung
+//
+
+#define CRCCNF_LEN(x)     x
+// Anzahl der Bytes für CRC (0-3)
+
+#define CRCCNF_SKIPADDR(x)  (x << 8)
+// Zugriffsadresse (Access Address) nicht im CRC (1), im CRC (0)
+
+
+typedef struct _nrf52840Cfg
+{
+  dword   pCnf0;
+  dword   pCnf1;
+  dword   whiteInit;
+  dword   modeCnf0;
+  dword   crcPoly;
+  dword   crcInit;
+  dword   crcCnf;
+  dword   packetPtr;
+  dword   frequency;
+  dword   txPower;
+  dword   mode;
+  dword   dacnf;
+  dword   rxAddrEn;
+  dword   base0;
+  dword   prefix0;
+  dword   txAddr;
+  dword   rxAddr;
+
+}nrf52840Cfg, *nrf52840CfgPtr;
+
+// ----------------------------------------------------------------------------
+
+class nRF52840Radio : IntrfRadio
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten
+  // --------------------------------------------------------------------------
+  //
+  byte        pduMem[256];
+  byte        pduSentE[256];
+  byte        pduSentS[256];
+
+  bcPduPtr    pmPtr;
+  bcPduPtr    pePtr;
+  bcPduPtr    psPtr;
+
+  nrf52840Cfg cfgData;
+
+  bool        recMode;
+  bool        eadM;
+  bool        nakM;
+  bool        comFin;
+  bool        comError;
+  bool        newValues;
+
+  dword       irqCounter;
+  TxMode      trfMode;
+
+  TxStatistics    statList[NrOfTxModes];
+  TxStatisticsPtr statisticPtr;
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen der Basis-Klasse
+  // --------------------------------------------------------------------------
+
+  nRF52840Radio();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  void  begin();
+  void  setAccessAddress(dword addr); // Setzen der Zugriffsadresse
+  void  setPacketParms(blePduType type);
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void  setChannel(int nr);           // Schalten physikalischer Kanal
+  int   sendSync(bcPduPtr inPduPtr, TxStatePtr refState);
+
+  void  send(bcPduPtr inPduPtr, TxMode txMode);
+  void  send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, bool newValues);
+  int   getRecData(bcPduPtr data, TxMode txMode, int max);  // Empfangene Daten lesen
+
+  void  disable(TxMode txMode);
+  bool  disabled(TxMode txMode);      // Abfrage, ob ausgeschaltet
+  void  cont(TxMode txMode);
+  bool  fin(TxMode txMode, bool *err);
+                                      // Senden eines Telegramms (und warten)
+  int   startRec();                   // Datenempfang starten
+  int   contRec();                    // Datenempfang fortsetzen
+  int   endRec();                     // Datenempfang beenden
+  int   checkRec();                   // Zustand Datenempfang feststellen
+  int   getRecData(bcPduPtr data, int max);  // Empfangene Daten lesen
+
+  void  setPower(int DBm);            // Leistung des Senders in DBm
+
+  void  readCheckCfg();               // Konfigurationsdaten auslesen
+
+  static  nRF52840Radio *instPtr0;
+  static  void irqHandler0();
+
+  void    irqHandler();
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  int   getStatistics(TxStatisticsPtr dest);
+  int   getState();
+
+  // ----------------------------------------------------------------------------
+  //                      D e b u g - H i l f e n
+  // ----------------------------------------------------------------------------
+  //
+  int   getPduMem(byte *dest, int start, int end);
+  int   getPduSent(byte *dest, int start, int end);
+
+
+};
+
+
+#endif // NRF52840RADIO_H
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Ser/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Ser/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..fa5d17537ce11418ad11ee8b2689c1ae0ba6a20b
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Ser/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Ser",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Ser/nRF52840Ser.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Ser/nRF52840Ser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..86b66bb6cd5ba3f8e3a58c8587d7df52eac240f5
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Ser/nRF52840Ser.cpp
@@ -0,0 +1,323 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Ser.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#include "nRF52840Ser.h"
+#include <string.h>
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+
+nRF52840Ser::nRF52840Ser()
+{
+  serPtr      = NULL;
+  instPtr0    = NULL;
+  irqCounter  = 0;
+  curIntEn    = 0;
+  curIRQ      = 0;
+  lastError   = 0;
+  cntError    = 0;
+}
+
+dword speedArr[18] =
+{
+    0x0004F000, 0x0009D000, 0x0013B000,
+    0x00275000, 0x003B0000, 0x004EA000,
+    0x0075F000, 0x00800000, 0x009D5000,
+    0x00E50000, 0x00EBF000, 0x013A9000,
+    0x01D7E000, 0x03AFB000, 0x04000000,
+    0x075F7000, 0x0EBED000, 0x10000000
+};
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+//
+void nRF52840Ser::begin(SerParamsPtr inParPtr, IntrfBuf *bufferIf)
+{
+  nrfGpioPtr  gpioPtr;
+  dword       regVal;
+
+  // Setzen des Peripheriezeigers anhand der Instanz
+  // und Initialisieren weiterer Variablen/Zeiger
+  //
+  serPtr = NrfSerPtr0;
+  clrAllEvents();
+  instPtr0  = this;
+  curIRQ    = 2;
+
+  // Interruptvektor setzen
+  //
+  __NVIC_SetVector((IRQn_Type) 2, (dword) nRF52840Ser::irqHandler0);
+  __NVIC_SetPriority((IRQn_Type) 2, 1);
+  __NVIC_EnableIRQ((IRQn_Type) 2);
+
+  // Alternative Peripherie (gleiche ID, also Alles) abschalten
+  //
+  serPtr->ENABLE = SerDisable;
+
+
+  // TxD
+  // -------------------------------------------------
+  //
+  // Pins zuweisen und initialisieren
+  //
+  if(inParPtr->txdPort == 1)
+  {
+    regVal = 32 + inParPtr->txdPin;
+    gpioPtr = NrfGpioPtr1;
+  }
+  else
+  {
+    regVal = inParPtr->txdPin;
+    gpioPtr = NrfGpioPtr0;
+  }
+
+
+  // Connect (hoechstwertiges Bit) beruecksichtigen
+  //
+  serPtr->PSEL_TXD = regVal | 0x7FFFFFC0;
+
+  // Zugewiesenen Pin als Ausgang schalten und Treibermodus setzen
+  // Laut Datenblatt ist das entsprechende Bit im Konfigurationsregister
+  // mit dem DIR-Register physikalisch verbunden
+  //
+  if(inParPtr->type == stStd)
+    regVal = GpioPinCnf_DRIVE(GpioDriveS0S1);
+  else if(inParPtr->type == stPow)
+    regVal = GpioPinCnf_DRIVE(GpioDriveH0H1);
+  else
+    regVal = GpioPinCnf_DRIVE(GpioDriveH0D1);
+
+  gpioPtr->PIN_CNF[inParPtr->txdPin] = regVal | GpioPinCnf_DIROUT;
+
+  // RXD
+  // -------------------------------------------------
+  //
+  if(inParPtr->rxdPort == 1)
+  {
+    regVal = 32 + inParPtr->rxdPin;
+    gpioPtr = NrfGpioPtr1;
+  }
+  else
+  {
+    regVal = inParPtr->rxdPin;
+    gpioPtr = NrfGpioPtr0;
+  }
+
+  // Connect (hoechstwertiges Bit) beruecksichtigen
+  //
+  serPtr->PSEL_RXD = regVal | 0x7FFFFFC0;
+
+  // Zugewiesenen Pin als Eingang schalten und Treibermodus setzen
+  // Laut Datenblatt ist das entsprechende Bit im Konfigurationsregister
+  // mit dem DIR-Register physikalisch verbunden
+  //
+  gpioPtr->PIN_CNF[inParPtr->rxdPin] = GpioPinCnf_PULL(GpioPullUp);
+
+  // Bitrate einstellen
+  //
+  regVal = speedArr[inParPtr->speed];
+  serPtr->BAUDRATE = regVal;
+  serPtr->SHORTS = 0;
+
+  // Interrupts freischalten
+  //
+  curIntEn = (SerInt_TXDRDY | SerInt_RXDRDY | SerInt_ERROR);
+  serPtr->INTENSET = curIntEn;
+
+  // Und bereit machen
+  //
+  serPtr->ENABLE = SerEnable;
+  txdFin = true;
+
+  bufIf = bufferIf;
+  delay(10);
+}
+
+
+// ----------------------------------------------------------------------------
+// Steuerfunktionen, gezielte Prozessorzugriffe und Hilfsfunktionen
+// ----------------------------------------------------------------------------
+//
+void nRF52840Ser::clrAllEvents()
+{
+  serPtr->EVENTS_RXDRDY     = 0;
+  serPtr->EVENTS_TXDRDY     = 0;
+  serPtr->EVENTS_ERROR      = 0;
+}
+
+// Fortsetzen des Interrupt-Sendebetriebs
+//
+void nRF52840Ser::resuSend()
+{
+  byte  td;
+
+  if(!txdFin) return;
+  if(bufIf == NULL) return;
+  if(!bufIf->getByteSnd(&td)) return;
+
+  txdFin = false;
+  serPtr->EVENTS_TXDRDY = 0;
+  serPtr->TXD = td;
+}
+
+// Starten des Sendebetriebs
+//
+void nRF52840Ser::startSend()
+{
+  serPtr->TASKS_STARTTX = 1;
+}
+
+// Anhalten des Sendebetriebs
+//
+void nRF52840Ser::stopSend()
+{
+  serPtr->TASKS_STOPTX = 1;
+}
+
+// Starten des Empfangsbetriebs
+//
+void nRF52840Ser::startRec()
+{
+  serPtr->TASKS_STARTRX = 1;
+}
+
+// Anhalten des Empfangsbetriebs
+//
+void nRF52840Ser::stopRec()
+{
+  serPtr->TASKS_STOPRX = 1;
+}
+
+
+// Bedingtes Ausgeben eines Zeichens
+//
+bool nRF52840Ser::condSend(byte c)
+{
+  if(!txdFin) return(false);
+
+  txdFin = false;
+  serPtr->EVENTS_TXDRDY = 0;
+  serPtr->TXD = c;
+  return(true);
+}
+
+// ----------------------------------------------------------------------------
+// Ereignisbearbeitung und Interrupts
+// ----------------------------------------------------------------------------
+//
+nRF52840Ser *nRF52840Ser::instPtr0 = NULL;
+
+void nRF52840Ser::irqHandler0()
+{
+  if(instPtr0 == NULL) return;
+  instPtr0->irqCounter++;
+  instPtr0->irqHandler();
+}
+
+
+  // --------------------------------------------------------------------------
+  // Interrupts (Ereignisbehandlung)
+  // --------------------------------------------------------------------------
+  //
+void nRF52840Ser::irqHandler()
+{
+  byte  b;
+
+  if(serPtr->EVENTS_TXDRDY != 0)
+  {
+    serPtr->EVENTS_TXDRDY = 0;
+    if(bufIf == NULL) return;
+
+    if(!bufIf->getByteSnd(&b))
+      txdFin = true;
+    else
+      serPtr->TXD = b;
+  }
+  else if(serPtr->EVENTS_RXDRDY != 0)
+  {
+    serPtr->EVENTS_RXDRDY = 0;
+    b = serPtr->RXD;
+    if(bufIf == NULL) return;
+    bufIf->putByteRec(b);
+  }
+  else if(serPtr->EVENTS_ERROR != 0)
+  {
+    serPtr->EVENTS_ERROR = 0;
+    cntError++;
+    lastError = serPtr->ERRORSRC;
+    anyError |= lastError;
+  }
+}
+
+// --------------------------------------------------------------------------
+// Datenzugriffe
+// --------------------------------------------------------------------------
+//
+// Letzten Fehler lesen (Bits)
+//
+int   nRF52840Ser::getLastError()
+{
+  return(lastError);
+}
+
+// Alle vorgekommenen Fehlerbits
+//
+int   nRF52840Ser::getAnyError()
+{
+  return(anyError);
+}
+
+// Anzahl der Fehler lesen
+//
+dword nRF52840Ser::getErrCount()
+{
+  return(cntError);
+}
+
+
+
+// ----------------------------------------------------------------------------
+//                      D e b u g - H i l f e n
+// ----------------------------------------------------------------------------
+//
+dword nRF52840Ser::getIrqCount()
+{
+  return(irqCounter);
+}
+
+void nRF52840Ser::resetIrqList()
+{
+  irqIdx = 0;
+  firstRead = true;
+
+  for(int i = 0; i < 8; i++)
+    irqList[i] = 0;
+}
+
+void nRF52840Ser::getIrqList(char *dest)
+{
+  int destIdx = 0;
+
+  for(int i = 0; i < 8; i++)
+  {
+    if(irqList[i] == 0) break;
+
+    dest[destIdx++] = ' ';
+    dest[destIdx++] = irqList[i] + 0x30;
+  }
+
+  dest[destIdx] = '\0';
+}
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Ser/nRF52840Ser.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Ser/nRF52840Ser.h
new file mode 100644
index 0000000000000000000000000000000000000000..37fcae4b19bc8ec15a2a83040f6f086d35e68efd
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Ser/nRF52840Ser.h
@@ -0,0 +1,234 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Ser.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef NRF52840SER_H
+#define NRF52840SER_H
+
+#include "Arduino.h"
+#include "arduinoDefs.h"
+#include "IntrfBuf.h"
+#include "IntrfSerial.h"
+
+// ----------------------------------------------------------------------------
+
+typedef struct _nrfSer
+{
+  volatile  dword  TASKS_STARTRX;           // 000
+  volatile  dword  TASKS_STOPRX;            // 004
+  volatile  dword  TASKS_STARTTX;           // 008
+  volatile  dword  TASKS_STOPTX;            // 00C
+  volatile  dword  Reserve01[3];            // 010
+  volatile  dword  TASKS_SUSPEND;           // 01C
+  volatile  dword  Reserve02[56];           // 020
+  volatile  dword  EVENTS_CTS;              // 100
+  volatile  dword  EVENTS_NCTS;             // 104
+  volatile  dword  EVENTS_RXDRDY;           // 108
+  volatile  dword  Reserve03[4];            // 10C
+  volatile  dword  EVENTS_TXDRDY;           // 11C
+  volatile  dword  Reserve04;               // 120
+  volatile  dword  EVENTS_ERROR;            // 124
+  volatile  dword  Reserve05[7];            // 128
+  volatile  dword  EVENTS_RXTO;             // 144
+  volatile  dword  Reserve06[46];           // 148
+  volatile  dword  SHORTS;                  // 200
+  volatile  dword  Reserve07[64];           // 204
+  volatile  dword  INTENSET;                // 304
+  volatile  dword  INTENCLR;                // 308
+  volatile  dword  Reserve08[93];           // 30C
+  volatile  dword  ERRORSRC;                // 480
+  volatile  dword  Reserve09[31];           // 484
+  volatile  dword  ENABLE;                  // 500
+  volatile  dword  Reserve10;               // 504
+  volatile  dword  PSEL_RTS;                // 508
+  volatile  dword  PSEL_TXD;                // 50C
+  volatile  dword  PSEL_CTS;                // 510
+  volatile  dword  PSEL_RXD;                // 514
+  volatile  dword  RXD;                     // 518
+  volatile  dword  TXD;                     // 51C
+  volatile  dword  Reserve11;               // 520
+  volatile  dword  BAUDRATE;                // 524
+  volatile  dword  Reserve12[17];           // 528
+  volatile  dword  CONFIG;                  // 56C
+} nrfSer, *nrfSerPtr;
+
+#define NrfSerBase0   0x40002000
+#define NrfSerPtr0    ((nrfSerPtr) NrfSerBase0)
+
+#ifndef nrfGpioDef
+
+typedef struct _nrfGpio
+{
+  volatile  dword Reserve01;                // 000
+  volatile  dword OUT;                      // 004
+  volatile  dword OUTSET;                   // 008
+  volatile  dword OUTCLR;                   // 00C
+  volatile  dword IN;                       // 010
+  volatile  dword DIR;                      // 014
+  volatile  dword DIRSET;                   // 018
+  volatile  dword DIRCLR;                   // 01C
+  volatile  dword LATCH;                    // 020
+  volatile  dword DETECTMODE;               // 024
+  volatile  dword Reserve02[118];           // 026
+  volatile  dword PIN_CNF[32];              // 200
+} nrfGpio, *nrfGpioPtr;
+
+#define NrfGpioBase   0x50000000
+#define NrfGpioBase0  0x50000500
+#define NrfGpioPtr0   ((nrfGpioPtr) NrfGpioBase0)
+#define NrfGpioBase1  0x50000800
+#define NrfGpioPtr1   ((nrfGpioPtr) NrfGpioBase1)
+
+#define GpioPinCnf_DIROUT     ((dword) 0x00000001)
+
+#define GpioPinCnf_DISBUF     ((dword) 0x00000002)
+
+#define GpioPinCnf_PULL(x)    ((dword) x << 2)
+#define GpioPullDown          1
+#define GpioPullUp            3
+
+#define GpioPinCnf_DRIVE(x)   ((dword) x << 8)
+#define GpioDriveS0S1         0
+#define GpioDriveH0S1         1
+#define GpioDriveS0H1         2
+#define GpioDriveH0H1         3
+#define GpioDriveD0S1         4
+#define GpioDriveD0H1         5
+#define GpioDriveS0D1         6
+#define GpioDriveH0D1         7
+
+#define GpioPinCnf_SENSE(x)   ((dword) x << 16)
+#define GpioSenseHigh         2
+#define GpioSenseLow          3
+
+#define nrfGpioDef
+#endif
+
+// Festlegungen für die Paketkonfigurationsregister
+//
+
+#define SerInt_RXDRDY     ((dword) 0x00000001 << 2)
+// Interrupt für Event RXDRDY
+
+#define SerInt_TXDRDY     ((dword) 0x00000001 << 7)
+// Interrupt für Event TXDRDY
+
+#define SerInt_ERROR      ((dword) 0x00000001 << 9)
+// Interrupt für Event ERROR
+
+
+#define SerEnable   4
+#define SerDisable  0
+
+// Bit-Masken fuer Kommunikationsbedingungen
+//
+#define BM_REC_NOT_COND 0x00
+// Keine Bedingungen beim Empfang
+#define BM_REC_END_CHR  0x01
+// Empfang Stoppen beim Eintreffen des vorgegebenen Zeichens
+#define BM_REC_RINGBUF  0x02
+// Receive characters in ring buffer
+#define BM_SND_RINGBUF  0x04
+// Transmit characters via ring buffer
+
+
+
+// ----------------------------------------------------------------------------
+
+class nRF52840Ser : IntrfSerial
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten und Funktionen
+  // --------------------------------------------------------------------------
+  //
+  nrfSerPtr     serPtr;
+  dword         irqCounter;
+
+  int           lastError;
+  int           anyError;
+  dword         cntError;
+
+  int           curIRQ;
+  dword         curIntEn;
+
+  IntrfBuf      *bufIf;
+  bool          txdFin;       // TRUE = Sendevorgang beendet
+
+  void clrAllEvents();
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen der Basis-Klasse
+  // --------------------------------------------------------------------------
+
+  nRF52840Ser();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  void begin(SerParamsPtr serParPtr, IntrfBuf *bufferIf);
+
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+  void resuSend();    // Fortsetzen des Interrupt-Sendebetriebs
+  void startSend();   // Starten des Sendebetriebs
+  void stopSend();    // Anhalten des Sendebetriebs
+
+  void startRec();    // Starten des Empfangsbetriebs
+  void stopRec();     // Anhalten des Empfangsbetriebs
+
+
+  // --------------------------------------------------------------------------
+  // Datenzugriffe
+  // --------------------------------------------------------------------------
+  //
+  bool condSend(byte c);  // Bedingtes Senden eines Zeichens
+
+  int   getLastError();   // Letzten Fehler lesen (Bits)
+  int   getAnyError();    // Alle vorgekommenen Fehlerbits
+  dword getErrCount();    // Anzahl der Fehler lesen
+
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
+  static  nRF52840Ser *instPtr0;
+  static  void irqHandler0();
+
+  void    irqHandler();
+
+  // --------------------------------------------------------------------------
+  // lokale Variablen
+  // --------------------------------------------------------------------------
+  //
+
+
+  // ----------------------------------------------------------------------------
+  //                      D e b u g - H i l f e n
+  // ----------------------------------------------------------------------------
+  //
+  int           irqIdx;
+  int           irqList[8];
+
+  byte          extraValue;
+  bool          firstRead;
+
+  dword   getIrqCount();
+  void    resetIrqList();
+  void    getIrqList(char *dest);
+
+};
+
+#endif // NRF52840SER_H
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Twi/library.json b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Twi/library.json
new file mode 100644
index 0000000000000000000000000000000000000000..16ae3922cdc02214ba2709422d1f9acfa86d132d
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Twi/library.json
@@ -0,0 +1,4 @@
+{
+  "name": "nRF52840Twi",
+  "version": "0.0.0+20220823165932"
+}
\ No newline at end of file
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Twi/nRF52840Twi.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Twi/nRF52840Twi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..81fdb263721b902935a3a21f952b214796e8c9d5
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Twi/nRF52840Twi.cpp
@@ -0,0 +1,586 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Radio.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#include "nRF52840Twi.h"
+#include <string.h>
+
+// ----------------------------------------------------------------------------
+// Initialisierungen
+// ----------------------------------------------------------------------------
+
+nRF52840Twi::nRF52840Twi()
+{
+  twiPtr      = NULL;
+  instPtr0    = NULL;
+  instPtr1    = NULL;
+  irqCounter  = 0;
+}
+
+// ----------------------------------------------------------------------------
+// Konfiguration
+// ----------------------------------------------------------------------------
+//
+TwiError nRF52840Twi::begin(TwiParamsPtr inParPtr)
+{
+  TwiError    retv;
+  nrfGpioPtr  gpioPtr;
+  dword       regVal;
+
+  retv = TEnoError;
+
+  params = *inParPtr;
+
+  // Setzen des Peripheriezeigers anhand der Instanz
+  // und Initialisieren weiterer Variablen/Zeiger
+  //
+  if(inParPtr->inst == 0)
+  {
+    twiPtr    = NrfTwiPtr0;
+    clrAllEvents();
+    instPtr0  = this;
+    curIRQ    = 3;
+
+    // Interruptvektor setzen
+    //
+    __NVIC_SetVector((IRQn_Type) 3, (dword) nRF52840Twi::irqHandler0);
+    __NVIC_SetPriority((IRQn_Type) 3, 1);
+    __NVIC_EnableIRQ((IRQn_Type) 3);
+  }
+  else
+  {
+    twiPtr    = NrfTwiPtr1;
+    clrAllEvents();
+    instPtr1  = this;
+    curIRQ    = 4;
+
+    // Interruptvektor setzen
+    //
+    __NVIC_SetVector((IRQn_Type) 4, (dword) nRF52840Twi::irqHandler1);
+    __NVIC_SetPriority((IRQn_Type) 4, 1);
+    __NVIC_EnableIRQ((IRQn_Type) 4);
+  }
+
+  // Alternative Peripherie (gleiche ID, also Alles) abschalten
+  //
+  twiPtr->ENABLE = TwiDisable;
+
+
+  // Takt
+  // -------------------------------------------------
+  //
+  // Pins zuweisen und initialisieren
+  //
+  if(inParPtr->clkPort == 1)
+  {
+    regVal = 32 + inParPtr->clkPin;
+    gpioPtr = NrfGpioPtr1;
+  }
+  else
+  {
+    regVal = inParPtr->clkPin;
+    gpioPtr = NrfGpioPtr0;
+  }
+
+  // Connect (hoechstwertiges Bit) beruecksichtigen
+  //
+  twiPtr->PSEL_SCL = regVal | 0x7FFFFFC0;
+
+  // Zugewiesenen Pin als Eingang schalten und Treibermodus setzen
+  // Laut Datenblatt ist das entsprechende Bit im Konfigurationsregister
+  // mit dem DIR-Register physikalisch verbunden
+  //
+  gpioPtr->PIN_CNF[inParPtr->clkPin] = GpioPinCnf_DRIVE(GpioDriveS0D1);
+
+  // Daten
+  // -------------------------------------------------
+  //
+  if(inParPtr->dataPort == 1)
+  {
+    regVal = 32 + inParPtr->dataPin;
+    gpioPtr = NrfGpioPtr1;
+  }
+  else
+  {
+    regVal = inParPtr->dataPin;
+    gpioPtr = NrfGpioPtr0;
+  }
+
+  // Connect (hoechstwertiges Bit) beruecksichtigen
+  //
+  twiPtr->PSEL_SDA = regVal | 0x7FFFFFC0;
+
+  // Zugewiesenen Pin als Eingang schalten und Treibermodus setzen
+  // Laut Datenblatt ist das entsprechende Bit im Konfigurationsregister
+  // mit dem DIR-Register physikalisch verbunden
+  //
+  gpioPtr->PIN_CNF[inParPtr->dataPin] = GpioPinCnf_DRIVE(GpioDriveS0D1);
+
+  // Frequenz einstellen
+  //
+  if(inParPtr->speed == Twi100k)
+    regVal = NrfTwi100k;
+  else if(inParPtr->speed == Twi400k)
+    regVal = NrfTwi400k;
+  else
+    regVal = NrfTwi250k;
+
+  twiPtr->FREQUENCY = regVal;
+
+  twiPtr->SHORTS = 0;
+
+  // Interrupts freischalten
+  //
+  curIntEn = (TwiInt_TXDSENT | TwiInt_RXDREADY | TwiInt_ERROR | TwiInt_STOPPED);
+  twiPtr->INTENSET = curIntEn;
+
+  // Und bereit machen
+  //
+  twiPtr->ENABLE = TwiEnable;
+
+  delay(10);
+
+  return(retv);
+}
+
+
+void nRF52840Twi::getParams(TwiParamsPtr parPtr)
+{
+  *parPtr = params;
+}
+
+
+// ----------------------------------------------------------------------------
+// Steuerfunktionen, gezielte Prozessorzugriffe und Hilfsfunktionen
+// ----------------------------------------------------------------------------
+//
+void nRF52840Twi::clrAllEvents()
+{
+  twiPtr->EVENTS_STOPPED    = 0;
+  twiPtr->EVENTS_RXDREADY   = 0;
+  twiPtr->EVENTS_TXDSENT    = 0;
+  twiPtr->EVENTS_SUSPENDED  = 0;
+  twiPtr->EVENTS_BB         = 0;
+  twiPtr->EVENTS_ERROR      = 0;
+}
+
+// ----------------------------------------------------------------------------
+//                      M a s t e r
+// ----------------------------------------------------------------------------
+//
+
+  // --------------------------------------------------------------------------
+  // Datenaustausch
+  // --------------------------------------------------------------------------
+  //
+TwiError nRF52840Twi::sendByte(int adr, TwiBytePtr refByte)
+{
+  TwiError retv = TEnoError;
+  lastError     = 0;
+
+  resetIrqList();
+
+  byteStruPtr     = refByte;
+  twiPtr->ADDRESS = adr;
+
+  byteStruPtr->twiStatus  = TwStWrReq;
+  trfMode                 = ttmWriteByte;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = refByte->value;
+
+  return(retv);
+}
+
+TwiError nRF52840Twi::sendByteReg(int adr, int reg, TwiBytePtr refByte)
+{
+  TwiError retv = TEnoError;
+
+  //dynHand = &nRF52840Twi::irqHandler;
+
+  resetIrqList();
+
+  byteStruPtr     = refByte;
+  twiPtr->ADDRESS = adr;
+
+  byteStruPtr->twiStatus  = TwStWrReq;
+  trfMode                 = ttmWriteByteReg;
+  comIdx                  = 1;
+  irqIdx                  = 0;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = reg;
+
+  return(retv);
+}
+
+TwiStatus nRF52840Twi::writeByteReg(int adr, int reg, byte value)
+{
+  twiPtr->INTENCLR = curIntEn;
+
+  tmpByte.value = value;
+
+  sendByteReg(adr, reg, &tmpByte);
+
+  while(tmpByte.twiStatus != TwStFin)
+  {
+    irqHandler();
+
+    if(tmpByte.twiStatus & TwStError)
+      break;
+  }
+
+  twiPtr->INTENSET = curIntEn;
+
+  return(tmpByte.twiStatus);
+}
+
+
+TwiError nRF52840Twi::recByteReg(int adr, int reg, TwiBytePtr refByte)
+{
+  TwiError retv = TEnoError;
+
+  //dynHand = &nRF52840Twi::irqHandler;
+
+  byteStruPtr     = refByte;
+  twiPtr->ADDRESS = adr;
+
+  resetIrqList();
+
+  byteStruPtr->twiStatus  = TwStRdReq;
+  trfMode                 = ttmReadByteReg;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = reg;
+
+  return(retv);
+}
+
+int nRF52840Twi::readByteReg(int adr, int reg)
+{
+  twiPtr->INTENCLR = curIntEn;
+
+  recByteReg(adr, reg, &tmpByte);
+
+  while(tmpByte.twiStatus != TwStFin)
+  {
+    irqHandler();
+
+    if(tmpByte.twiStatus & TwStError)
+      break;
+  }
+
+  twiPtr->INTENSET = curIntEn;
+
+  if(tmpByte.twiStatus == TwStFin)
+    return(tmpByte.value);
+  else
+    return(-1);
+}
+
+
+TwiError nRF52840Twi::recByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq)
+{
+  TwiError retv = TEnoError;
+
+  byteSeqPtr      = refByteSeq;
+  comIdx          = 0;
+  twiPtr->ADDRESS = adr;
+
+  byteSeqPtr->twiStatus   = TwStRdReq;
+  trfMode                 = ttmReadByteRegSeq;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = reg;
+
+  return(retv);
+}
+
+TwiStatus nRF52840Twi::readByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq)
+{
+  byteSeqPtr      = refByteSeq;
+  comIdx          = 0;
+  twiPtr->ADDRESS = adr;
+
+  byteSeqPtr->twiStatus   = TwStRdReq;
+  trfMode                 = ttmReadByteRegSeq;
+
+  twiPtr->INTENCLR        = curIntEn;
+
+  twiPtr->TASKS_STARTTX   = 1;
+  twiPtr->TXD             = reg;
+
+  while(byteSeqPtr->twiStatus != TwStFin)
+  {
+    irqHandler();
+
+    if(byteSeqPtr->twiStatus & TwStError)
+      break;
+  }
+
+  twiPtr->INTENSET        = curIntEn;
+
+  return(byteSeqPtr->twiStatus);
+}
+
+// ----------------------------------------------------------------------------
+// Ereignisbearbeitung und Interrupts
+// ----------------------------------------------------------------------------
+//
+nRF52840Twi *nRF52840Twi::instPtr0 = NULL;
+
+void nRF52840Twi::irqHandler0()
+{
+  if(instPtr0 == NULL) return;
+  instPtr0->irqCounter++;
+  instPtr0->irqHandler();
+}
+
+nRF52840Twi *nRF52840Twi::instPtr1 = NULL;
+
+void nRF52840Twi::irqHandler1()
+{
+  if(instPtr1 == NULL) return;
+  instPtr1->irqCounter++;
+  instPtr1->irqHandler();
+}
+
+
+  // --------------------------------------------------------------------------
+  // Interrupts (Ereignisbehandlung)
+  // --------------------------------------------------------------------------
+  //
+void nRF52840Twi::irqHandler()
+{
+  switch(trfMode)
+  {
+    case ttmWriteByte:
+    // ------------------------------------------------------------------------
+
+      if(twiPtr->EVENTS_ERROR)
+      {
+        twiPtr->EVENTS_ERROR    = 0;
+        lastError               = twiPtr->ERRORSRC;
+        twiPtr->ERRORSRC        = (lastError & 0x06);   // Clear AdrNak/DataNak
+        byteStruPtr->twiStatus  = (TwiStatus) ( (int) TwStError + lastError);
+        twiPtr->TASKS_STOP      = 1;
+
+        irqList[irqIdx++] = 8;
+        return;
+      }
+
+      if(twiPtr->EVENTS_TXDSENT)
+      {
+        twiPtr->EVENTS_TXDSENT   = 0;
+        byteStruPtr->twiStatus   = TwStSent;
+        twiPtr->TASKS_STOP       = 1;
+
+        irqList[irqIdx++] = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_STOPPED)
+      {
+        twiPtr->EVENTS_STOPPED  = 0;
+        if(lastError == 0)
+          byteStruPtr->twiStatus  = TwStFin;
+
+        irqList[irqIdx++] = 3;
+        return;
+      }
+
+      break;
+
+    case ttmWriteByteReg:
+    // ------------------------------------------------------------------------
+
+      if(twiPtr->EVENTS_ERROR)
+      {
+        twiPtr->EVENTS_ERROR    = 0;
+        lastError               = twiPtr->ERRORSRC;
+        twiPtr->ERRORSRC        = (lastError & 0x06);   // Clear AdrNak/DataNak
+        byteStruPtr->twiStatus  = (TwiStatus) ( (int) TwStError + lastError);
+        twiPtr->TASKS_STOP      = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_TXDSENT)
+      {
+        twiPtr->EVENTS_TXDSENT   = 0;
+        byteStruPtr->twiStatus   = TwStSent;
+        if(comIdx == 1)
+        {
+          comIdx = 0;
+          twiPtr->TXD = byteStruPtr->value;
+        }
+        else
+          twiPtr->TASKS_STOP    = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_STOPPED)
+      {
+        twiPtr->EVENTS_STOPPED  = 0;
+        if(lastError == 0)
+          byteStruPtr->twiStatus  = TwStFin;
+        return;
+      }
+
+      break;
+
+    case ttmReadByteReg:
+    // ------------------------------------------------------------------------
+
+      if(twiPtr->EVENTS_ERROR)
+      {
+        twiPtr->EVENTS_ERROR    = 0;
+        lastError               = twiPtr->ERRORSRC;
+        twiPtr->ERRORSRC        = (lastError & 0x06);   // Clear AdrNak/DataNak
+        byteStruPtr->twiStatus  = (TwiStatus) ( (int) TwStError + lastError);
+        twiPtr->TASKS_STOP      = 1;
+
+        irqList[irqIdx++] = 8;
+        return;
+      }
+
+      if(twiPtr->EVENTS_TXDSENT)
+      {
+        twiPtr->EVENTS_TXDSENT  = 0;
+        byteStruPtr->twiStatus  = TwStSent;
+        twiPtr->TASKS_STARTRX   = 1;
+        twiPtr->SHORTS          = 2;
+
+        irqList[irqIdx++] = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_STOPPED)
+      {
+        twiPtr->EVENTS_STOPPED  = 0;
+        if(lastError == 0)
+          byteStruPtr->twiStatus  = TwStFin;
+
+        irqList[irqIdx++] = 3;
+        twiPtr->SHORTS = 0;
+        return;
+      }
+
+      if(twiPtr->EVENTS_RXDREADY)
+      {
+        twiPtr->EVENTS_RXDREADY = 0;
+        byteStruPtr->twiStatus  = TwStRecvd;
+        byteStruPtr->value      = twiPtr->RXD;
+
+        irqList[irqIdx++] = 2;
+        return;
+      }
+
+      break;
+
+    case ttmReadByteRegSeq:
+    // ------------------------------------------------------------------------
+
+      if(twiPtr->EVENTS_ERROR)
+      {
+        twiPtr->EVENTS_ERROR    = 0;
+        lastError               = twiPtr->ERRORSRC;
+        twiPtr->ERRORSRC        = (lastError & 0x06);   // Clear AdrNak/DataNak
+        byteSeqPtr->twiStatus   = (TwiStatus) ( (int) TwStError + lastError);
+        twiPtr->TASKS_STOP      = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_TXDSENT)
+      {
+        twiPtr->EVENTS_TXDSENT  = 0;
+        byteSeqPtr->twiStatus   = TwStSent;
+        twiPtr->TASKS_STARTRX   = 1;
+        return;
+      }
+
+      if(twiPtr->EVENTS_STOPPED)
+      {
+        twiPtr->EVENTS_STOPPED   = 0;
+        if(lastError == 0)
+          byteSeqPtr->twiStatus  = TwStFin;
+        twiPtr->SHORTS = 0;
+        return;
+      }
+
+      if(twiPtr->EVENTS_RXDREADY)
+      {
+        twiPtr->EVENTS_RXDREADY       = 0;
+        byteSeqPtr->twiStatus         = TwStRecvd;
+        /*
+        if(comIdx == (byteSeqPtr->len - 2))
+          twiPtr->SHORTS              = 2;
+        byteSeqPtr->valueRef[comIdx]  = twiPtr->RXD;
+        if(comIdx < (byteSeqPtr->len - 1))
+          comIdx++;
+        */
+        if(comIdx == (byteSeqPtr->len - 2))
+          twiPtr->SHORTS              = 2;
+
+        lastIn = twiPtr->RXD;
+
+        if(comIdx < (byteSeqPtr->len))
+          byteSeqPtr->valueRef[comIdx]  = lastIn;
+
+        comIdx++;
+        return;
+      }
+
+      break;
+
+  }
+}
+
+// ----------------------------------------------------------------------------
+//                      S l a v e
+// ----------------------------------------------------------------------------
+
+// Starten des Datenempfangs
+//
+
+// ----------------------------------------------------------------------------
+//                      D e b u g - H i l f e n
+// ----------------------------------------------------------------------------
+//
+dword nRF52840Twi::getIrqCount()
+{
+  return(irqCounter);
+}
+
+void nRF52840Twi::resetIrqList()
+{
+  irqIdx = 0;
+  firstRead = true;
+
+  for(int i = 0; i < 8; i++)
+    irqList[i] = 0;
+}
+
+void nRF52840Twi::getIrqList(char *dest)
+{
+  int destIdx = 0;
+
+  for(int i = 0; i < 8; i++)
+  {
+    if(irqList[i] == 0) break;
+
+    dest[destIdx++] = ' ';
+    dest[destIdx++] = irqList[i] + 0x30;
+  }
+
+  dest[destIdx] = '\0';
+}
+
+
+
+
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Twi/nRF52840Twi.h b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Twi/nRF52840Twi.h
new file mode 100644
index 0000000000000000000000000000000000000000..e33ca74b72c254311a695ab5ea7fd3152a8ebf4d
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/nRF52840Twi/nRF52840Twi.h
@@ -0,0 +1,250 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Development Environment
+// Datei:   nRF52840Twi.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (wikipedia: Creative Commons)
+//
+
+#ifndef NRF52840TWI_H
+#define NRF52840TWI_H
+
+#include "Arduino.h"
+#include "arduinoDefs.h"
+#include "IntrfTw.h"
+
+// ----------------------------------------------------------------------------
+
+typedef struct _nrfTwi
+{
+  volatile  dword  TASKS_STARTRX;           // 000
+  volatile  dword  Reserve01;               // 004
+  volatile  dword  TASKS_STARTTX;           // 008
+  volatile  dword  Reserve02[2];            // 00C
+  volatile  dword  TASKS_STOP;              // 014
+  volatile  dword  Reserve03;               // 018
+  volatile  dword  TASKS_SUSPEND;           // 01C
+  volatile  dword  TASKS_RESUME;            // 020
+  volatile  dword  Reserve04[56];           // 024
+  volatile  dword  EVENTS_STOPPED;          // 104
+  volatile  dword  EVENTS_RXDREADY;         // 108
+  volatile  dword  Reserve05[4];            // 118
+  volatile  dword  EVENTS_TXDSENT;          // 11C
+  volatile  dword  Reserve06;               // 120
+  volatile  dword  EVENTS_ERROR;            // 124
+  volatile  dword  Reserve07[4];            // 128
+  volatile  dword  EVENTS_BB;               // 138
+  volatile  dword  Reserve08[3];            // 13C
+  volatile  dword  EVENTS_SUSPENDED;        // 148
+  volatile  dword  Reserve09[45];           // 14C
+  volatile  dword  SHORTS;                  // 200
+  volatile  dword  Reserve10[64];           // 204
+  volatile  dword  INTENSET;                // 304
+  volatile  dword  INTENCLR;                // 308
+  volatile  dword  Reserve11[110];          // 30C
+  volatile  dword  ERRORSRC;                // 4C4
+  volatile  dword  Reserve12[14];           // 4C8
+  volatile  dword  ENABLE;                  // 500
+  volatile  dword  Reserve13;               // 504
+  volatile  dword  PSEL_SCL;                // 508
+  volatile  dword  PSEL_SDA;                // 50C
+  volatile  dword  Reserve14[2];            // 510
+  volatile  dword  RXD;                     // 518
+  volatile  dword  TXD;                     // 51C
+  volatile  dword  Reserve15;               // 520
+  volatile  dword  FREQUENCY;               // 524
+  volatile  dword  Reserve16[24];           // 528
+  volatile  dword  ADDRESS;                 // 588
+} nrfTwi, *nrfTwiPtr;
+
+#define NrfTwiBase0   0x40003000
+#define NrfTwiPtr0    ((nrfTwiPtr) NrfTwiBase0)
+#define NrfTwiBase1   0x40004000
+#define NrfTwiPtr1    ((nrfTwiPtr) NrfTwiBase1)
+
+#define NrfTwi100k    0x01980000
+#define NrfTwi250k    0x04000000
+#define NrfTwi400k    0x06680000
+
+typedef enum _TwiTrfMode
+{
+  ttmWriteByte = 1,
+  ttmWriteByteReg,
+  ttmReadByteReg,
+  ttmReadByteRegSeq
+} TwiTrfMode;
+
+#ifndef nrfGpioDef
+
+typedef struct _nrfGpio
+{
+  volatile  dword Reserve01;                // 000
+  volatile  dword OUT;                      // 004
+  volatile  dword OUTSET;                   // 008
+  volatile  dword OUTCLR;                   // 00C
+  volatile  dword IN;                       // 010
+  volatile  dword DIR;                      // 014
+  volatile  dword DIRSET;                   // 018
+  volatile  dword DIRCLR;                   // 01C
+  volatile  dword LATCH;                    // 020
+  volatile  dword DETECTMODE;               // 024
+  volatile  dword Reserve02[118];           // 026
+  volatile  dword PIN_CNF[32];              // 200
+} nrfGpio, *nrfGpioPtr;
+
+#define NrfGpioBase   0x50000000
+#define NrfGpioBase0  0x50000500
+#define NrfGpioPtr0   ((nrfGpioPtr) NrfGpioBase0)
+#define NrfGpioBase1  0x50000800
+#define NrfGpioPtr1   ((nrfGpioPtr) NrfGpioBase1)
+
+#define GpioPinCnf_DIR        ((dword) 0x00000001)
+
+#define GpioPinCnf_INPUT      ((dword) 0x00000001 << 1)
+
+#define GpioPinCnf_PULL(x)    ((dword) x << 2)
+#define GpioPullDown          1
+#define GpioPullUp            3
+
+#define GpioPinCnf_DRIVE(x)   ((dword) x << 8)
+#define GpioDriveS0S1         0
+#define GpioDriveH0S1         1
+#define GpioDriveS0H1         2
+#define GpioDriveH0H1         3
+#define GpioDriveD0S1         4
+#define GpioDriveD0H1         5
+#define GpioDriveS0D1         6
+#define GpioDriveH0D1         7
+
+#define GpioPinCnf_SENSE(x)   ((dword) x << 16)
+#define GpioSenseHigh         2
+#define GpioSenseLow          3
+
+#define nrfGpioDef
+#endif
+
+// Festlegungen für die Paketkonfigurationsregister
+//
+
+#define TwiInt_STOPPED    ((dword) 0x00000001 << 1)
+// Interrupt für Event STOPPED
+
+#define TwiInt_RXDREADY   ((dword) 0x00000001 << 2)
+// Interrupt für Event RXDREADY
+
+#define TwiInt_TXDSENT    ((dword) 0x00000001 << 7)
+// Interrupt für Event TXDSENT
+
+#define TwiInt_ERROR      ((dword) 0x00000001 << 9)
+// Interrupt für Event ERROR
+
+#define TwiInt_BB         ((dword) 0x00000001 << 14)
+// Interrupt für Event BB
+
+#define TwiInt_SUSPENDED  ((dword) 0x00000001 << 18)
+// Interrupt für Event SUSPENDED
+
+#define TwiEnable   5
+#define TwiDisable  0
+
+
+
+
+// ----------------------------------------------------------------------------
+
+class nRF52840Twi : IntrfTw
+{
+private:
+  // --------------------------------------------------------------------------
+  // Lokale Daten und Funktionen
+  // --------------------------------------------------------------------------
+  //
+  nrfTwiPtr     twiPtr;
+  dword         irqCounter;
+
+  TwiBytePtr    byteStruPtr;
+  TwiWordPtr    wordStruPtr;
+  TwiByteSeqPtr byteSeqPtr;
+
+  TwiTrfMode    trfMode;
+  dword         lastError;
+  byte          lastIn;
+  int           comIdx;
+
+  int           curIRQ;
+  dword         curIntEn;
+
+  TwiByte       tmpByte;
+
+  TwiParams     params;
+
+  void clrAllEvents();
+
+public:
+  // --------------------------------------------------------------------------
+  // Initialisierungen der Basis-Klasse
+  // --------------------------------------------------------------------------
+
+  nRF52840Twi();
+
+  // --------------------------------------------------------------------------
+  // Konfigurationen
+  // --------------------------------------------------------------------------
+  //
+  TwiError begin(TwiParamsPtr inParPtr);
+  void getParams(TwiParamsPtr parPtr);
+
+
+  // --------------------------------------------------------------------------
+  // Steuerfunktionen
+  // --------------------------------------------------------------------------
+  //
+
+  // --------------------------------------------------------------------------
+  // Datenaustausch
+  // --------------------------------------------------------------------------
+  //
+  // asynchrone Kommunikation, Zustand in TwiByte.twiStatus
+  //
+  TwiError sendByte(int adr, TwiBytePtr refByte);
+  TwiError sendByteReg(int addr, int reg, TwiBytePtr refByte);
+  TwiError recByteReg(int addr, int reg, TwiBytePtr refByte);
+  TwiError recByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq);
+
+  // synchrone Kommunikation
+  //
+  TwiStatus writeByteReg(int adr, int reg, byte value);
+  int       readByteReg(int adr, int reg);
+  TwiStatus readByteRegSeq(int adr, int reg, TwiByteSeqPtr refByteSeq);
+
+  // ----------------------------------------------------------------------------
+  // Ereignisbearbeitung und Interrupts
+  // ----------------------------------------------------------------------------
+  //
+  static  nRF52840Twi *instPtr0;
+  static  void irqHandler0();
+
+  static  nRF52840Twi *instPtr1;
+  static  void irqHandler1();
+
+  void    irqHandler();
+
+  // ----------------------------------------------------------------------------
+  //                      D e b u g - H i l f e n
+  // ----------------------------------------------------------------------------
+  //
+  int           irqIdx;
+  int           irqList[8];
+
+  byte          extraValue;
+  bool          firstRead;
+
+  dword   getIrqCount();
+  void    resetIrqList();
+  void    getIrqList(char *dest);
+
+};
+
+#endif // NRF52840RADIO_H
+
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/template_platformio.txt b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/template_platformio.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bfec98771c70ca94f7c7c7198cb894d6330c8a09
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/template_platformio.txt
@@ -0,0 +1,32 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:nano33ble]
+platform = nordicnrf52
+board = nano33ble
+framework = arduino
+upload_port = COM5
+build_flags =
+	-DsmnDEFBYBUILD -DsmnNANOBLE33  -DsmnDEBUG ;-DSlaveACM3
+lib_deps = 
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\BlePoll
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\environment
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\ComRingBuf
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\LoopCheck
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\MidiNotes
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\Monitor
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Gpio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Radio
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Ser
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\nRF52840Twi
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SensorLSM9DS1
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapMsg
+	symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\StateMachine
+	;symlink://C:\Users\lenna\OneDrive\Dokumente\Git\SOAAP\libraries\SoaapComDue
diff --git a/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/test/README b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/test/README
new file mode 100644
index 0000000000000000000000000000000000000000..9b1e87bc67c90e7f09a92a3e855444b085c655a6
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/test/README
@@ -0,0 +1,11 @@
+
+This directory is intended for PlatformIO Test Runner and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PlatformIO Unit Testing:
+- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
diff --git a/sketches/_PIO_Sketches/README.md b/sketches/_PIO_Sketches/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a38fa89c3f61ca00246497ef2b7ba9e35902a5ed
--- /dev/null
+++ b/sketches/_PIO_Sketches/README.md
@@ -0,0 +1,12 @@
+Speicherort für PlatformIO projekte.
+
+Workflow:
+    -PlatformIO öffnen
+    -Projekt öffnen -> Projektordner wählen, in dem die platformio.ini liegt.
+    -platformio.ini anpassen:
+        Inhalt für die platformio.ini aus der template_platformio.txt kopieren.
+        Dabei den Pfad für die libraries für den jeweiligen Rechner anpassen.
+
+        
+Trotz implementierung in der .gitignore will git nachwievor die platformio.ini synchronisieren, obwohl das eigentlich nicht der Fall sein soll.
+Synchronisierung dieser ist aufgrund der unterschiedlichen Dateipfade nicht gewünscht.
\ No newline at end of file