diff --git a/libraries/BlePoll/BlePoll.cpp b/libraries/BlePoll/BlePoll.cpp
index 6a5758513a4d5470bb585843702aa8dfeba7f106..878c420cc61a195ee1a37fd8f130a84a298c79bb 100644
--- a/libraries/BlePoll/BlePoll.cpp
+++ b/libraries/BlePoll/BlePoll.cpp
@@ -205,10 +205,6 @@ void BlePoll::setPollAddress(int chnIn, int adrIn, int areaIn, bool masterIn, bo
   nak     = nakIn;
 }
 
-bcPduPtr BlePoll::getPduAdress(){
-  return &pduOut;
-}
-
 void BlePoll::setPduAddress()
 {
   setPduAddress(&pduOut);
diff --git a/libraries/environment/SoaapBleSlave.h b/libraries/environment/SoaapBleSlave.h
index f85448f1dfd6ad4eb777263bba7f7c1f61359650..f3ae7f7500126e35f19524b4188a3044d43dfaf4 100644
--- a/libraries/environment/SoaapBleSlave.h
+++ b/libraries/environment/SoaapBleSlave.h
@@ -1,7 +1,17 @@
 #ifndef SoaapBleSlave_h
 #define SoaapBleSlave_h
 
-#include "SoaapMsg.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);
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/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/src/main.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..138a3b7033e0e1f2c71e089f81f214d850350db3
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleMaster_Test_2/src/main.cpp
@@ -0,0 +1,674 @@
+// ----------------------------------------------------------------------------
+//                              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
+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
+
+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);
+
+#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 == '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/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/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/src/main.cpp b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a08a695470c1e17a573a33cbbaea07ca59419c6c
--- /dev/null
+++ b/sketches/_PIO_Sketches/Karger/SoaapBleSlave_Test_2/src/main.cpp
@@ -0,0 +1,853 @@
+// ----------------------------------------------------------------------------
+//                              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
+
+#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++] = 0;
+      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/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