diff --git a/libraries/BlePoll/BlePoll.cpp b/libraries/BlePoll/BlePoll.cpp
index 878c420cc61a195ee1a37fd8f130a84a298c79bb..a89524607616eaaa08301a29147ba9840e327336 100644
--- a/libraries/BlePoll/BlePoll.cpp
+++ b/libraries/BlePoll/BlePoll.cpp
@@ -69,6 +69,7 @@ void BlePoll::init(IntrfRadio *refRadio, dword inCycleMics, MicsecFuPtr inMicroF
   runCounter = 0;
   newValue = false;
   cbData = NULL;
+  lenPollCtrl = 0;
 
   for(int i = 1; i <= MAXSLAVE; i++)
   {
@@ -96,6 +97,8 @@ void BlePoll::begin(ComType typeIn, int adrIn, AppType appType, dword watchDog)
   // weil für jede Testanwendung spezifische Vorbereitungen gemacht wurden.
   // --------------------------------------------------------------------------
   //
+  PlpCtrl25Ptr ctrlPtr;
+
   wdTimeOut = watchDog;   // WatchDog-Time-Out in Mikrosekunden
 
   if(typeIn == ctMASTER)
@@ -122,14 +125,20 @@ void BlePoll::begin(ComType typeIn, int adrIn, AppType appType, dword watchDog)
     slaveIdx = adr;     // Reserve für getrennte Verwaltung von adr und slaveIdx
     next(smInit);
   }
-  else
+  else // Slave
   {
     nak = true;
     adr = adrIn;
     next(smInit);
   }
 
-  if(appType == atSOAAP || appType == atTestSend || appType == atDevSOAAP)
+  if
+    (
+        appType == atSOAAP1
+     || appType == atTestSend
+     || appType == atDevSOAAP
+     || appType == atSOAAP2
+    )
   {
     pduOut.adr5 = 0x53;
     pduOut.adr4 = 0x4F;
@@ -152,19 +161,54 @@ void BlePoll::begin(ComType typeIn, int adrIn, AppType appType, dword watchDog)
   pduOut.data[1] = appType;   // Pdu-Typ (TYPE)
   pduIn.data[1] = appType;
 
-  if(appType == atSOAAP)
+  if(appType == atSOAAP1)
   {
     if(master)
     {
       valuePdu.appId = plptMeas9Ctrl4;
-      ctrlPdu.appId = plptCtrlX;
+      ctrlPdu.appId = plptCtrl2;
       plMode = plmSoaapM;
       fullCycle = true;
     }
     else
     {
       valuePdu.appId = plptMeas9Ctrl4;
-      ctrlPdu.appId = plptCtrlX;
+      ctrlPdu.appId = plptCtrl2;
+      plMode = plmSoaapS;
+    }
+  }
+  else if(appType == atSOAAP2)
+  {
+    if(master)
+    {
+      // Bei atSOAAP2 wird die Übermittlung von Daten beim Sendeaufruf implementiert.
+      // Das erfordert eine spezifische Behandlung für jeden Slave.
+      // Die globalen Anweisungen sind obsolet und sollen demnächst eliminiert werden.
+      // (Vorher Auswertung kontrollieren).
+      //
+      valuePdu.appId = plptIMU3F4Ctrl4;
+      ctrlPdu.appId = plptCtrl2;
+      plMode = plmSoaapM;
+      fullCycle = true;
+
+      for(int i = 1; i <= MAXSLAVE; i++)
+      {
+        ctrlPtr = (PlpCtrl25Ptr) &slaveList[i].control;
+        ctrlPtr->counter = 0;
+        ctrlPtr->type = appType;
+        ctrlPtr->appId = plptCtrl2;
+        ctrlPtr->ctrlPath = 0;
+        ctrlPtr->ctrlCnt = 0;
+        ctrlPtr->reqAppId = plptIMU3F4Ctrl4;
+        ctrlPtr->ctrl[0] = 0;
+        ctrlPtr->ctrl[1] = 0;
+      }
+
+    }
+    else
+    {
+      valuePdu.appId = plptIMU3F4Ctrl4;
+      ctrlPdu.appId = plptCtrl2;
       plMode = plmSoaapS;
     }
   }
@@ -185,6 +229,8 @@ void BlePoll::begin(ComType typeIn, int adrIn, AppType appType, dword watchDog)
     }
   }
 
+  gAppId = (PlpType) valuePdu.appId;
+
   valuePdu.measCnt = 0;
   valuePdu.counter = 0;
   valuePdu.type = appType;
@@ -247,8 +293,6 @@ void BlePoll::setCbCtrlPtr(cbCtrlPtr cbPtr)
 
 
 dword smStartComESCnt;
-bcPdu recBeacon;
-int   lenBeacon = 0;
 
 // --------------------------------------------------------------------------
 // Hilfsfunktionen
@@ -301,6 +345,10 @@ bool BlePoll::getValues(bcPduPtr pduPtr, PlpType appId)
     case plptMeas9Ctrl4:
       pduPtr->len = sizeof(PlpM9C4) + 6;
       break;
+
+    case plptIMU3F4Ctrl4:
+      pduPtr->len = sizeof(PlpI3S4C4) + 6;
+      break;
   }
   pduPtr->data[0]++;      // Pdu-Counter
   pduPtr->data[1] = valuePdu.type;
@@ -320,13 +368,14 @@ bool BlePoll::getValues(bcPduPtr pduPtr, PlpType appId)
 bool BlePoll::getCtrls(bcPduPtr pduPtr, PlpType appId)
 {
   int   ctrlLen;
+  PlpI3S4C4Ptr  locPtr = (PlpI3S4C4Ptr) &pduPtr->data[0];
 
-  if(recBeacon.len > 6)
-    ctrlLen = recBeacon.len - 6;
+  if(pollCtrl.len > 6)
+    ctrlLen = pollCtrl.len - 6;
   else
     ctrlLen = 4;
 
-  newCtrl = cbCtrl((PlpType) appId, &pduPtr->data[22], &recBeacon.data[0], ctrlLen);
+  newCtrl = cbCtrl((PlpType) appId, &locPtr->ctrlPath, &pollCtrl.data[0], ctrlLen);
 
   return(newCtrl);
 }
@@ -902,12 +951,6 @@ void BlePoll::smStartCom()
     }
     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);
   }
   // --------------------------------------------
@@ -979,9 +1022,27 @@ void BlePoll::smReqComS()
   nak = false;          // Ist true, wenn keine Daten übertragen werden (empty poll)
   adr = curSlave->adr;
   area = curSlave->area;
-  setPduAddress();
+  setPduAddress(&pduOut);
   setTimeOut(curSlave->timeOut);
 
+  // Vorbereitung der mit dem Polling übermittelten Daten
+  //
+  //ctrlPdu.counter = 0;        // Zähler im Steuertelegramm
+  //ctrlPdu.appId = gAppId;     // Info für Slave zur Antwort
+
+
+  pduOut.len  = 14;           // Adresse (6) + 7 Byte Steuerung
+  ctrlPduPtr = (PlpCtrl25Ptr) &curSlave->control;
+
+  int dIdx = 0;
+  pduOut.data[dIdx++] = ctrlPduPtr->counter++;
+  pduOut.data[dIdx++] = ctrlPduPtr->type;
+  pduOut.data[dIdx++] = ctrlPduPtr->appId;
+  pduOut.data[dIdx++] = ctrlPduPtr->ctrlPath;
+  pduOut.data[dIdx++] = ctrlPduPtr->ctrlCnt;
+  pduOut.data[dIdx++] = ctrlPduPtr->reqAppId;
+  pduOut.data[dIdx++] = ctrlPduPtr->ctrl[0];
+  pduOut.data[dIdx++] = ctrlPduPtr->ctrl[1];
 
   // Statistic-Daten einholen für evt. Auswertung
   //
@@ -1115,6 +1176,20 @@ void BlePoll::smWaitAckComS()
         ((PlpM9C4Ptr) resPtr)->ctrl[1]  = pduIn.data[25];
         break;
 
+      case plptIMU3F4Ctrl4:
+        ((PlpI3S4C4Ptr) resPtr)->meas[0]  = *(float *) &pduIn.data[4];
+        ((PlpI3S4C4Ptr) resPtr)->meas[1]  = *(float *) &pduIn.data[8];
+        ((PlpI3S4C4Ptr) resPtr)->meas[2]  = *(float *) &pduIn.data[12];
+        ((PlpI3S4C4Ptr) resPtr)->state[0] = pduIn.data[16];
+        ((PlpI3S4C4Ptr) resPtr)->state[1] = pduIn.data[17];
+        ((PlpI3S4C4Ptr) resPtr)->state[2] = pduIn.data[18];
+        ((PlpI3S4C4Ptr) resPtr)->state[3] = pduIn.data[19];
+        ((PlpI3S4C4Ptr) resPtr)->ctrlPath = pduIn.data[20];
+        ((PlpI3S4C4Ptr) resPtr)->procCnt  = pduIn.data[21];
+        ((PlpI3S4C4Ptr) resPtr)->ctrl[0]  = pduIn.data[22];
+        ((PlpI3S4C4Ptr) resPtr)->ctrl[1]  = pduIn.data[23];
+        break;
+
       case plptMeas6:
         ((PlpM9C4Ptr) resPtr)->meas[0]  = *(word *) &pduIn.data[4];
         ((PlpM9C4Ptr) resPtr)->meas[1]  = *(word *) &pduIn.data[6];
@@ -1327,14 +1402,14 @@ void BlePoll::smStartComES()
 
   // Eintragen der Messwerte in das Sendetelegramm
   //
-  if(lenBeacon == 0)            // Wenn noch kein Empfangszyklus vorliegt
+  if(lenPollCtrl == 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
+    appId = pollCtrl.data[5];   // ansonsten der speziell angeforderte
 
   newValues = getValues(&pduOut, (PlpType) appId);
 
-  if((appId == plptMeas9Ctrl4) && (cbCtrl != NULL))
+  if((appId == plptMeas9Ctrl4 || appId == plptIMU3F4Ctrl4) && (cbCtrl != NULL))
     getCtrls(&pduOut, (PlpType) appId);
 
   radio->setChannel(chn);
@@ -1352,6 +1427,8 @@ void BlePoll::smWaitComES()
   radio->getStatistics(&statistic);
   if(timeOut())
   {
+    //TEST
+    lenPollCtrl = 2;
     next(smStartComES);
     return;
   }
@@ -1360,12 +1437,14 @@ void BlePoll::smWaitComES()
   //
   // Übertragung beendet, Daten empfangen (polling) und versendet (response)
   //
-  //lenBeacon = radio->getRecData(&recBeacon, txmResp, sizeof(recBeacon));
+  lenPollCtrl = radio->getRecData(&pollCtrl, txmResp, sizeof(pollCtrl));
+
   next(smStartComES);
 }
 
+// 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
 // --------------------------------------------------------------------------
-// Anwenderfunktionen
+// Anwenderfunktionen als Master
 // --------------------------------------------------------------------------
 //
 
@@ -1376,10 +1455,10 @@ 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;
+  if(nr > 26) return;
 
   SlavePtr  slavePtr = &slaveList[adr];
-  PlpCtrl27Ptr ctrlPtr = (PlpCtrl27Ptr) &slavePtr->control;
+  PlpCtrl25Ptr ctrlPtr = (PlpCtrl25Ptr) &slavePtr->control;
   for(int i = 0; i < nr; i++)
     ctrlPtr->ctrl[i] = ctrlList[i];
   ctrlPtr->ctrlCnt++;
@@ -1405,7 +1484,7 @@ bool BlePoll::ackControl(int adr)
   if(adr >= MAXSLAVE) return(false);
 
   SlavePtr  slavePtr = &slaveList[adr];
-  PlpCtrl27Ptr ctrlPtr = (PlpCtrl27Ptr) &slavePtr->control;
+  PlpCtrl25Ptr ctrlPtr = (PlpCtrl25Ptr) &slavePtr->control;
   if(ctrlPtr->ctrlCnt == slavePtr->rspCtrlCount)
     return(true);
   else
@@ -1485,6 +1564,10 @@ int BlePoll::getMeas(int slAdr, byte *dest)
       anzByte = 22;
       break;
 
+    case plptIMU3F4Ctrl4:
+      anzByte = 20;
+      break;
+
     case plptMeas13:
       anzByte = 26;
       break;
@@ -1502,7 +1585,68 @@ int BlePoll::getMeas(int slAdr, byte *dest)
   return(anzByte);
 }
 
+/*
+// Auslesen der Steuerwerte/Antwort
+//
+CtrlData2Ptr BlePoll::getCtrl(int slAdr)
+{
+
+  if(slAdr < 1) return(NULL);
+  if(slAdr >= MAXSLAVE) return(NULL);
+
+  SlavePtr  slavePtr = &slaveList[slAdr];
+  PlpI3S4C4Ptr dptr = (PlpI3S4C4Ptr) &slavePtr->result;
+  return((CtrlData2Ptr) &dptr->ctrlPath);
+}
+*/
+
+
+// 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
+// --------------------------------------------------------------------------
+// Anwenderfunktionen als Slave
+// --------------------------------------------------------------------------
+//
+bool BlePoll::getCtrlResp(int adr, CtrlResp2Ptr ctlRspPtr)
+{
+  PlpType   appId;
+  bool      retv = false;
+  SlavePtr  slPtr = &slaveList[adr];
+
+  appId = (PlpType) slPtr->result.plData[0];
+
+  switch(appId)
+  {
+    case plptMeas6:
+      break;
+
+    case plptMeas9:
+      break;
+
+    case plptMeas9Ctrl4:
+      ctlRspPtr->ctrlPath = ((PlpM9C4Ptr) &slPtr->result)->ctrlPath;
+      ctlRspPtr->procCnt  = ((PlpM9C4Ptr) &slPtr->result)->procCnt;
+      ctlRspPtr->ctrl[0]  = ((PlpM9C4Ptr) &slPtr->result)->ctrl[0];
+      ctlRspPtr->ctrl[1]  = ((PlpM9C4Ptr) &slPtr->result)->ctrl[1];
+      retv = true;
+      break;
+
+    case plptIMU3F4Ctrl4:
+      ctlRspPtr->ctrlPath = ((PlpI3S4C4Ptr) &slPtr->result)->ctrlPath;
+      ctlRspPtr->procCnt  = ((PlpI3S4C4Ptr) &slPtr->result)->procCnt;
+      ctlRspPtr->ctrl[0]  = ((PlpI3S4C4Ptr) &slPtr->result)->ctrl[0];
+      ctlRspPtr->ctrl[1]  = ((PlpI3S4C4Ptr) &slPtr->result)->ctrl[1];
+      retv = true;
+      break;
+
+    case plptMeas13:
+      break;
+
+    default:
+      break;
+  }
 
+  return(retv);
+}
 // --------------------------------------------------------------------------
 // Debugging
 // --------------------------------------------------------------------------
@@ -1574,6 +1718,13 @@ PollStatePtr  BlePoll::getPollPtr(int idx)
   return(&pollList[idx]);
 }
 
+int BlePoll::getCtrlData(byte *dest)
+{
+  byte *src = (byte *) &pollCtrl;
+  for(int i = 0; i < lenPollCtrl+2; i++)
+    dest[i] = src[i];
+  return(lenPollCtrl+2);
+}
 
 
 
diff --git a/libraries/BlePoll/BlePoll.h b/libraries/BlePoll/BlePoll.h
index 0a5cd9c66417896d310e87852550579e08511b3e..4abe53d334bb57d5692a0fe1cf202107172441e6 100644
--- a/libraries/BlePoll/BlePoll.h
+++ b/libraries/BlePoll/BlePoll.h
@@ -68,15 +68,19 @@ typedef struct _PlPduExtd   // grundsätzliche maximale Länge = 249 Bytes
   byte  plData[247];  // weitere spezifische Nutzdaten
 } PlPduExtd, *PlPduExtdPtr;
 
-// Datentypen (appId in plPduBase)
+// Datentypen (appId in plPduMeas)
 //
 typedef enum _PlpType
 {
   plptError,        // Fehler erkannt
-  plptEmpty,        // Leeres Telegramm (nur adresse)
+  plptEmpty,        // Leeres Telegramm (nur Adresse)
   plptBasic,        // Grundlegende Bytestruktur
+  plptIMU3F,        // 3 Messwerte Float (Roll-, Nick- und Gierwinkel)
+  plptIMU3F4Ctrl4,  // 3 Messwerte Float (Roll-, Nick- und Gierwinkel)
+                    // 4 Byte Status und 4 Byte Steuerung
   plptFullMeas,     // Maximale Belegung mit 16-Bit Messwerten (word)
   plptMeas3,        // 3 Messwerte (1 Raumsensor)
+  plptMeas3F,       // 3 Messwerte Float
   plptMeas6,        // 6 Messwerte (2 Raumsensoren)
   plptMeas9,        // 9 Messwerte (3 Raumsensoren)
   plptMeas9Ctrl4,   // 9 Messwerte + 4 Byte Steuerung
@@ -91,7 +95,25 @@ typedef enum _PlpType
   plptMsg           // (Quittierte) Meldung an Slave
 } PlpType, *PlpTypePtr;
 
+
+// Teilstrukturen für bestimmte Bearbeitungen
+//
+typedef struct _CtrlResp2
+{
+  byte    ctrlPath;   // Steuerungspfad (für Verzweigungen/Funktionen)
+  byte    procCnt;    // Prozesszähler
+  byte    ctrl[2];    // Inhalt Steuerungsantwort
+} CtrlResp2, *CtrlResp2Ptr;
+
+typedef struct _CtrlResp25
+{
+  byte    ctrlPath;   // Steuerungspfad (für Verzweigungen/Funktionen)
+  byte    procCnt;    // Prozesszähler
+  byte    ctrl[26];   // Inhalt Steuerungsantwort
+} CtrlResp25, *CtrlResp25Ptr;
+
 // Spezifische Datenstrukturen
+// Bezug zum Telegramm: bcPdu.data (bleSpec.h)
 //
 typedef struct _PlpFullMeas   // Ausnahme für vordefinierte Spezialfälle
 {
@@ -138,9 +160,22 @@ typedef struct _PlpM9C4      // Länge 26 (+ 6 Bytes Adresse)
   word    meas[9];    // Liste von 9 Messwerten
   byte    ctrlPath;   // Steuerungspfad (für Verzweigungen/Funktionen)
   byte    procCnt;    // Prozesszähler
-  byte    ctrl[2];    // Steuerungsdaten
+  byte    ctrl[2];    // Inhalt Steuerungsantwort
 } PlpM9C4, *PlpM9C4Ptr;
 
+typedef struct _PlpI3S4C4      // Länge 24 (+ 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
+  float   meas[3];    // Liste von 3 Float-Messwerten
+  byte    state[4];   // Gerätezustand
+  byte    ctrlPath;   // Steuerungspfad (Verzw./Fkt.)
+  byte    procCnt;    // Prozesszähler
+  byte    ctrl[2];    // Inhalt Steuerungsantwort
+} PlpI3S4C4, *PlpI3S4C4Ptr;
+
 typedef struct _PlpMeas12      // Länge 28 (+ 6 Bytes Adresse)
 {
   byte    counter;    // zyklischer Telegrammmzähler
@@ -159,25 +194,36 @@ typedef struct _PlpMeas13      // Länge 30 (+ 6 Bytes Adresse)
   word    meas[13];   // Liste von 13 Messwerten
 } PlpMeas13, *PlpMeas13Ptr;
 
-typedef struct _PlpCtrl2        // Länge 7 (+ 6 Bytes Adresse)
+// TODO
+// ----------------------------------------------------------------------------
+// Die folgenden Strukturen sind für (vollständige) Telegramme vom Master
+// zum Slave vorgesehen (Empfangsaufruf und Datenübertragung)
+// Das ist noch nicht richtig überlegt.
+// Zur Zeit werden sie zur Ergänzung des Sendeaufrufs verwendet
+// ----------------------------------------------------------------------------
+//
+
+typedef struct _PlpCtrl2        // Länge 8 (+ 6 Bytes Adresse)
 {
   byte    counter;    // zyklischer Telegrammmzähler
   byte    type;       // Kennzeichnung der Datenstruktur (AppType)
   byte    appId;      // Kennzeichnung für Dateninhalte (PlpType)
+  byte    ctrlPath;   // Steuerungspfad
   byte    ctrlCnt;    // Zähler für Kommandoaktualisierung
-  byte    procCnt;    // Zähler für Prozessaktualisierung
+  byte    reqAppId;   // Angeforderter Datentyp/Anwendung
   byte    ctrl[2];    // Liste von 2 Steuerbytes
 } PlpCtrl2, *PlpCtrl2Ptr;
 
-typedef struct _PlpCtrl27        // Länge 31 (+ 6 Bytes Adresse)
+typedef struct _PlpCtrl25        // 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    ctrlPath;   // Steuerungspfad
   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;
+  byte    reqAppId;   // Angeforderter Datentyp
+  byte    ctrl[25];   // Liste von bis zu 26 Steuerbytes
+} PlpCtrl25, *PlpCtrl25Ptr;
 
 // Identifikator für die Art der Daten
 //
@@ -186,6 +232,8 @@ typedef enum _MeasId
   app               // Gestaltung/Bedeutung der Daten aus Anwendung
 } MeasId, *MeasIdPtr;
 
+// Umgebungsspeicher für einen Slave
+//
 typedef struct _Slave
 {
   dword     timeOut;        // Wartezeit beim Polling in Mikrosekunden
@@ -255,7 +303,8 @@ public:
   {
     atDefault,        // Standard-Default-Anwendung
     atTestSend,       // einfacher Sendetest (Soaap)
-    atSOAAP,          // Steuerung optischer und akustischer Ausgaben für Performance-Künstler
+    atSOAAP1,         // Steuerung optischer und akustischer Ausgaben für Performance-Künstler
+    atSOAAP2,         // Version 2
     atDevSOAAP,       // Entwicklerbetrieb für SOAAP
     atDHA             // Dezentrale Hausautomatisierung
   } AppType;
@@ -282,6 +331,8 @@ private:
   IntrfRadio    *radio;
   bcPdu         pduOut;
   bcPdu         pduIn;
+  bcPdu         pollCtrl;
+  int           lenPollCtrl;
   cbVector      nextState;
   MicsecFuPtr   micSec;
   cbDataPtr     cbData;
@@ -332,7 +383,8 @@ private:
 
   TxStatistics  statistic;
   PlPduMeas     valuePdu;
-  PlpCtrl27     ctrlPdu;
+  PlpCtrl25     ctrlPdu;
+  PlpCtrl25Ptr  ctrlPduPtr;
   bool          newValue;
   bool          newCtrl;
 
@@ -342,6 +394,7 @@ private:
   int           epCycleTotal;   // Anzahl der leeren Pollings gesamt
   int           epCycleRun;     // Anzahl der leeren Pollings nach Kontakt
   dword         epTimeOut;      // Time-Out in Mikrosekunden
+  PlpType       gAppId;         // Anwendungs-Id zur Protokollsteuerung
 
 
   // --------------------------------------------------------------------------
@@ -430,7 +483,7 @@ public:
   void updControl(int adr, byte *ctrlList, int nr);   // neue Steuerungsdaten
   bool ackTrans(int adr);         // Bestätigung Steuerungsdaten übertragen
   bool ackControl(int adr);       // Bestätigung Steuerung ausgeführt
-
+  bool getCtrlResp(int adr, CtrlResp2Ptr ctlRspPtr);  // Antwort auf Steuerdaten holen
 
   // Test
   //
@@ -467,10 +520,10 @@ public:
   // 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
+  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
 
 
 
@@ -483,6 +536,7 @@ public:
 
   SlavePtr      getSlavePtr(int idx);
   PollStatePtr  getPollPtr(int idx);
+  int           getCtrlData(byte *dest);
 };
 
 
diff --git a/libraries/EulerAngles/EulerAngles.cpp b/libraries/EulerAngles/EulerAngles.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..94955536ad4fb7e6305491a9e4ade7000455bd46
--- /dev/null
+++ b/libraries/EulerAngles/EulerAngles.cpp
@@ -0,0 +1,53 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Calculations with Euler Angles
+// Datei:   EulerAngles.cpp
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (siehe Wikipedia: Creative Commons)
+//
+
+#include "EulerAngles.h"
+
+
+// ---------------------------------------------------------------------------
+// Konstruktoren und Initialisierungen
+// ---------------------------------------------------------------------------
+//
+EulerAngles::EulerAngles()
+{
+  minTanDenom = 0.0001;
+}
+
+// ---------------------------------------------------------------------------
+// Anwenderfunktionen
+// ---------------------------------------------------------------------------
+//
+float EulerAngles::getRollFromGravity(float accY, float accZ)
+{
+  if(accZ < 0)
+  {
+    if(accZ > - minTanDenom)
+      accZ = - minTanDenom;
+  }
+  else
+  {
+    if(accZ < minTanDenom)
+      accZ = minTanDenom;
+  }
+  return(atan2(accY,accZ));
+}
+
+float EulerAngles::getPitchFromGravity(float accX, float accY, float accZ)
+{
+  float denom;
+
+  denom = sqrt(accY * accY + accZ * accZ);
+  if(denom < minTanDenom)
+    denom = minTanDenom;
+
+  if(accZ < 0)
+    denom = - denom;
+
+  return(atan2(- accX, denom));
+}
diff --git a/libraries/EulerAngles/EulerAngles.h b/libraries/EulerAngles/EulerAngles.h
new file mode 100644
index 0000000000000000000000000000000000000000..7681c2678e664048aa8a9e95a8f259ba2df93e69
--- /dev/null
+++ b/libraries/EulerAngles/EulerAngles.h
@@ -0,0 +1,64 @@
+//-----------------------------------------------------------------------------
+// Thema:   Social Manufacturing Network / Calculations with Euler Angles
+// Datei:   EulerAngles.h
+// Editor:  Robert Patzke
+// URI/URL: www.mfp-portal.de
+//-----------------------------------------------------------------------------
+// Lizenz:  CC-BY-SA  (siehe Wikipedia: Creative Commons)
+//
+#ifndef _EulerAngles_h
+#define _EulerAngles_h
+//-----------------------------------------------------------------------------
+
+#include <math.h>
+
+// ---------------------------------------------------------------------------
+// class EulerAngles
+// ---------------------------------------------------------------------------
+//
+class EulerAngles
+{
+  // -------------------------------------------------------------------------
+  // Klassenspezifische Datentypen
+  // -------------------------------------------------------------------------
+  //
+
+private:
+  // -------------------------------------------------------------------------
+  // Lokale Variablen
+  // -------------------------------------------------------------------------
+  //
+  float minTanDenom;
+
+private:
+  // -------------------------------------------------------------------------
+  // Lokale Funktionen
+  // -------------------------------------------------------------------------
+  //
+
+public:
+  // -------------------------------------------------------------------------
+  // Konstruktoren und Initialisierungen
+  // -------------------------------------------------------------------------
+  //
+  EulerAngles();
+
+  // -------------------------------------------------------------------------
+  // Anwenderfunktionen
+  // -------------------------------------------------------------------------
+  //
+  float getRollFromGravity(float accY, float accZ);
+  float getPitchFromGravity(float accX, float accY, float accZ);
+
+  // -------------------------------------------------------------------------
+  // Debug-Funtionen
+  // -------------------------------------------------------------------------
+  //
+
+
+
+};
+
+//-----------------------------------------------------------------------------
+#endif  // _EulerAngles_h
+
diff --git a/libraries/Monitor/Monitor.cpp b/libraries/Monitor/Monitor.cpp
index 9c30d24b20011e8d22623c261a295ccfb42fe1ea..8efd09be53e5cf936cc9c48982671d990eb7d8f8 100644
--- a/libraries/Monitor/Monitor.cpp
+++ b/libraries/Monitor/Monitor.cpp
@@ -30,7 +30,7 @@ void Monitor::init(int inMode, int inCpu, LoopCheck *inLcPtr, IntrfTw *inTwPtr)
   blkOut        = false;
   blkIn         = false;
   inIdx         = 0;
-  info          = NULL;
+  infoMsg       = NULL;
   readOffsAddr  = 0;
   doReadReg     = false;
   extraIn       = false;
@@ -38,6 +38,24 @@ void Monitor::init(int inMode, int inCpu, LoopCheck *inLcPtr, IntrfTw *inTwPtr)
   twiPtr        = inTwPtr;
   nrOfChnChar   = '@';
 
+  helpMsg =
+  {
+  "Monitor 32-Bit ARM, Version 22.09.20\r\n"
+  "\r\n"
+  "C_  Lokale Steuerungen/Abfragen\r\n"
+  "cs  Anzeigen der Flags cFlag[]\r\n"
+  "cx  Invertieren der Flags cFlag[x], x=0...9\r\n"
+  "cfg Anzeigen der Konfiguration\r\n"
+  "\r\n"
+  "I_ Zugriff auf I2C-Bus\r\n"
+  "IA xx Setzen der Adresse\r\n"
+  "IL xxyy Lesen yy Bytes von Register xx\r\n"
+  "IR xx Lesen 1 Byte von Register xx\r\n"
+  "IW xxyy Schreiben yy an Register xx\r\n"
+  "\r\n"
+  };
+
+
 #ifdef smnNANOBLE33
 
   microTicValPtr  = (dword *) 0x40009548;
@@ -271,6 +289,20 @@ void Monitor::getKey()
           inChar[inIdx] = cin;
           inIdx++;
         }
+
+        else if(cin == 's' || cin == 'S')
+        {
+          inIdx = 0;
+          for(int i = 0; i < 10; i++)
+          {
+            out(' ');
+            out('c');
+            out(i);
+            out('=');
+            out(cFlag[i]);
+          }
+          GoPrm
+        }
       }
 
       else if(inIdx == 2)
@@ -286,6 +318,13 @@ void Monitor::getKey()
         GoPrm
       break;
 
+    case '?':
+    case 'H':
+    case 'h':
+      outl(" Info:");
+      nextState = &Monitor::help;
+      break;
+
     case 'i':
     case 'I':
       if(inIdx == 0)
@@ -423,9 +462,57 @@ void Monitor::prompt()
   GoInp
 }
 
+void Monitor::help()
+{
+  helpLen = helpPart = strlen(helpMsg);
+  helpIdx = 0;
+  nextState = &Monitor::helpOut;
+}
+
+void Monitor::helpOut()
+{
+  outn(&helpMsg[helpIdx],helpLen);
+  nextState = &Monitor::infoIni;
+}
+
+void Monitor::infoIni()
+{
+  if(infoMsg == NULL)
+  {
+    GoPrm
+    return;
+  }
+  infoLen = infoPart = strlen(infoMsg);
+  infoIdx = 0;
+  nextState = &Monitor::infoOut;
+}
+
+/*
+void Monitor::infoOut()
+{
+  int space;
+  space = outFree();
+  if(space == 0) return;
+
+  if((infoLen - infoIdx) < space)
+    space = infoLen - infoIdx;
+  outn(&info[infoIdx],space);
+  infoIdx += space;
+  if(infoIdx < infoLen) return;
+
+  GoPrm
+}
+*/
+void Monitor::infoOut()
+{
+  outn(&infoMsg[infoIdx],infoLen);
+  GoPrm
+}
+
+
 void Monitor::version()
 {
-  out("Monitor: Version 0.1, May 16, 2021");
+  out("Monitor: Version 0.2, September 20, 2022");
   GoPrm
 }
 
@@ -1135,7 +1222,7 @@ void Monitor::println(byte *iVal, int nr, char fill)
 
 void Monitor::setInfo(char *txt)
 {
-  info = txt;
+  infoMsg = txt;
 }
 
 void Monitor::config(int inNrOfChn)
diff --git a/libraries/Monitor/Monitor.h b/libraries/Monitor/Monitor.h
index 1ee2bb11830c716703e5489655355c93a039d131..3af0a9a81be4d60ca6a926b317892cb350b9bf47 100644
--- a/libraries/Monitor/Monitor.h
+++ b/libraries/Monitor/Monitor.h
@@ -23,8 +23,10 @@
 
 #define keyHit()  smnSerial.available()
 #define keyIn()   smnSerial.read()
+#define outFree() smnSerial.availableForWrite()
 #define out(x)    smnSerial.print(x)
 #define outl(x)   smnSerial.println(x)
+#define outn(x,y) smnSerial.write(x,y)
 #define GoInp     nextState = &Monitor::getKey;
 #define GoPrm     nextState = &Monitor::prompt;
 #define GoWt      nextState = &Monitor::waitEnter;
@@ -82,7 +84,15 @@ private:
   char      cmdMode1;
   char      cmdMode2;
 
-  char      *info;
+  char      *helpMsg;
+  int       helpLen;
+  int       helpPart;
+  int       helpIdx;
+
+  char      *infoMsg;
+  int       infoLen;
+  int       infoPart;
+  int       infoIdx;
 
   StatePtr  nextState;
   LoopCheck *lcPtr;
@@ -107,6 +117,10 @@ private:
   void  init(int mode, int cpu, LoopCheck *inLcPtr, IntrfTw *inTwPtr);
 
   void  waitEnter();
+  void  help();
+  void  helpOut();
+  void  infoIni();
+  void  infoOut();
   void  prompt();
   void  getKey();
   void  version();
diff --git a/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp b/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp
index 5a57198a5bb3b3c340ffa5a725f7f7c009725d9a..d08f0cb527a0ef965ecb104ba21e637eed30fd30 100644
--- a/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp
+++ b/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp
@@ -36,6 +36,10 @@ SensorLSM9DS1::SensorLSM9DS1(IntrfTw *refI2C, int inRunCycle)
   avgSetM     = 0;
   avgCntM     = 0;
 
+  signA   = 0;
+  signG   = 0;
+  signM   = 0;
+
   errorCntAdrNakAG    = 0;
   errorCntDataNakAG   = 0;
   errorCntOverAG      = 0;
@@ -448,6 +452,7 @@ void SensorLSM9DS1::resume()
   enableMeasM = true;
 }
 
+
 void SensorLSM9DS1::run()
 {
   runStateCntTotal++;
@@ -588,6 +593,8 @@ void SensorLSM9DS1::run()
           rawDataAG.valueAG.G.z = sumG.z / avgSetAG;
           sumA.x = sumA.y = sumA.z = sumG.x = sumG.y = sumG.z = 0;
           avgCntAG = avgSetAG;
+          markSigns(signA, rawDataAG.valueAG.A.x, rawDataAG.valueAG.A.y, rawDataAG.valueAG.A.z);
+          markSigns(signG, rawDataAG.valueAG.G.x, rawDataAG.valueAG.G.y, rawDataAG.valueAG.G.z);
           newValueAG = true;
         }
       }
@@ -599,6 +606,8 @@ void SensorLSM9DS1::run()
         rawDataAG.valueAG.G.x = comDataAG.valueAG.G.x;
         rawDataAG.valueAG.G.y = comDataAG.valueAG.G.y;
         rawDataAG.valueAG.G.z = comDataAG.valueAG.G.z;
+        markSigns(signA, rawDataAG.valueAG.A.x, rawDataAG.valueAG.A.y, rawDataAG.valueAG.A.z);
+        markSigns(signG, rawDataAG.valueAG.G.x, rawDataAG.valueAG.G.y, rawDataAG.valueAG.G.z);
         newValueAG = true;
       }
 
@@ -718,11 +727,13 @@ void SensorLSM9DS1::run()
           rawDataM.valueM.z = sumM.z / avgSetM;
           sumM.x = sumM.y = sumM.z = 0;
           avgCntM = avgSetM;
+          markSigns(signM, rawDataM.valueM.x, rawDataM.valueM.y, rawDataM.valueM.z);
           newValueM = true;
         }
       }
       else
       {
+        markSigns(signM, rawDataM.valueM.x, rawDataM.valueM.y, rawDataM.valueM.z);
         newValueM = true;
       }
 
@@ -762,6 +773,24 @@ void  SensorLSM9DS1::syncValuesAG()
   newValueAG = false;
 }
 
+bool  SensorLSM9DS1::availValuesAG()
+{
+  return(newValueAG);
+}
+
+void  SensorLSM9DS1::sync(int type, int code)
+{
+  if(type == 1 && code == 1)
+    newValueAG = false;
+}
+
+bool  SensorLSM9DS1::available(int type, int code)
+{
+  if(type == 1 && code == 1)
+    return(newValueAG);
+  return(false);
+}
+
 bool  SensorLSM9DS1::getValuesAG(RawDataAGPtr rdptr)
 {
   if(!newValueAG) return(false);
@@ -787,6 +816,29 @@ bool  SensorLSM9DS1::getValuesAG(CalValueAGPtr calPtr)
   return(true);
 }
 
+int  SensorLSM9DS1::getValues(int type, int code, void *dataPtr)
+{
+  if(type == 1 && code == 1)
+  {
+    ((TriFloatPtr) dataPtr)->x = (float) fullScaleA * (float) rawDataAG.valueAG.A.x / (float) 32767;
+    ((TriFloatPtr) dataPtr)->y = (float) fullScaleA * (float) rawDataAG.valueAG.A.y / (float) 32767;
+    ((TriFloatPtr) dataPtr)->z = (float) fullScaleA * (float) rawDataAG.valueAG.A.z / (float) 32767;
+    return(code);
+  }
+  else
+    return(-1);
+}
+
+byte SensorLSM9DS1::getSigns(int type, int code)
+{
+  if(type == 1 && code == 1)
+  {
+    return(signA);
+  }
+  else
+    return(0);
+}
+
 bool  SensorLSM9DS1::getAvgValuesAG(CalValueAGPtr calPtr)
 {
   if(!newValueAG) return(false);
diff --git a/libraries/SensorLSM9DS1/SensorLSM9DS1.h b/libraries/SensorLSM9DS1/SensorLSM9DS1.h
index 63cb831c96688b30a85397927a14a52dcb6a15f2..179aabea7ab6fb730d4de858cbcc55c9d5103456 100644
--- a/libraries/SensorLSM9DS1/SensorLSM9DS1.h
+++ b/libraries/SensorLSM9DS1/SensorLSM9DS1.h
@@ -13,6 +13,7 @@
 #include "Arduino.h"
 #include "arduinoDefs.h"
 #include "IntrfTw.h"
+#include "IntrfMeas.h"
 
 // ----------------------------------------------------------------------------
 
@@ -220,7 +221,7 @@ typedef struct _SensorErrors
 
 } SensorErrors, *SensorErrorsPtr;
 
-class SensorLSM9DS1
+class SensorLSM9DS1 : IntrfMeas
 {
 private:
   // --------------------------------------------------------------------------
@@ -236,10 +237,13 @@ private:
   bool        newValueAG;
   RawDataAG   rawDataAG;
   RawDataAG   comDataAG;
+  byte        signA;
+  byte        signG;
 
   bool        enableMeasM;
   bool        newValueM;
   RawDataM    rawDataM;
+  byte        signM;
 
   int         fullScaleA;
   int         fullScaleG;
@@ -274,6 +278,31 @@ private:
 
   void setTimeOutValues(FreqAG fAG, FreqM fM);
 
+  // Inline-Funktionen
+  void markSigns(byte signs, short x, short y, short z)
+  {
+    byte newSigns, chkSigns;
+
+    if(x < 0) newSigns = signX;
+    else newSigns = 0;
+    chkSigns = signs ^ newSigns;
+    if(chkSigns & signX) newSigns |= deltaSignX;
+
+    if(y < 0) newSigns |= signY;
+    chkSigns = signs ^ newSigns;
+    if(chkSigns & signY) newSigns |= deltaSignY;
+
+    if(z < 0) newSigns |= signZ;
+    chkSigns = signs ^ newSigns;
+    if(chkSigns & signZ) newSigns |= deltaSignZ;
+
+    if(newSigns & chkSignAll) newSigns |= signAll;
+    chkSigns = signs ^ newSigns;
+    if(chkSigns & signAll) newSigns |= deltaSignAll;
+
+    signs = newSigns;
+  }
+
 public:
   // --------------------------------------------------------------------------
   // Initialisierungen der Basis-Klasse
@@ -336,6 +365,7 @@ public:
   dword       toCntStatusM;
 
   void  syncValuesAG();
+  bool  availValuesAG();
   bool  getValuesAG(RawDataAGPtr rdptr);
   bool  getValuesAG(CalValueAGPtr calPtr);
   bool  getAvgValuesAG(CalValueAGPtr calPtr);
@@ -348,6 +378,18 @@ public:
   // ----------------------------------------------------------------------------
   //
 
+  // ----------------------------------------------------------------------------
+  // Schnittstelle für allgemeine Anwendungen
+  // ----------------------------------------------------------------------------
+  //
+  #define typeFloat   1
+  #define codeAcc     1
+
+  void sync(int type, int code);
+  bool available(int type, int code);
+  int  getValues(int type, int code, void *dataPtr);
+  byte getSigns(int type, int code);
+
   // ----------------------------------------------------------------------------
   //                      D e b u g - H i l f e n
   // ----------------------------------------------------------------------------
diff --git a/libraries/environment/IntrfRadio.h b/libraries/environment/IntrfRadio.h
index 1b50345c2a7bc65f6989a255bfc4f0ff56af88ae..798ded94567ba1595a396ef64d9080acaefe4bc7 100644
--- a/libraries/environment/IntrfRadio.h
+++ b/libraries/environment/IntrfRadio.h
@@ -70,6 +70,7 @@ typedef enum _TxMode
 
 #define SOAAP_NAK     0x40
 #define SOAAP_EADR    0x80
+#define SOAAP_MA      0x80
 
 // Modeabhängige Statistikdaten
 //
diff --git a/libraries/nRF52840Radio/nRF52840Radio.cpp b/libraries/nRF52840Radio/nRF52840Radio.cpp
index 5639480f98f812bc2170a24674d34534dd95d5e6..27c14c9221ca7f8fa06e74ad67767f0759870a8e 100644
--- a/libraries/nRF52840Radio/nRF52840Radio.cpp
+++ b/libraries/nRF52840Radio/nRF52840Radio.cpp
@@ -39,6 +39,7 @@ nRF52840Radio::nRF52840Radio()
   comFin = false;
   comError = false;
   newValues = false;
+  sizeM = 0;
 
   memset(statList,0,NrOfTxModes * sizeof(TxStatistics));
 }
@@ -167,7 +168,15 @@ void  nRF52840Radio::send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode,
   // 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
+  // Problem 20221023A
+  // Es werden im Empfangspuffer pduRec auch die gesendeten Daten angezeigt
+  // Deshalb wird hier der Kommunikationsspeicher extra vorweg gelöscht
+  // Das war aber leider keine Lösung für das Problem
+  //
+  if(txMode == txmResp)
+    memset((void *)pduMem,0,31);
+  else
+    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
@@ -429,13 +438,13 @@ int   nRF52840Radio::getRecData(bcPduPtr data, TxMode txMode, int max)
   switch(txMode)
   {
     case txmResp:
-      data->head = pduSentE[0];
-      retv = data->len  = pduSentE[1];
+      data->head = pduRec[0];
+      retv = data->len  = pduRec[1];
 
       for(int i = 2; i < (retv + 2); i++)
       {
         if(i == max) break;
-        bPtr[i] = pduSentE[i];
+        bPtr[i] = pduRec[i];
       }
 
       break;
@@ -556,7 +565,7 @@ int   nRF52840Radio::getRecData(bcPduPtr data, int max)
     bPtr[i] = pduMem[i];
   }
 
-  return(retv);
+  return(retv+2);
 }
 
 // ----------------------------------------------------------------------------
@@ -780,6 +789,29 @@ void nRF52840Radio::irqHandler()
       case txmResp:               // Datenübertragung Slave
       // ----------------------------------------------------------------------
 
+        // Problem 20221023A
+        // Es werden im Empfangspuffer pduRec auch die gesendeten Daten angezeigt
+        // und auch die der vorbereiteten Empfangsdaten (für EADR-Kommunikation)
+        //
+
+        // Problem 20221023A
+        // Keine Lösung, es sind sehr selten die richtigen Werte im Empfangspuffer
+        // und in der Regel die gesendeten Daten
+        //
+        if(comFin)
+        {
+          NrfRadioPtr->SHORTS = 0;
+          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;
+
+          break;
+        }
+
         // --------------------------------------------------------------------
         if(NrfRadioPtr->EVENTS_END == 1)        // Übertragung beendet
                                                 // Polling-Daten empfangen
@@ -789,8 +821,13 @@ void nRF52840Radio::irqHandler()
 
 #if (defined smnDEBUG  && defined nRF52840RadioDEB)
           statisticPtr->recs++;
-          memcpy(statisticPtr->memDumpRec,pduMem,8);
+          memcpy(statisticPtr->memDumpRec,pduMem,14);
 #endif
+          // Problem 20221023A
+          // Es sind an dieser Stelle alle möglichen Telegramme im Kommunikationspuffer pduMem.
+          // Auch das erwartete Polling vom Master, aber auch die Antworten der anderen Slaves
+          // und die eigene Antwort (nicht erwartet) oder auch der leere Speicher (nicht erwartet)
+          //
 
           if((pduSentE[5] != pduMem[5]) || (pduSentE[6] != pduMem[6]) || (pduSentE[7] != pduMem[7]))
           {
@@ -804,6 +841,10 @@ void nRF52840Radio::irqHandler()
             break;
           }
 
+          // Problem 20221023A
+          // Hier sind nur die Telegramme in pduMem, die zum eigenen Netzwerk gehören,
+          //
+
           if((pduSentE[2] != pduMem[2]) || ((pduSentE[3] & 0x3F) != (pduMem[3] & 0x3F)))
           {
             // Das empfangene Telegramm ist für einen anderen Slave oder Bereich
@@ -818,8 +859,13 @@ void nRF52840Radio::irqHandler()
             // Hier wird das Protokoll noch erweitert zum Belauschen anderer Slaves
           }
 
+          // Problem 20221023A
+          // Hier sind nur die Telegramme in pduMem, die zu diesem Slave gehören
+          // Leider auch das von ihm gesendete Telegramm (unverständlicherweise)
+          //
           eadM = ((pduMem[3] & SOAAP_EADR) != 0); // Merker für Empfangspolling
           nakM = ((pduMem[3] & SOAAP_NAK) != 0);  // Merker für NAK-Polling
+          maM  = ((pduMem[4] & SOAAP_MA) != 0);   // Merker für Master-Telegramm
 
 #if (defined smnDEBUG  && defined nRF52840RadioDEB)
           if(nakM)
@@ -827,6 +873,27 @@ void nRF52840Radio::irqHandler()
           else
             statisticPtr->pollAcks++;
 #endif
+
+          /*
+          // Problem 20221023A
+          // Es ist noch nicht geklärt, wieso hier die eigenen Sendungen eintreffen
+          // Für den Fall wird jetzt der Empfang abgebrochen und muss neu
+          // gestartet werden
+          //
+          if(!maM)
+          {
+            NrfRadioPtr->SHORTS = 0;
+            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;
+            break;
+          }
+          */
+
           if(eadM)
           {
             // Empfangsaufforderung
@@ -840,8 +907,14 @@ void nRF52840Radio::irqHandler()
             // 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));
+
+            if(maM)
+            {
+              sizeM = pduMem[1];
+              memcpy((void *)pduRec, (void *)pduMem, sizeM+2);
+            }
+            //memcpy((void *)pduMem, (void *)pduSentS, sizeof(bcPdu));
+            memcpy((void *)pduMem, (void *)pduSentS, 39);
           }
 
           // Setzen der Direktverbinder auf vollständigen Durchlauf bis Ende der Sendung
@@ -877,6 +950,12 @@ void nRF52840Radio::irqHandler()
         {
           NrfRadioPtr->EVENTS_DISABLED = 0;     // Event quittieren
           comFin = true;
+
+          // Problem 20221023A
+          // Keine Lösung des Problems
+          NrfRadioPtr->SHORTS = 0;
+
+
 #if (defined smnDEBUG  && defined nRF52840RadioDEB)
           statisticPtr->sendings++;
           memcpy(statisticPtr->memDumpSnd,pduMem,16);
@@ -922,7 +1001,7 @@ int   nRF52840Radio::getPduMem(byte *dest, int start, int end)
   return(j);
 }
 
-int   nRF52840Radio::getPduSent(byte *dest, int start, int end)
+int   nRF52840Radio::getPduSentE(byte *dest, int start, int end)
 {
   int i,j;
 
@@ -935,6 +1014,32 @@ int   nRF52840Radio::getPduSent(byte *dest, int start, int end)
   return(j);
 }
 
+int   nRF52840Radio::getPduSentS(byte *dest, int start, int end)
+{
+  int i,j;
+
+  j = 0;
+
+  for(i = start; i < end; i++)
+  {
+    dest[j++] = pduSentS[i];
+  }
+  return(j);
+}
+
+int   nRF52840Radio::getPduRec(byte *dest, int start, int end)
+{
+  int i,j;
+
+  j = 0;
+
+  for(i = start; i < end; i++)
+  {
+    dest[j++] = pduRec[i];
+  }
+  return(j);
+}
+
 
 
 
diff --git a/libraries/nRF52840Radio/nRF52840Radio.h b/libraries/nRF52840Radio/nRF52840Radio.h
index 0e61246043b8b3bd78928b3e33e31f81e180d011..a463c962c48d21ffbfdcdc020e2ad46be53ecee0 100644
--- a/libraries/nRF52840Radio/nRF52840Radio.h
+++ b/libraries/nRF52840Radio/nRF52840Radio.h
@@ -14,7 +14,13 @@
 #include "bleSpec.h"
 #include "IntrfRadio.h"
 
+//#define smnDEBUG
+// Mit dieser Definition wird das Debuggen der Module grundsätzlich ermöglicht
+// Sie wird in der Regel in der Projektumgebung des Entwicklungssystems gesetzt
+// (z.B. Arduino Compile Options bei Eclipse/Sloeber)
+
 #define nRF52840RadioDEB
+// Damit wird die Erzeugung von Debug-Daten in diesem Modul geschaltet
 
 // ----------------------------------------------------------------------------
 
@@ -123,6 +129,8 @@ typedef struct _NRF_RADIO_Type
 #define nrfPowerDCDCEN  ((dword *) 0x40000578)
 #endif
 
+// Falls noch kein Zugriff auf die Taktfestlegung erfolgte
+//
 #ifndef NrfClockBase
 #define NrfClockBase    0x40000000
 #define nrfClockTASKS_HFCLKSTART  ((dword *) 0x40000000)
@@ -223,8 +231,10 @@ private:
   // --------------------------------------------------------------------------
   //
   byte        pduMem[256];
+  int         sizeM;
   byte        pduSentE[256];
   byte        pduSentS[256];
+  byte        pduRec[256];
 
   bcPduPtr    pmPtr;
   bcPduPtr    pePtr;
@@ -233,8 +243,9 @@ private:
   nrf52840Cfg cfgData;
 
   bool        recMode;
-  bool        eadM;
-  bool        nakM;
+  bool        eadM;           // Merker für Empfangsanfrage
+  bool        nakM;           // Merker für NAK-Antwort (oder Request)
+  bool        maM;            // Merker für Master-Telegramm
   bool        comFin;
   bool        comError;
   bool        newValues;
@@ -303,8 +314,9 @@ public:
   // ----------------------------------------------------------------------------
   //
   int   getPduMem(byte *dest, int start, int end);
-  int   getPduSent(byte *dest, int start, int end);
-
+  int   getPduSentE(byte *dest, int start, int end);
+  int   getPduSentS(byte *dest, int start, int end);
+  int   getPduRec(byte *dest, int start, int end);
 
 };
 
diff --git a/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.h b/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.h
index 29a71a446043a39e76e8eb029c05ebce360c0d21..9bb0445f1db6ca2ab7082d767361e1a084332643 100644
--- a/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.h
+++ b/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.h
@@ -21,9 +21,13 @@
 //#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"
@@ -52,6 +56,41 @@ typedef struct _Value2Midi
 
 } 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
 // ----------------------------------------------------------------------------
@@ -67,6 +106,9 @@ void apTestController();
 
 void setParM1();
 void setParM2();
+void setParP1();
+void setParP2();
+
 
 #ifdef DebugTerminal
 // ----------------------
@@ -76,7 +118,9 @@ void smDebDword() ;
 void smCtrlPolling() ;
 void smWaitPolling() ;
 void smReadPollValues() ;
-void smCheckSer();
+void smCheckApp();
+void smMode4Slave();
+void smMode4SlaveIn();
 // ----------------------
 #endif
 
diff --git a/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.ino b/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.ino
index 1aaf110af91edb270cd1165e6261a89eff15a437..b2577ce24c6307e36242ce5ce34e0b78f618d7e9 100644
--- a/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.ino
+++ b/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.ino
@@ -60,7 +60,8 @@ BlePoll       blePoll((IntrfRadio *) &bleCom, micros);
 // Anzahl der Slaves (MAXSLAVE) sein, weil die Ressourcen darüber statisch
 // festgelegt werden.
 
-Value2Midi  val2midArr[NrOfSlavesToPoll + 1];
+Value2Midi    val2midArr[NrOfSlavesToPoll + 1];
+Posture2Midi  post2midArr[NrOfSlavesToPoll + 1];
 // Jeder Slave bekommt spezifische Value->Midi-Parameter.
 // Index 0 steht für eventuelle Parameter des Masters
 
@@ -120,6 +121,18 @@ StateMachine  sm(smInit, NULL, smCycleTime);
 //                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
@@ -138,6 +151,8 @@ Monitor       mon(modeEcho | modeNl,0,&lc);
 #endif
 
 
+BlePoll::AppType  appType;
+
 // ============================================================================
 void setup()
 // ============================================================================
@@ -147,7 +162,10 @@ void setup()
   // TEST
   bleCom.setPower(0x0FC);   // Reduzierte Sendeleistung beim Schreibtisch-Test
 
-  blePoll.begin(BlePoll::ctMASTER, NrOfSlavesToPoll, BlePoll::atDevSOAAP, 10000);
+  //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.)
@@ -173,7 +191,8 @@ void setup()
   // <1000>   Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden
 
 #ifdef DebugTerminal
-  blePoll.stopEP();   // Das Polling muss extra gestartet werden
+  blePoll.stopEP();       // Das Polling muss extra gestartet werden
+  mon.setInfo(infoThis);  // Info-Meldung für Monitor
 #endif
 
   // Initialisierung von serieller Schnittstelle und Ringpuffer
@@ -200,10 +219,12 @@ void setup()
   // 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();
@@ -251,14 +272,14 @@ void loop()
   if(lc.timerMilli(lcTimer3, 1000, 0))
   {
     if(!mon.cFlag[0])
-      mon.printcr((char *)"%@TestBleMidiMaster, Version 20220426");
+      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(lcTimer3, smCycleTime, 0))
+  if(lc.timerMilli(lcTimer4, smCycleTime, 0))
   {
     sm.run();
   }
@@ -294,11 +315,10 @@ char testMsgBuf[256];
 // ----------------------------------------------------------------------------
 // Initialisierungen
 //
+dword apInitCnt;
 void apInit()
 {
-#ifdef TEST001
-  crb.putLine("Initialisierung");
-#endif
+  apInitCnt++;
 
   midi1.setNoteType(MidiNotes::nti8);
   lastNoteIdxM1 = midi1.addChordNote(MidiNotes::nti8, SchlossC, 10);
@@ -312,26 +332,28 @@ void apInit()
 // ----------------------------------------------------------------------------
 // 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
 
-#ifdef TEST001
-  crb.putStr("Slaveliste\r\n");
-#endif
-
   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++)
@@ -343,10 +365,6 @@ void apWaitMeas()
   // 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);
@@ -355,18 +373,10 @@ void apWaitMeas()
 // ----------------------------------------------------------------------------
 // Verarbeiten der Daten vom Slave
 //
+dword apProcMeasCnt;
 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
+  apProcMeasCnt++;
 
   // Parameter und Daten für die SOAAP-Ausgabe holen
   //
@@ -375,11 +385,6 @@ void apProcMeas()
   pAppId = blePoll.getAppId(slNr);
   apNrOfMeasBytes = blePoll.getMeas(slNr, apMeasByteArray);
 
-#ifdef TEST001
-  ap.enter(apWaitMeas);
-  return;
-#endif
-
   // Spezifisch je Slave auswerten
   //
   if(slNr == 1 || slNr == 2)
@@ -397,30 +402,30 @@ void apProcMeas()
 // Daten überprüfen (auswerten)
 //
 short accXold, accYold, accZold;
-
+float rollOld, pitchOld, yawOld;
+dword apCheckValuesCnt;
 void apCheckValues()
 {
-  //bool newData = false;
+  apCheckValuesCnt++;
 
-  short accX = * (short *) &apMeasByteArray[6];
-  short accY = * (short *) &apMeasByteArray[8];
-  short accZ = * (short *) &apMeasByteArray[10];
+  switch (appType)
+  {
+   case BlePoll::atSOAAP1:
+     //bool newData = false;
 
-  /*
-  newData |= (accX != accXold);
-  newData |= (accY != accYold);
-  newData |= (accZ != accZold);
+     accXold = * (short *) &apMeasByteArray[6];
+     accYold = * (short *) &apMeasByteArray[8];
+     accZold = * (short *) &apMeasByteArray[10];
 
-  if(!newData)
-  {
-    ap.enter(apWaitMeas);
-    return;
-  }
-  */
+     break;
 
-  accXold = accX;
-  accYold = accY;
-  accZold = accZ;
+   case BlePoll::atSOAAP2:
+     rollOld  = * (float *) &apMeasByteArray[0];
+     pitchOld = * (float *) &apMeasByteArray[4];
+     yawOld   = * (float *) &apMeasByteArray[8];
+
+     break;
+  }
 
   ap.enter(apCalcResult);
 }
@@ -463,32 +468,136 @@ void setParM2()
   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()
 {
-  if((accZold < val2midArr[slNr].borderLowAz) && (accXold < val2midArr[slNr].borderLowAx))
-  {
-    ap.enter(apWaitMeas);
-    return;
-  }
+  short     testY;
+  int       result;
+  float     rollVal, pitchVal, yawVal;
+  Meas2Midi meas2midi;
 
-  short testY = accZold + accYold / 4;
-  int 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;
+  apCalcResultCnt++;
 
-  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;
+  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);
 }
@@ -496,12 +605,40 @@ void apCalcResult()
 // ----------------------------------------------------------------------------
 // Bedienen des Midi-Controller
 //
+dword apSetResultCnt;
 void apSetResult()
 {
-  if(slNr == 1)
-    midi1.setChordNote(lastNoteIdxM1, (MidiNotes::NoteTypeIdx) resultAx, resultAz, 100);
-  else if(slNr == 2)
-    midi2.setChordNote(lastNoteIdxM2, (MidiNotes::NoteTypeIdx) resultAx, resultAz, 100);
+  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);
 }
 
@@ -546,7 +683,9 @@ void smCheckJobs()
   else if(mon.cFlag[3] && !mon.busy)
     sm.enter(smReadPollValues);
   else if(mon.cFlag[4] && !mon.busy)
-    sm.enter(smCheckSer);
+    sm.enter(smCheckApp);
+  else if(mon.cFlag[5] && !mon.busy)
+    sm.enter(smMode4Slave);
 }
 
 // ----------------------------------------------------------------------------
@@ -591,6 +730,17 @@ void smDebDword()
 // ----------------------------------------------------------------------------
 //
 
+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()
@@ -609,8 +759,15 @@ void smCtrlPolling()
 
   if(mon.lastKeyIn == ':') return;
 
+  if(mon.lastKeyIn == 'H' || mon.lastKeyIn == 'h')
+  {
+    mon.println();
+    mon.print(smPollHelp);
+    sm.resetEnter();
+  }
+
   // --------------------------------------------------------------------------
-  if(mon.lastKeyIn == 'P' || mon.lastKeyIn == 'p')
+  else if(mon.lastKeyIn == 'P' || mon.lastKeyIn == 'p')
   {
     if(blePoll.stoppedEP())
     {
@@ -638,8 +795,8 @@ void smCtrlPolling()
   else if(mon.lastKeyIn == 'R' || mon.lastKeyIn == 'r')
   {
     mon.print((char *) "Radiopuffer = ");
-    bleCom.getPduMem(tmpByteArray, 0, 10);
-    mon.println(tmpByteArray, 10, ' ');
+    bleCom.getPduMem(tmpByteArray, 0, 16);
+    mon.println(tmpByteArray, 16, ' ');
     sm.resetEnter();
   }
 
@@ -648,8 +805,8 @@ void smCtrlPolling()
   else if(mon.lastKeyIn == 'S' || mon.lastKeyIn == 's')
   {
     mon.print((char *) "Sendepuffer = ");
-    bleCom.getPduSent(tmpByteArray, 0, 10);
-    mon.println(tmpByteArray, 10, ' ');
+    bleCom.getPduSentS(tmpByteArray, 0, 16);
+    mon.println(tmpByteArray, 16, ' ');
     sm.resetEnter();
   }
 
@@ -757,31 +914,265 @@ void smWaitPolling()
 }
 
 // ----------------------------------------------------------------------------
-// Testen der seriellen Schnittstelle
+// Zugriff auf die Sensordaten
 // ----------------------------------------------------------------------------
 //
-void smCheckSer()
+
+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 *) "TestSer...");
+    mon.print((char *) "Werte vom Sensor ");
     mon.lastKeyIn = ':';
   }
 
   if(mon.lastKeyIn == ':') return;
 
-  if(mon.lastKeyIn == ' ')
+  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
   {
-    crb.putChr(mon.lastKeyIn);
+    mode2Snd[inIdx] = mon.lastKeyIn;
     mon.cprint(mon.lastKeyIn);
     mon.lastKeyIn = ':';
+    inIdx++;
   }
+
 }
 
 // ----------------------------------------------------------------------------
@@ -789,10 +1180,5 @@ void smCheckSer()
 // ----------------------------------------------------------------------------
 //
 
-void smReadPollValues()
-{
-
-}
-
 #endif // DebugTerminal
 
diff --git a/sketches/SoaapBleSlave/SoaapBleSlave.h b/sketches/SoaapBleSlave/SoaapBleSlave.h
new file mode 100644
index 0000000000000000000000000000000000000000..84bf1f4243b3b5f477a99f99819ef95061c2cf35
--- /dev/null
+++ b/sketches/SoaapBleSlave/SoaapBleSlave.h
@@ -0,0 +1,69 @@
+/*
+ * SoaapBleSlave.h
+ *
+ *  Created on: 26.04.2022
+ *      Author: robert
+ */
+
+#ifndef SoaapBleSlave_h
+#define SoaapBleSlave_h
+
+//#define DebugTerminal
+// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden
+// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist
+// Dieser Schalter wird in der Regel in der Umgebung des Projektes beim
+// Entwicklungssystem gesetzt (z.B. Arduino Compile Options bei Eclipse/Sloeber)
+
+
+#include "LoopCheck.h"
+#include "StateMachine.h"
+
+#include "nRF52840Gpio.h"
+
+#include "nRF52840Twi.h"
+#include "SensorLSM9DS1.h"
+
+#include "nRF52840Radio.h"
+#include "BlePoll.h"
+
+#include "ProcMeas.h"
+
+#include "nRF52840Adc.h"
+
+#ifdef DebugTerminal
+#include "Monitor.h"
+#endif
+
+bool getValues(PlpType plpType, byte *dest);
+bool xchgCtrl(PlpType plpType, byte *dest, byte *src, int sSize);
+
+#ifdef DebugTerminal
+void smInit() ;
+void smCheckJobs() ;
+void smDebDword() ;
+void smCtrlPolling() ;
+void smWaitPolling() ;
+void smCheckSens() ;
+void smSensHelp();
+void smSensReset1() ;
+void smSensReset2() ;
+void smSensGetValues1() ;
+void smSensGetValues2() ;
+void smSensGetValues3() ;
+void smSensGetValues4() ;
+void smSensGetValues5() ;
+void smSensGetValues6() ;
+void smSensGetValues7() ;
+void smSensGetAngleValues();
+void smSensCheckAngleValues();
+void smSensGetSoaapValues() ;
+void smSensDebugValues() ;
+void smSensGetErrors() ;
+void smDebugProcMeas();
+void smSensGetTimeOuts() ;
+void smSensGetRunCounts() ;
+void smTempTesting();
+void smTestAdcMem();
+#endif
+
+#endif // SoaapBleSlave_h
diff --git a/sketches/SoaapBleSlave/SoaapBleSlave.ino b/sketches/SoaapBleSlave/SoaapBleSlave.ino
new file mode 100644
index 0000000000000000000000000000000000000000..e2c03755245a1e74d71dc505a0e14aad0d63b515
--- /dev/null
+++ b/sketches/SoaapBleSlave/SoaapBleSlave.ino
@@ -0,0 +1,1185 @@
+// ----------------------------------------------------------------------------
+//                              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"
+
+#ifdef SlaveADR1
+#define SlaveADR 1
+#endif
+
+#ifdef SlaveADR2
+#define SlaveADR 2
+#endif
+
+#ifdef SlaveADR3
+#define SlaveADR 3
+#endif
+
+#ifdef SlaveADR4
+#define SlaveADR 4
+#endif
+
+char *StartMsg =
+{
+    "%@TestBleSlave "
+#ifdef SlaveADR1
+    "(Adr=1), "
+#endif
+#ifdef SlaveADR2
+    "(Adr=2), "
+#endif
+#ifdef SlaveADR3
+    "(Adr=3), "
+#endif
+#ifdef SlaveADR4
+    "(Adr=4), "
+#endif
+    "Version 20221024-1 "
+};
+
+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
+
+char *infoThis =
+{
+"SOAAP BLE Slave Version 22.09.25-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  Steuern/Analysieren der Messwerterfassung\r\n"
+"c4  Temporäre lokale Tests\r\n"
+};
+
+#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.
+
+#define ProcMeasCycle 250
+ProcMeas proc((IntrfMeas *) &sens);
+// Vorauswertung der Messwerte
+
+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
+
+nRF52840Adc   adc;
+
+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);
+  }
+
+  mon.setInfo(infoThis);
+#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::atDevSOAAP, 10000);
+  blePoll.begin(BlePoll::ctSLAVE, SlaveADR, BlePoll::atSOAAP2, 50000);
+  // 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 250 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();
+
+  // Alle 250 Mikrosekunden erfolgt der Aufruf der Messwertvorverarbeitung
+  if(lc.timerMicro(lcTimer2, ProcMeasCycle, 0))
+    proc.run();
+
+#ifdef DebugTerminal
+  // Alle 5 Millisekunden wird die Zustandsmaschine für
+  // betriebliche Abläufe aufgerufen
+  //
+  if(lc.timerMilli(lcTimer3, smCycleTime, 0))
+  {
+    sm.run();
+  }
+
+  // Jede halbe Sekunde erfolgt die Ausgabe der Version
+  //
+  if(lc.timerMilli(lcTimer4, 500, 0))
+  {
+    if(!mon.cFlag[0])
+    {
+      mon.print(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;
+CalValueAG  calDataAG;
+byte        deviceState[4];
+
+bool getValues(PlpType plpType, byte *dest)
+{
+  bool  retv;
+  int   si,di;
+  union {float tmpFloat; byte tmpByteArr[4]; } transData;
+
+
+  si = di = 0;
+
+  switch(plpType)
+  {
+    case plptMeas6:
+      if(!sens.availValuesAG())
+      {
+        retv = false;
+        break;
+      }
+      memset(rawDataAG.byteArray,0,12);
+      sens.getValuesAG(&rawDataAG);
+      for(si = 0; si < 12; si++)
+        dest[di++] = rawDataAG.byteArray[si];
+      retv = true;
+      break;
+
+    case plptMeas9Ctrl4:
+      if(!sens.availValuesAG())
+      {
+        retv = false;
+        break;
+      }
+      memset(rawDataAG.byteArray,0,12);
+      sens.getValuesAG(&rawDataAG);
+      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;
+
+    // ----------------------------------------------------------------------------------
+    case plptIMU3F4Ctrl4:     // Roll-, Nick- und Gierwinkel Float + 4 Byte Status
+    // ----------------------------------------------------------------------------------
+      if(!proc.availAngles(true))
+      {
+        retv = false;
+        break;
+      }
+
+      transData.tmpFloat = proc.getRollValue();
+      for(si = 0; si < 4; si++)
+        dest[di++] = transData.tmpByteArr[si];
+
+      transData.tmpFloat = proc.getPitchValue();
+      for(si = 0; si < 4; si++)
+        dest[di++] = transData.tmpByteArr[si];
+
+      transData.tmpFloat = proc.getYawValue();
+      for(si = 0; si < 4; si++)
+        dest[di++] = transData.tmpByteArr[si];
+
+      deviceState[0] = proc.getGravSigns();
+
+      for(si = 0; si < 4; si++)
+        dest[di++] = deviceState[si];
+
+      retv = true;
+      break;
+  }
+
+  return(retv);
+}
+
+union
+{
+byte procData[32];
+PlpCtrl25 pdu;
+} inCtrl;
+
+int  procSize     = 0;
+byte procPath     = 0;
+byte procCnt      = 0;
+byte ctrlCnt      = 0;
+
+
+bool xchgCtrl(PlpType plpType, byte *dest, byte *src, int sSize)
+{
+  int   si,di;
+  bool  retv;
+
+  PlpCtrl2Ptr   recPtr  = (PlpCtrl2Ptr) src;
+
+  if(recPtr->ctrlCnt == ctrlCnt) return(false); // Nichts Neues
+  ctrlCnt = recPtr->ctrlCnt;
+
+  si = di = 0;
+  retv = false;
+
+  switch(plpType)
+  {
+    case plptMeas9Ctrl4:
+    case plptIMU3F4Ctrl4:
+      // Lokale Kopie der Steuerdaten vom Master anlegen
+      //
+      for(si = 0; si < sSize; si++)
+        inCtrl.procData[si] = src[si];
+      procSize = sSize;
+
+      dest[di++] = procPath;
+      dest[di++] = ++procCnt;
+      // Test
+      dest[di++] = (inCtrl.pdu.counter & 0x3F) | 0x40;
+      dest[di++] = 'O';
+      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];
+int         tmpInt;
+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(smTempTesting);
+}
+
+
+// ----------------------------------------------------------------------------
+// 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
+//
+char *smPollHelp =
+{
+    "B   Prozessdaten anzeigen\r\n"
+    "C   Steuerempfang auslesen\r\n"
+    "E   Empfangspuffer auslesen (16 Zeichen)\r\n"
+    "P   Polling starten/stoppen/fortsetzen\r\n"
+    "R   Radiopuffer auslesen (16 Zeichen)\r\n"
+    "S   Sendepuffer auslesen (30 Zeichen)\r\n"
+    "T   Übertragungsstatistik und Daten anzeigen\r\n"
+    "0...9  Slave-Umgebung\r\n"
+};
+
+TxStatistics txStatistics;
+
+void smCtrlPolling()
+{
+  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 == 'B' || mon.lastKeyIn == 'b')
+  {
+    mon.print((char *) "Prozessdaten = ");
+    mon.println(inCtrl.procData, 16, ' ');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'C' || mon.lastKeyIn == 'c')
+  {
+    mon.print((char *) "Steuerempfang[");
+    tmpInt = blePoll.getCtrlData(tmpByteArray);
+    mon.print(tmpInt);
+    mon.print("] = ");
+    mon.println(tmpByteArray, tmpInt, ' ');
+    sm.resetEnter();
+  }
+
+  // --------------------------------------------------------------------------
+  else if(mon.lastKeyIn == 'E' || mon.lastKeyIn == 'e')
+  {
+    mon.print((char *) "Empfangspuffer = ");
+    bleCom.getPduRec(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, 32);
+    mon.println(tmpByteArray, 32, ' ');
+    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 == '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,14,' '); mon.print("]  s[ ");
+    mon.print(txStatistics.memDumpSnd,24,' '); 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);
+}
+
+// ----------------------------------------------------------------------------
+// (3) Testen der Sensorzugriffe
+// ----------------------------------------------------------------------------
+//
+
+char *chkSensHelp =
+{
+"3 Beschleunigung Rohwerte (short)\r\n"
+"4 Beschleunigung kalibrierte Werte (float)\r\n"
+"5 Beschleunigung kalibrierte Werte zyklisch (float)\r\n"
+"6 Beschleunigung & Gyroskop kalibrierte Werte zyklisch (float)\r\n"
+#ifdef ProcMeasDebug
+"p Debug <ProcMeas>\r\n"
+#endif
+};
+
+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 == 'H' || mon.lastKeyIn == 'h')
+  {
+    mon.println();
+    sm.enter(smSensHelp);
+  }
+  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 == 'a')
+    sm.enter(smSensGetAngleValues);
+  else if(mon.lastKeyIn == 'b')
+    sm.enter(smSensCheckAngleValues);
+  else if(mon.lastKeyIn == 'c')
+    sm.enter(smSensDebugValues);
+  else if(mon.lastKeyIn == 'e')
+    sm.enter(smSensGetErrors);
+#ifdef ProcMeasDebug
+  else if(mon.lastKeyIn == 'p')
+    sm.enter(smDebugProcMeas);
+#endif
+  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 smSensHelp()
+{
+  mon.println();
+  mon.println(chkSensHelp);
+  sm.enter(smCheckSens);
+}
+
+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);
+  sm.setDelay(500);
+
+  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);
+  sm.setDelay(500);
+
+  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 smSensGetAngleValues()
+{
+  float roll, pitch;
+
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    sm.setTimeOut(1000);
+  }
+
+  if(!proc.availAngles(true))
+  {
+    if(sm.timeOut())
+    {
+      mon.println("Time-Out Warten auf Messwerte");
+      sm.enter(smCheckSens);
+    }
+    return;
+  }
+
+  roll = proc.getRollValue();
+  pitch = proc.getPitchValue();
+
+  mon.print((char *) "Angles Roll = ");
+  sprintf(outValue,"%f  Pitch = ",roll);
+  mon.print(outValue);
+  sprintf(outValue,"%f ",pitch);
+  mon.println(outValue);
+  sm.enter(smCheckSens);
+}
+
+
+void smSensCheckAngleValues()
+{
+  float roll, pitch;
+  dword cntMics;
+
+  if(sm.firstEnter())
+  {
+    sens.syncValuesAG();
+    sm.setTimeOut(1000);
+  }
+
+  if(!proc.availAngles(true))
+  {
+    if(sm.timeOut())
+    {
+      mon.println("Time-Out Warten auf Messwerte");
+      sm.enter(smCheckSens);
+    }
+    return;
+  }
+
+  cntMics = micros();
+  roll = proc.getRollValue();
+  pitch = proc.getPitchValue();
+  cntMics = micros() - cntMics;
+
+  mon.print(cntMics);
+  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);
+
+  mon.print((char *) "Angles Roll = ");
+  sprintf(outValue,"%f  Pitch = ",roll);
+  mon.print(outValue);
+  sprintf(outValue,"%f ",pitch);
+  mon.println(outValue);
+  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);
+}
+
+#ifdef ProcMeasDebug
+void smDebugProcMeas()
+{
+  mon.print((char *) "ProcMeas: Init = ");
+  mon.print(proc.statistics.pmInitCnt);
+  mon.print((char *) " Wait = ");
+  mon.print(proc.statistics.pmWaitCnt);
+  mon.print((char *) " Calc = ");
+  mon.println(proc.statistics.pmCalcCnt);
+
+  sm.enter(smCheckSens);
+}
+#endif
+
+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);
+}
+
+// ----------------------------------------------------------------------------
+// (4) Temporäres Testen lokaler Speicher und Funktionen
+// ----------------------------------------------------------------------------
+//
+
+void smTempTesting()
+{
+  if(sm.firstEnter())
+  {
+    mon.print((char *) "Temp. Testen ");
+    mon.lastKeyIn = ':';
+  }
+
+  if(mon.lastKeyIn == ':') return;
+
+  charOut[0] = mon.lastKeyIn;
+  charOut[1] = '\0';
+  mon.println(charOut);
+
+  if(mon.lastKeyIn == '0' || mon.lastKeyIn == ' ')
+  {
+    mon.cFlag[4] = false;
+    mon.print((char *) "-- Schleifenabbruch - drücke Enter");
+    sm.enter(smCheckJobs);
+  }
+  else if(mon.lastKeyIn == 'M' || mon.lastKeyIn == 'm')
+  {
+    mon.println();
+    sm.enter(smTestAdcMem);
+  }
+  mon.lastKeyIn = ':';
+  sm.resetEnter();
+}
+
+char  tmpOut[256];
+
+void smTestAdcMem()
+{
+  nrfAdcPtr perMem = NULL;
+  volatile ChnConfigs  *chnCfgPtr;
+
+  dword res1 = (dword) &perMem->EVENTS_STARTED;
+  dword res2 = (dword) &perMem->INTEN;
+  dword res3 = (dword) &perMem->STATUS;
+  dword res4 = (dword) &perMem->ENABLE;
+  //dword res5 = (dword) &perMem->CH[0];
+  chnCfgPtr = &(NrfAdcPtr->CH[0]);
+  volatile dword *res5Ptr = &(chnCfgPtr->CONFIG);
+  dword res5 = (dword) res5Ptr;
+  dword res6 = (dword) &perMem->RESOLUTION;
+  dword res7 = (dword) &perMem->RESULT_PTR;
+
+  sprintf(tmpOut,"%X %X %X %X %X %X %X",res1,res2,res3,res4,res5,res6,res7);
+  mon.println(tmpOut);
+  sm.enter(smTempTesting);
+}
+
+
+#endif // DebugTerminal
+
diff --git a/sketches/ctrlMidi/SoaapMidi.h b/sketches/ctrlMidi/SoaapMidi.h
new file mode 100644
index 0000000000000000000000000000000000000000..80c8b92e9432291d004c4de4f114744dbf6a5825
--- /dev/null
+++ b/sketches/ctrlMidi/SoaapMidi.h
@@ -0,0 +1,16 @@
+
+#ifndef SoaapMidi_h
+#define SoaapMidi_h
+
+void smInit();
+void smIdle();
+void smGetValues();
+void smCheckValues();
+void smCalcResult();
+void smSetResult();
+void smTestValues();
+
+
+
+#endif
+
diff --git a/sketches/pollingBLE/SoaapBleMaster.h b/sketches/pollingBLE/SoaapBleMaster.h
new file mode 100644
index 0000000000000000000000000000000000000000..fb14e55e99bd8ccfb2139924ab0425a6a21de623
--- /dev/null
+++ b/sketches/pollingBLE/SoaapBleMaster.h
@@ -0,0 +1,58 @@
+// ----------------------------------------------------------------------------
+//                              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 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/pollingBLE/SoaapBleSlave.h b/sketches/pollingBLE/SoaapBleSlave.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e4279ef6ff361a3bf6eabd69fab59e87636e4ed
--- /dev/null
+++ b/sketches/pollingBLE/SoaapBleSlave.h
@@ -0,0 +1,57 @@
+/*
+ * SoaapBleSlave.h
+ *
+ *  Created on: 26.04.2022
+ *      Author: robert
+ */
+
+#ifndef SoaapBleSlave_h
+#define SoaapBleSlave_h
+
+#define DebugTerminal
+// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden
+// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist
+
+
+#include "LoopCheck.h"
+#include "StateMachine.h"
+
+#include "nRF52840Gpio.h"
+
+#include "nRF52840Twi.h"
+#include "SensorLSM9DS1.h"
+
+#include "nRF52840Radio.h"
+#include "BlePoll.h"
+
+#ifdef DebugTerminal
+#include "Monitor.h"
+#endif
+
+bool getValues(PlpType plpType, byte *dest);
+bool xchgCtrl(PlpType plpType, byte *dest, byte *src, int sSize);
+
+#ifdef DebugTerminal
+void smInit() ;
+void smCheckJobs() ;
+void smDebDword() ;
+void smCtrlPolling() ;
+void smWaitPolling() ;
+void smCheckSens() ;
+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
+
+#endif // SoaapBleSlave_h