From 14e9045d09e164bddfc8b8e40eefa1bf53a1ded8 Mon Sep 17 00:00:00 2001 From: Lennard Karger <lennard.karger@stud.hs-hannover.de> Date: Fri, 11 Nov 2022 17:54:47 +0100 Subject: [PATCH] Bibliotheken Update 11.11.22 --- libraries/BlePoll/BlePoll.cpp | 205 ++- libraries/BlePoll/BlePoll.h | 113 +- libraries/BlePoll/library.json | 2 +- libraries/ComRingBuf/library.json | 4 +- libraries/EulerAngles/EulerAngles.cpp | 53 + libraries/EulerAngles/EulerAngles.h | 64 + libraries/EulerAngles/library.json | 4 + libraries/GpioCtrl/GpioCtrl.cpp | 165 +++ libraries/GpioCtrl/GpioCtrl.h | 91 ++ libraries/GpioCtrl/library.json | 4 + libraries/LoopCheck/examples/lcBlink.ino | 81 ++ libraries/LoopCheck/examples/lcStatistics.ino | 127 ++ .../examplesLinux/testCppArduino.cpp | 38 + libraries/LoopCheck/examplesWindows/README.md | 2 + .../examplesWindows/testLoopCheck.txt | 145 ++ libraries/LoopCheck/library.json | 30 +- libraries/MidiNotes/library.json | 2 +- libraries/Monitor/Monitor.cpp | 93 +- libraries/Monitor/Monitor.h | 16 +- libraries/Monitor/library.json | 2 +- libraries/ProcMeas/ProcMeas.cpp | 97 ++ libraries/ProcMeas/ProcMeas.h | 106 ++ libraries/ProcMeas/library.json | 4 + libraries/SensorLSM9DS1/SensorLSM9DS1.cpp | 52 + libraries/SensorLSM9DS1/SensorLSM9DS1.h | 44 +- libraries/SensorLSM9DS1/library.json | 2 +- libraries/SoaapComDue/library.json | 2 +- libraries/SoaapMsg/library.json | 2 +- libraries/StateMachine/library.json | 2 +- libraries/environment/IntrfAdc.h | 161 +++ libraries/environment/IntrfMeas.h | 69 + libraries/environment/IntrfRadio.h | 3 +- libraries/environment/library.json | 2 +- libraries/nRF52840Adc/library.json | 4 + libraries/nRF52840Adc/nRF52840Adc.cpp | 265 ++++ libraries/nRF52840Adc/nRF52840Adc.h | 235 ++++ libraries/nRF52840Gpio/library.json | 2 +- libraries/nRF52840Gpio/nRF52840Gpio.cpp | 35 +- libraries/nRF52840Gpio/nRF52840Gpio.h | 6 +- libraries/nRF52840Radio/library.json | 2 +- libraries/nRF52840Radio/nRF52840Radio.cpp | 123 +- libraries/nRF52840Radio/nRF52840Radio.h | 20 +- libraries/nRF52840Ser/library.json | 2 +- libraries/nRF52840Twi/library.json | 2 +- .../SoaapBleMidiMaster/SoaapBleMidiMaster.h | 46 +- .../SoaapBleMidiMaster/SoaapBleMidiMaster.ino | 560 ++++++-- sketches/SoaapBleSlave/SoaapBleSlave.h | 71 + sketches/SoaapBleSlave/SoaapBleSlave.ino | 1250 +++++++++++++++++ sketches/ctrlMidi/SoaapMidi.h | 16 + sketches/pollingBLE/SoaapBleMaster.h | 58 + sketches/pollingBLE/SoaapBleSlave.h | 57 + 51 files changed, 4321 insertions(+), 220 deletions(-) create mode 100644 libraries/EulerAngles/EulerAngles.cpp create mode 100644 libraries/EulerAngles/EulerAngles.h create mode 100644 libraries/EulerAngles/library.json create mode 100644 libraries/GpioCtrl/GpioCtrl.cpp create mode 100644 libraries/GpioCtrl/GpioCtrl.h create mode 100644 libraries/GpioCtrl/library.json create mode 100644 libraries/LoopCheck/examples/lcBlink.ino create mode 100644 libraries/LoopCheck/examples/lcStatistics.ino create mode 100644 libraries/LoopCheck/examplesLinux/testCppArduino.cpp create mode 100644 libraries/LoopCheck/examplesWindows/README.md create mode 100644 libraries/LoopCheck/examplesWindows/testLoopCheck.txt create mode 100644 libraries/ProcMeas/ProcMeas.cpp create mode 100644 libraries/ProcMeas/ProcMeas.h create mode 100644 libraries/ProcMeas/library.json create mode 100644 libraries/environment/IntrfAdc.h create mode 100644 libraries/environment/IntrfMeas.h create mode 100644 libraries/nRF52840Adc/library.json create mode 100644 libraries/nRF52840Adc/nRF52840Adc.cpp create mode 100644 libraries/nRF52840Adc/nRF52840Adc.h create mode 100644 sketches/SoaapBleSlave/SoaapBleSlave.h create mode 100644 sketches/SoaapBleSlave/SoaapBleSlave.ino create mode 100644 sketches/ctrlMidi/SoaapMidi.h create mode 100644 sketches/pollingBLE/SoaapBleMaster.h create mode 100644 sketches/pollingBLE/SoaapBleSlave.h diff --git a/libraries/BlePoll/BlePoll.cpp b/libraries/BlePoll/BlePoll.cpp index f2b89ae..a895246 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,26 +1437,28 @@ 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 // -------------------------------------------------------------------------- // // neue Steuerungsdaten für einen Slave - +// void BlePoll::updControl(int adr, byte *ctrlList, int nr) { if(adr <= 0) return; if(adr >= MAXSLAVE) return; if(nr <= 1) return; - if(nr > 27) return; + 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++; @@ -1387,7 +1466,7 @@ void BlePoll::updControl(int adr, byte *ctrlList, int nr) } // Feststellenn, ob Übertragung der Steuerungsdaten erfolgt ist - +// bool BlePoll::ackTrans(int adr) { if(adr <= 0) return(false); @@ -1398,14 +1477,14 @@ bool BlePoll::ackTrans(int adr) } // Feststellen, ob Steuerungsdaten beim Slave verarbeitet sind - +// bool BlePoll::ackControl(int adr) { if(adr <= 0) return(false); if(adr >= MAXSLAVE) return(false); SlavePtr slavePtr = &slaveList[adr]; - PlpCtrl27Ptr ctrlPtr = (PlpCtrl27Ptr) &slavePtr->control; + 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,49 +1585,68 @@ int BlePoll::getMeas(int slAdr, byte *dest) return(anzByte); } -int BlePoll::getCtrlM(int slAdr, byte *dest){ - int anzByte; - PlpType appId; +/* +// Auslesen der Steuerwerte/Antwort +// +CtrlData2Ptr BlePoll::getCtrl(int slAdr) +{ - if(slAdr < 1) return(false); - if(slAdr >= MAXSLAVE) return(false); + if(slAdr < 1) return(NULL); + if(slAdr >= MAXSLAVE) return(NULL); - SlavePtr slavePtr = &slaveList[slAdr]; - appId = (PlpType) slavePtr->result.plData[0]; + 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: - anzByte = 0; break; case plptMeas9: - anzByte = 0; break; case plptMeas9Ctrl4: - anzByte = 4; + 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: - anzByte = 0; break; default: - anzByte = 0; break; } - for (int i = 0; i < anzByte; i++) - { - dest[i] = slavePtr->result.plData[i+20]; - } - - return(anzByte); + return(retv); } - - // -------------------------------------------------------------------------- // Debugging // -------------------------------------------------------------------------- @@ -1616,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 721d22c..4abe53d 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 @@ -219,7 +267,6 @@ typedef struct _PollInfo dword wrongs; // Anzahl ungewünschter Netzaktivitäten } PollInfo, *PollInfoPtr; - typedef struct _PollState { byte slIdx; // Index in der Slave-Liste @@ -256,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; @@ -283,6 +331,8 @@ private: IntrfRadio *radio; bcPdu pduOut; bcPdu pduIn; + bcPdu pollCtrl; + int lenPollCtrl; cbVector nextState; MicsecFuPtr micSec; cbDataPtr cbData; @@ -333,7 +383,8 @@ private: TxStatistics statistic; PlPduMeas valuePdu; - PlpCtrl27 ctrlPdu; + PlpCtrl25 ctrlPdu; + PlpCtrl25Ptr ctrlPduPtr; bool newValue; bool newCtrl; @@ -343,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 // -------------------------------------------------------------------------- @@ -356,7 +408,6 @@ private: bool getValues(bcPduPtr pduPtr, PlpType appId); bool getCtrls(bcPduPtr pduPtr, PlpType appId); - // Zustandsmaschine // ----------------------------- void smInit(); @@ -428,32 +479,11 @@ public: // -------------------------------------------------------------------------- // void run(); // Ablaufsteuerung (CPU-Übergabe) dieses Moduls -/** - * @brief Sendet neue Steuerungsdaten an einen Slave - * - * @param adr Addresse d. zu Steuernden Slaves - * @param ctrlList Liste mit Bytes zum Austausch der Steuerbytes - * @param nr Anzahl d. Steuerbytes - */ + void updControl(int adr, byte *ctrlList, int nr); // neue Steuerungsdaten - // -/** - * @brief Prüft ob Steuerungsdaten übertragen wurden - * - * @param adr Adresse d. Slaves - * @return true Erfolgreiche übertragung - * @return false Fehler in Übertragung / Falsche Adresse - */ bool ackTrans(int adr); // Bestätigung Steuerungsdaten übertragen - /** - * @brief Überprüft ob Steuerungsdaten korrekt übertragen wurden - * - * @param adr Adresse d. Slavrs - * @return true Daten erfolgreich verarbeitet - * @return false Fehler in Übertragung - */ bool ackControl(int adr); // Bestätigung Steuerung ausgeführt - + bool getCtrlResp(int adr, CtrlResp2Ptr ctlRspPtr); // Antwort auf Steuerdaten holen // Test // @@ -490,11 +520,11 @@ 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 - int getCtrlM(int slIdx, byte *dest); + 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 + // -------------------------------------------------------------------------- @@ -506,6 +536,7 @@ public: SlavePtr getSlavePtr(int idx); PollStatePtr getPollPtr(int idx); + int getCtrlData(byte *dest); }; diff --git a/libraries/BlePoll/library.json b/libraries/BlePoll/library.json index 477225b..527c685 100644 --- a/libraries/BlePoll/library.json +++ b/libraries/BlePoll/library.json @@ -1,4 +1,4 @@ { "name": "BlePoll", - "version": "0.0.0+20220804174235" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/ComRingBuf/library.json b/libraries/ComRingBuf/library.json index 054f2c8..5778404 100644 --- a/libraries/ComRingBuf/library.json +++ b/libraries/ComRingBuf/library.json @@ -1,4 +1,4 @@ { - "name": "BlePoll", - "version": "0.0.0+20220804174235" + "name": "ComRingBuf", + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/EulerAngles/EulerAngles.cpp b/libraries/EulerAngles/EulerAngles.cpp new file mode 100644 index 0000000..9495553 --- /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 0000000..7681c26 --- /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/EulerAngles/library.json b/libraries/EulerAngles/library.json new file mode 100644 index 0000000..06c82fe --- /dev/null +++ b/libraries/EulerAngles/library.json @@ -0,0 +1,4 @@ +{ + "name": "EulerAngles", + "version": "0.0.1+20221111" + } \ No newline at end of file diff --git a/libraries/GpioCtrl/GpioCtrl.cpp b/libraries/GpioCtrl/GpioCtrl.cpp new file mode 100644 index 0000000..19ba58e --- /dev/null +++ b/libraries/GpioCtrl/GpioCtrl.cpp @@ -0,0 +1,165 @@ +//----------------------------------------------------------------------------- +// Thema: Social Manufacturing Network / Development Environment +// Datei: GpioCtrl.cpp +// Editor: Robert Patzke +// URI/URL: www.mfp-portal.de +//----------------------------------------------------------------------------- +// Lizenz: CC-BY-SA (siehe Wikipedia: Creative Commons) +// + +#include "GpioCtrl.h" + +// -------------------------------------------------------------------------- +// Konstruktoren +// -------------------------------------------------------------------------- +// + +GpioCtrl::GpioCtrl(IntrfGpio *inGpioPtr, int inPeriod) +{ + gpioPtr = inGpioPtr; + period = inPeriod; +} + +// -------------------------------------------------------------------------- +// Konfigurationen +// -------------------------------------------------------------------------- +// + + + +// -------------------------------------------------------------------------- +// Anwendungsfunktionen allgemein +// -------------------------------------------------------------------------- +// +void GpioCtrl::run() +{ + BlinkPtr blinkPtr; + + for(int i = 0; i < MaxGpioElements; i++) + { + // ----------------------------------------------------------------------- + // run blink + // ----------------------------------------------------------------------- + // + blinkPtr = &blinkEl[i]; + + if(blinkPtr->doBlink && (blinkPtr->portRef != NULL)) + { + // Blinken wird aktiviert/deaktiviert + // -------------------------------------------------------- + if(!blinkPtr->blinked) // Noch kein Blinken + { + if(!blinkPtr->portSet) // Port noch nicht gesetzt + { + if(blinkPtr->invPort) + gpioPtr->clr(blinkPtr->portRef); + else + gpioPtr->set(blinkPtr->portRef); + blinkPtr->portSet = true; + } + + if(blinkPtr->blinkLen > 0) + blinkPtr->blinkLen--; + else + { + blinkPtr->blinked = true; + blinkPtr->blinkLen = blinkPtr->blinkLenSet; + } + } + else // blinked + { + if(blinkPtr->portSet) // Port ist gesetzt + { + if(blinkPtr->invPort) + gpioPtr->set(blinkPtr->portRef); + else + gpioPtr->clr(blinkPtr->portRef); + blinkPtr->portSet = false; + } + + if(blinkPtr->repeatPause > 0) + { + blinkPtr->repeatPause--; + } + else if(blinkPtr->repeat > 0) + { + blinkPtr->repeat--; + blinkPtr->repeatPause = blinkPtr->repeatPauseSet; + blinkPtr->blinked = false; + } + else + { + if(blinkPtr->blinkPause > 0) + blinkPtr->blinkPause--; + else + { + blinkPtr->blinked = false; + blinkPtr->blinkPause = blinkPtr->blinkPauseSet; + blinkPtr->repeat = blinkPtr->repeatSet; + blinkPtr->repeatPause = blinkPtr->repeatPauseSet; + } + } + } + // -------------------------------------------------------- + } // doBlink, portRef + } // for +} // run + +// -------------------------------------------------------------------------- +// Anwendungsfunktionen Steuerung der Pins +// -------------------------------------------------------------------------- +// + +void GpioCtrl::blink(GpioExtRefPtr portRef, int chn, int len, int pause) +{ + blink(portRef,chn,len,0,pause,0,false); +} + +void GpioCtrl::blink(GpioExtRefPtr portRef, int chn, int len, int pause, bool invert) +{ + blink(portRef,chn,len,0,pause,0,invert); +} + +void GpioCtrl::blink(GpioExtRefPtr portRef, int chn, int len, int wait, int pause, int repeat, bool invert) +{ + BlinkPtr blinkPtr; + int calc; + + if(chn < 0 || chn >= MaxGpioElements) return; + if(len <= 0) return; + if(period == 0) return; + + blinkPtr = &blinkEl[chn]; + blinkPtr->portRef = portRef; + blinkPtr->invPort = invert; + + calc = (1000 * len) / period; + if(calc == 0) + calc = 1; + blinkPtr->blinkLen = blinkPtr->blinkLenSet = calc; + + calc = (1000 * pause) / period; + if(calc == 0) + calc = 1; + blinkPtr->blinkPause = blinkPtr->blinkPauseSet = calc; + + if(repeat != 0) + { + blinkPtr->repeat = blinkPtr->repeatSet = repeat; + + calc = (1000 * wait) / period; + if(calc == 0) + calc = 1; + blinkPtr->repeatPause = blinkPtr->repeatPauseSet = calc; + } + + blinkPtr->blinked = false; + blinkPtr->doBlink = true; + blinkPtr->portSet = false; +} + + +// ---------------------------------------------------------------------------- +// Ereignisbearbeitung und Interrupts +// ---------------------------------------------------------------------------- +// diff --git a/libraries/GpioCtrl/GpioCtrl.h b/libraries/GpioCtrl/GpioCtrl.h new file mode 100644 index 0000000..8374bdd --- /dev/null +++ b/libraries/GpioCtrl/GpioCtrl.h @@ -0,0 +1,91 @@ +//----------------------------------------------------------------------------- +// Thema: Social Manufacturing Network / Development Environment +// Datei: GpioCtrl.h +// Editor: Robert Patzke +// URI/URL: www.mfp-portal.de +//----------------------------------------------------------------------------- +// Lizenz: CC-BY-SA (siehe Wikipedia: Creative Commons) +// +#ifndef GpioCtrl_h +#define GpioCtrl_h +//----------------------------------------------------------------------------- + +#include "stdio.h" +#include "IntrfGpio.h" + +#define MaxGpioElements 4 + +class GpioCtrl +{ + // -------------------------------------------------------------------------- + // spezifische Datentypen + // -------------------------------------------------------------------------- + // + typedef struct _Blink + { + int blinkLen; + int blinkLenSet; + int blinkPause; + int blinkPauseSet; + int repeat; + int repeatSet; + int repeatPause; + int repeatPauseSet; + bool doBlink; + bool blinked; + bool portSet; + bool invPort; + GpioExtRefPtr portRef; + } Blink, *BlinkPtr; + +private: + // -------------------------------------------------------------------------- + // lokale Variablen + // -------------------------------------------------------------------------- + // + IntrfGpio *gpioPtr; // Referenz auf Pin-Treiber + Blink blinkEl[MaxGpioElements]; // Liste der Blinkelemente + int period; // Aufrufperiode in Mikrosekunden + + // -------------------------------------------------------------------------- + // lokale Funktionen + // -------------------------------------------------------------------------- + // + +public: + // -------------------------------------------------------------------------- + // Konstruktoren + // -------------------------------------------------------------------------- + // + GpioCtrl(IntrfGpio *inGpioPtr, int inPeriod); + + // -------------------------------------------------------------------------- + // Konfigurationen + // -------------------------------------------------------------------------- + // + + // -------------------------------------------------------------------------- + // Anwendungsfunktionen + // -------------------------------------------------------------------------- + // + void run(); + void blink(GpioExtRefPtr portRef, int chn, int len, int pause); + void blink(GpioExtRefPtr portRef, int chn, int len, int pause, bool invert); + void blink(GpioExtRefPtr portRef, int chn, int len, int wait, int pause, int repeat); + void blink(GpioExtRefPtr portRef, int chn, int len, int wait, int pause, int repeat, bool invert); + + + // ---------------------------------------------------------------------------- + // Ereignisbearbeitung und Interrupts + // ---------------------------------------------------------------------------- + // + + // -------------------------------------------------------------------------- + // Debugging und globale Variablen + // -------------------------------------------------------------------------- + // + +}; + +//----------------------------------------------------------------------------- +#endif // GpioCtrl_h diff --git a/libraries/GpioCtrl/library.json b/libraries/GpioCtrl/library.json new file mode 100644 index 0000000..175b326 --- /dev/null +++ b/libraries/GpioCtrl/library.json @@ -0,0 +1,4 @@ +{ + "name": "GpioCtrl", + "version": "0.0.1+20221111" + } \ No newline at end of file diff --git a/libraries/LoopCheck/examples/lcBlink.ino b/libraries/LoopCheck/examples/lcBlink.ino new file mode 100644 index 0000000..89bfdb2 --- /dev/null +++ b/libraries/LoopCheck/examples/lcBlink.ino @@ -0,0 +1,81 @@ +// Demo-Program for using library LoopCheck with Arduino +#include "Arduino.h" + +#include "LoopCheck.h" + +#define TestLed 13 +// The built in LED of some Arduino boards (and similar development boards like +// ESP32 Dev) seem to be connected to a pin (most 13), which is also used for the +// serial transmit (TxD) or other purposes. +// The blink example of Arduino works, because they switch the pin and then +// they freeze the program bei function <delay(milliseconds)>. +// But if you leave loop() for Arduino internal functions, the pin is +// no more valid, it is used for TxD (or some other purpose). +// In other words, with some (many?) boards, the blink example of Arduino does +// not work without the delay in loop-function. +// Because we now use a software-timer instead of a delay, +// we must use another pin to connect our own LED or look for a built-in LED +// which is not used outside loop-function. +// E.g. the blue LED of ESP32 DEVKIT V1 (doit) is connected at pin 2. + +LoopCheck loopCheck; +// Creating an instance of class LoopCheck +// Some compilers take a huge basic load of program space, if you use the +// new operator. That is the reason, why we use a static instantiation. + +//The setup function is called once at startup of the sketch +// +void setup() +{ + pinMode(TestLed, OUTPUT); + // Setting a free pin for output (connect a LED via serial resistor) +} + +// The loop function is called in an endless loop +// +void loop() +{ + loopCheck.begin(); + // This method has to be called, whenever entering the cyclic used function + + if(loopCheck.timerMilli(0, 500, 0)) + { + // This is a timer of LoopCheck: + // The first argument is an index (0 - NrOfTimerTasks) which is identifying + // a timer. timerMicro and timerMilli use the same function in LooopCheck.cpp + // and so You have only NrOfLoopTasks timers, either timerMilli or timerMicro. + // The second argument is the cycle time (in milliseconds with timerMilli + // and in microseconds with timerMicro. + // The third argument is the number of cycles. The value 0 stands for an + // endless running of the timer. + + if(loopCheck.toggle(0)) + { + // This is a toggle of LoopCheck: + // This function returns alternating true and false. The argument is an + // index (0 - NrOfToggleTasks) to identify the toggle. There is no relation + // between the indexes of timers and toggles. + + digitalWrite(TestLed, HIGH); + // Switching on the LED at pin TestLed + } + else + { + digitalWrite(TestLed, LOW); + // Switching off the LED + } + } + + loopCheck.end(); + // This method has to be called, whenever leaving the cyclic used function +} + +// With using LoopCheck, the blinking of a LED does not freeze the loop function. +// Depending on the speed of your CPU, this programm takes mikroseconds or only +// fractions of microsecond in one loop and the LED is switched on and off every second. +// You can use up to NrOfTimerTask timers (defined in LoopCheck.h) inside loop +// without creating a big load for the CPU. +// The timers do not fire in the same cycle. If You use many timers, they do +// not meet in the same cycle of the loop. So it will not happen, that your +// application creates a long duration of loop if all timers meet the same +// ending time. diff --git a/libraries/LoopCheck/examples/lcStatistics.ino b/libraries/LoopCheck/examples/lcStatistics.ino new file mode 100644 index 0000000..e2af591 --- /dev/null +++ b/libraries/LoopCheck/examples/lcStatistics.ino @@ -0,0 +1,127 @@ +// Using LoopCheck-Library for information about the loop +// + +#include "Arduino.h" +#include "LoopCheck.h" + +LoopCheck loopCheck; +// Creating an instance of class LoopCheck +// Some compilers take a huge basic load of program space, if you use the +// new operator. That is the reason, why we use a static instantiation. + + +//The setup function is called once at startup of the sketch +// +void setup() +{ + Serial.begin(115200); + // Prepare serial interface to print information + + Serial.println("Example for using loop statistics"); +} + +OpHourMeter cpuRunTime; +// This structure will hold the runtime of the CPU since reset +// organised in years,days,hours,minutes,seconds and milliseconds +// after calling <operationTime> + +LoopStatistics statistics; +// This structure will hold statistical information about the loop +// after calling <getStatistics> + +bool useDelay; +// A marker to show the influence of delay function on LoopCheck operation time + +#ifndef smnESP32 + +char sprintMem[64]; +// with ESP32 there is the function Serial.printf defined, but not with DUE +// so we need some memory for preperation of text for using print with DUE + +#endif + +// The loop function is called in an endless loop +// +void loop() +{ + loopCheck.begin(); + // This method has to be called, whenever entering the cyclic used function + + if(loopCheck.once(0,1)) + { + // 1. arg is task index (0-7), 2. arg is loop number + // I.e. : do only once with the first loop + useDelay = true; + // Of course this could be better done in the setup-function (above), + // but it is a chance to show the once-function of LoopCheck. + // Mind the 2. argument, you can do setups subsequently because + // once-function is skipping the entered number of loops + } + + if(loopCheck.timerMilli(0, 1000, 25)) + { + // The timer-function returns true whenever 1000 milliseconds passed + // but only 25 times + // The example <lcBlink.ino> for more details + + loopCheck.operationTime(&cpuRunTime); + +#ifdef smnESP32 + Serial.printf("%02dH,%02dm,%02ds\r\n", + cpuRunTime.Hours,cpuRunTime.Minutes,cpuRunTime.Seconds); +#else + sprintf(sprintMem, "%02dH,%02dm,%02ds\r\n", + cpuRunTime.Hours,cpuRunTime.Minutes,cpuRunTime.Seconds); + Serial.print(sprintMem); +#endif + } + + if(useDelay == true) delay(33); + // To have something to measure for the statistical information + // But see the influence on the operation time at the end of the code + + if(loopCheck.timerMilli(1, 2000, 10)) + { + // Do the following every 2 seconds but only 10 times + + loopCheck.getStatistics(&statistics); + +#ifdef smnESP32 + Serial.printf("AvgInLoopTime: %05d[us], AvgOutLoopTime: %05d[us]\r\n", + statistics.loopAvgTime,statistics.bgAvgTime); +#else + sprintf(sprintMem, "AvgInLoopTime: %05d[us], AvgOutLoopTime: %05d[us]\r\n", + statistics.loopAvgTime,statistics.bgAvgTime); + Serial.print(sprintMem); +#endif + +#ifdef smnESP32 + Serial.printf("LoopPeriodAlarm: %d, AlarmCounter: %d\r\n", + statistics.periodAlarm,statistics.alarmCount); +#else + sprintf(sprintMem,"LoopPeriodAlarm: %d, AlarmCounter: %d\r\n", + statistics.periodAlarm,statistics.alarmCount); + Serial.print(sprintMem); +#endif + } + + if(loopCheck.timerMilli(2, 10000, 1)) + { + // switch off the delay after 10 seconds + useDelay = false; + } + + loopCheck.end(); + // This method has to be called, whenever leaving the cyclic used function +} + +// This example looks rather complex for simply showing the elapsed operation time. +// But it had to be shown, that the operation time counter only works +// if the loop cycle time (time between two following loops) is less than +// 1 millisecond. +// This is not a mistake. LoopCheck was built to watch and control the behaviour +// of the Arduino loop and it shall be handled as a mistake, if you write a +// program that holds the CPU such a long time. +// Check the statistics to observe also the influence of resources running in background. + + diff --git a/libraries/LoopCheck/examplesLinux/testCppArduino.cpp b/libraries/LoopCheck/examplesLinux/testCppArduino.cpp new file mode 100644 index 0000000..57b8c06 --- /dev/null +++ b/libraries/LoopCheck/examplesLinux/testCppArduino.cpp @@ -0,0 +1,38 @@ +//============================================================================ +// Name : testCppArduino.cpp +// Author : Robert Patzke +// Version : +// Copyright : (c) MFP 2017 +// Description : Hello World in C++, Ansi-style +//============================================================================ + +#include <stdlib.h> +#include <stdio.h> +#include <time.h> + +#include "LoopCheck.h" +// environment.h will be included in LoopCheck.h +// You have to #define smnSimLinux there for IDE +// and comment out other definitions + +LoopCheck loopCheck; + +int main() +{ + printf("Test Arduino Software Environment\n"); + printf("Endless loop, terminate with Ctrl-C\n"); + + while(1) + { + loopCheck.begin(); + + if(loopCheck.timerMilli(0, 1000, 0)) + { + printf(".\n"); + } + + loopCheck.end(); + } + + return 0; +} diff --git a/libraries/LoopCheck/examplesWindows/README.md b/libraries/LoopCheck/examplesWindows/README.md new file mode 100644 index 0000000..1951370 --- /dev/null +++ b/libraries/LoopCheck/examplesWindows/README.md @@ -0,0 +1,2 @@ +Zur Kompatibilität mit platformIO wurde die Datei testLoopCheck umbenannt. +Wenn die Datei verwendet werden soll, muss die Dateiendung wieder auf .cpp geändert werden. \ No newline at end of file diff --git a/libraries/LoopCheck/examplesWindows/testLoopCheck.txt b/libraries/LoopCheck/examplesWindows/testLoopCheck.txt new file mode 100644 index 0000000..86ed449 --- /dev/null +++ b/libraries/LoopCheck/examplesWindows/testLoopCheck.txt @@ -0,0 +1,145 @@ +//----------------------------------------------------------------------------- +// Thema: Social Manufacturing Network / Software Loop Checking and Timing +// Datei: testLoopCheck.cpp +// Editor: Robert Patzke +// URI/URL: www.mfp-portal.de +//----------------------------------------------------------------------------- +// Lizenz: CC-BY-SA (see Wikipedia: Creative Commons) +// +// This program was developed and tested with Visual Studio 2010 +// Following configuration has to be done in C/C++ -> Preprocessor Definitions +// +// UseGithubPath +// Visual Studio searches for includes in the environment of the sources. +// With the switch UseGithubPath the #include directives in source files are +// relativ to the structure of the tree as it is used on Github repository. +// So it will work after simple copying the tree from Github. +// +// smnDEFBYBUILD +// With this switch the first part of file environment.h will be used. +// It is possible to use environment.h for many purposes. +// Without defining smnDEFBYBUILD the file has to be edited to fit to your IDE +// and your microcontroller targets +// +// smnWIN32_VS +// This switch opens a list of definitions in environment.h controlling +// conditional compilation in many source files + +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <sys/timeb.h> + +#include "../LoopCheck.h" + +LoopCheck loopCheck; + +int main(int argc, char *argv[]) +{ + time_t timeSec; + struct tm *timeStructPtr; + struct timeb ftimeStruct; + lcDateTime dateTime; + int msecOldPC, msecOldLC, msecOldOP; + int secOldPC, secOldLC, secOldOP; + LoopStatistics statistic; + + // ------------------------------------------------------------------------- + // setup + // ------------------------------------------------------------------------- + // + printf("Testing simulation of Arduino with Windows\n"); + printf("Check loop behaviour with LoopCheck, demonstrate clocks\n"); + + // Getting PC time with milliseconds resolution + // + ftime(&ftimeStruct); + timeSec = ftimeStruct.time; + timeStructPtr = gmtime(&timeSec); + + // Preparing some Variables to calculate and show time difference + // + msecOldPC = msecOldLC = dateTime.Millisecond = ftimeStruct.millitm; + secOldPC = secOldLC = dateTime.Second = timeStructPtr->tm_sec; + + // Setting the software clock of LoopCheck to PC time + // + dateTime.Minute = timeStructPtr->tm_min; + dateTime.Hour = timeStructPtr->tm_hour; + dateTime.Day = timeStructPtr->tm_mday; + dateTime.Month = timeStructPtr->tm_mon + 1; + dateTime.Year = timeStructPtr->tm_year + 1900; + + loopCheck.setDateTime(dateTime); + + // ------------------------------------------------------------------------- + // loop + // ------------------------------------------------------------------------- + // + while(1) + { + loopCheck.begin(); // this function has to be called first in loop + // ----------------------------------------------------------------------- + + // Comparing the software clock with the PC clock and showing the difference + // + if(loopCheck.timerMilli(0,1000,0)) + { + // + // This gets true once every second (1000 milliseconds) + // The error is that of the PC counter (clock or performance timer) + + // Get the current PC time with milliseconds + // + ftime(&ftimeStruct); + timeSec = ftimeStruct.time; + timeStructPtr = gmtime(&timeSec); + + // Get the current time of LoopCheck software clock + // + loopCheck.getDateTime(&dateTime); + + // Show the PC time and the LoopCheck time and their differences to the last measurement + // a second back (do not mind the overflow error with the distance) + // + printf("PC Time = %02d:%02d:%02d,%03d Diff=%4d LC Time = %02d:%02d:%02d,%03d Diff=%4d\n", + timeStructPtr->tm_hour, timeStructPtr->tm_min, timeStructPtr->tm_sec, ftimeStruct.millitm, + ftimeStruct.millitm - msecOldPC + 1000*(timeStructPtr->tm_sec - secOldPC), + dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond, + dateTime.Millisecond - msecOldLC + 1000*(dateTime.Second - secOldLC)); + // + // You will see, that the timer of LoopCheck is rather accurate. + // The variation of repetition time is less than 1% with some exceptions. + // Also the LoopCheck software clock is nearly perfect, because the + // underlaying counters are synchronised to the OS clock + + // preperation for the measurement of next cycle + // + msecOldPC = ftimeStruct.millitm; + msecOldLC = dateTime.Millisecond; + secOldPC = timeStructPtr->tm_sec; + secOldLC = dateTime.Second; + + // to show the difference between microcontrollers and OS based computers + // we will look into the statistics of LoopCheck + // + loopCheck.getStatistics(&statistic); + + // alarmCount is incremented, whenever the time between 2 loops exceeds PeriodMinTime + // (adjust PeriodMinTime in LoopCheck.h for your target system) + // + printf("Loop violations: %4d ", statistic.alarmCount); + // + // we have also a classification of exceeding the millisecond of loop cycle time + // counting the number of exceedings indexed by number of milliseconds. + // + for(int i = 0; i < LoopScreeningGrades - 1; i++) + printf(" %2dms: %4d", i+1 , statistic.rtSreening[i]); + printf(" >%2dms: %4d\r\n\n", LoopScreeningGrades - 1, statistic.rtSreening[LoopScreeningGrades - 1]); + + } + + // ----------------------------------------------------------------------- + loopCheck.end(); // this function has to be called last in the loop + } +} diff --git a/libraries/LoopCheck/library.json b/libraries/LoopCheck/library.json index 3af6924..56fba8d 100644 --- a/libraries/LoopCheck/library.json +++ b/libraries/LoopCheck/library.json @@ -1,4 +1,32 @@ { "name": "LoopCheck", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111", + "examples": [ + { + "name": "lcBlink", + "base": "examples", + "files": ["lcBlink.ino"] + }, + { + "name": "lcStatistics", + "base": "examples", + "files": ["lcStatistics.ino"] + }, + { + "name": "testCppArduino", + "base": "examplesLinux", + "files": ["testArduino.cpp"] + }, + { + "name": "testLoopCheck", + "base": "examplesWindows", + "files": ["testLoopCheck.cpp"] + } +], +"built": { + "srcFilter" : ["-<./examples>","-<./examplesLinux>","-<./examplesWindows>"] +}, +"export":{ + "exclude" : ["./examples", "./examplesLinux","./examplesWindows"] +} } \ No newline at end of file diff --git a/libraries/MidiNotes/library.json b/libraries/MidiNotes/library.json index a95d689..42acf47 100644 --- a/libraries/MidiNotes/library.json +++ b/libraries/MidiNotes/library.json @@ -1,4 +1,4 @@ { "name": "MidiNotes", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/Monitor/Monitor.cpp b/libraries/Monitor/Monitor.cpp index 9c30d24..8efd09b 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 1ee2bb1..3af0a9a 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/Monitor/library.json b/libraries/Monitor/library.json index a9b2811..0509f4e 100644 --- a/libraries/Monitor/library.json +++ b/libraries/Monitor/library.json @@ -1,4 +1,4 @@ { "name": "Monitor", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/ProcMeas/ProcMeas.cpp b/libraries/ProcMeas/ProcMeas.cpp new file mode 100644 index 0000000..bd0fd7e --- /dev/null +++ b/libraries/ProcMeas/ProcMeas.cpp @@ -0,0 +1,97 @@ +//----------------------------------------------------------------------------- +// Thema: Social Manufacturing Network / Process Measurements +// Datei: ProcMeas.cpp +// Editor: Robert Patzke +// URI/URL: www.mfp-portal.de +//----------------------------------------------------------------------------- +// Lizenz: CC-BY-SA (siehe Wikipedia: Creative Commons) +// + +#include "ProcMeas.h" + +// --------------------------------------------------------------------------- +// Konstruktoren und Initialisierungen +// --------------------------------------------------------------------------- +// +ProcMeas::ProcMeas(IntrfMeas *measPtr) +{ + pMeas = measPtr; + gravAnglesAvail = false; + pmState = pmInit; + gravSigns = 0; +#ifdef ProcMeasDebug + memset(&statistics,0,sizeof(Statistics)); +#endif +}; + +// --------------------------------------------------------------------------- +// Anwenderfunktionen +// --------------------------------------------------------------------------- +// + +void ProcMeas::run() +{ + if(pMeas == NULL) return; + + switch(pmState) + { + case pmInit: +#ifdef ProcMeasDebug + statistics.pmInitCnt++; +#endif + pmState = pmWait; + break; + + case pmWait: +#ifdef ProcMeasDebug + statistics.pmWaitCnt++; +#endif + if(pMeas->available(1, 1)) + { + pMeas->getValues(1, 1, &gravAngles); + gravSigns = pMeas->getSigns(1, 1); + pmState = pmCalc; + } + break; + + case pmCalc: +#ifdef ProcMeasDebug + statistics.pmCalcCnt++; +#endif + posture.pitch = euler.getPitchFromGravity(gravAngles.x, gravAngles.y, gravAngles.z) * RAD_TO_DEG; + posture.roll = euler.getRollFromGravity(gravAngles.y, gravAngles.z) * RAD_TO_DEG; + posture.yaw = 0.0; + pMeas->sync(1, 1); + gravAnglesAvail = true; + pmState = pmWait; + break; + } +} + +bool ProcMeas::availAngles(bool reset) +{ + if(!gravAnglesAvail) return(false); + if(reset) gravAnglesAvail = false; + return(true); +} + +float ProcMeas::getRollValue() +{ + return(posture.roll); +} + +float ProcMeas::getPitchValue() +{ + return(posture.pitch); +} + +float ProcMeas::getYawValue() +{ + return(posture.yaw); +} + +byte ProcMeas::getGravSigns() +{ + return(gravSigns); +} + diff --git a/libraries/ProcMeas/ProcMeas.h b/libraries/ProcMeas/ProcMeas.h new file mode 100644 index 0000000..e0b14eb --- /dev/null +++ b/libraries/ProcMeas/ProcMeas.h @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// Thema: Social Manufacturing Network / Process Measurements +// Datei: ProcMeas.h +// Editor: Robert Patzke +// URI/URL: www.mfp-portal.de +//----------------------------------------------------------------------------- +// Lizenz: CC-BY-SA (siehe Wikipedia: Creative Commons) +// +#ifndef _ProcMeas_h +#define _ProcMeas_h +//----------------------------------------------------------------------------- + +#include <stddef.h> +#include <string.h> +#include "arduinoDefs.h" +#include "IntrfMeas.h" +#include "EulerAngles.h" + +//#define ProcMeasDebug + +typedef enum _PmState +{ + pmInit, + pmWait, + pmCalc +} PmState; + +typedef struct _Posture +{ + float roll; + float pitch; + float yaw; +}Posture, *PosturePtr; + +// --------------------------------------------------------------------------- +// class ProcMeas +// --------------------------------------------------------------------------- +// +class ProcMeas +{ + // ------------------------------------------------------------------------- + // Klassenspezifische Datentypen + // ------------------------------------------------------------------------- + // +#ifdef ProcMeasDebug + typedef struct _Statistics + { + dword pmInitCnt; + dword pmWaitCnt; + dword pmCalcCnt; + } Statistics, *StatisticsPtr; +#endif + +private: + // ------------------------------------------------------------------------- + // Lokale Variablen + // ------------------------------------------------------------------------- + // + bool gravAnglesAvail; + IntrfMeas *pMeas; + TriFloat gravAngles; + byte gravSigns; + PmState pmState; + EulerAngles euler; + Posture posture; + +private: + // ------------------------------------------------------------------------- + // Lokale Funktionen + // ------------------------------------------------------------------------- + // + +public: + // ------------------------------------------------------------------------- + // Konstruktoren und Initialisierungen + // ------------------------------------------------------------------------- + // + ProcMeas(IntrfMeas *measPtr); + + // ------------------------------------------------------------------------- + // Anwenderfunktionen + // ------------------------------------------------------------------------- + // + void run(); + bool availAngles(bool reset); + float getRollValue(); + float getPitchValue(); + float getYawValue(); + byte getGravSigns(); + + // ------------------------------------------------------------------------- + // Debug-Funtionen + // ------------------------------------------------------------------------- + // +#ifdef ProcMeasDebug + Statistics statistics; + +#endif + + + +}; + +//----------------------------------------------------------------------------- +#endif // _ProcMeas_h + diff --git a/libraries/ProcMeas/library.json b/libraries/ProcMeas/library.json new file mode 100644 index 0000000..b488de4 --- /dev/null +++ b/libraries/ProcMeas/library.json @@ -0,0 +1,4 @@ +{ + "name": "ProcMeas", + "version": "0.0.1+20221111" + } \ No newline at end of file diff --git a/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp b/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp index 5a57198..d08f0cb 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 63cb831..179aabe 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/SensorLSM9DS1/library.json b/libraries/SensorLSM9DS1/library.json index 6432e5c..4e9466a 100644 --- a/libraries/SensorLSM9DS1/library.json +++ b/libraries/SensorLSM9DS1/library.json @@ -1,4 +1,4 @@ { "name": "SensorLSM9DS1", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/SoaapComDue/library.json b/libraries/SoaapComDue/library.json index d2cf151..d2f5532 100644 --- a/libraries/SoaapComDue/library.json +++ b/libraries/SoaapComDue/library.json @@ -1,4 +1,4 @@ { "name": "SoaapComDue", - "version": "0.0.0+20220804174235" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/SoaapMsg/library.json b/libraries/SoaapMsg/library.json index 86be2b9..7b6bd50 100644 --- a/libraries/SoaapMsg/library.json +++ b/libraries/SoaapMsg/library.json @@ -1,4 +1,4 @@ { "name": "SoaapMsg", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/StateMachine/library.json b/libraries/StateMachine/library.json index 4dbee44..2a474a2 100644 --- a/libraries/StateMachine/library.json +++ b/libraries/StateMachine/library.json @@ -1,4 +1,4 @@ { "name": "StateMachine", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/environment/IntrfAdc.h b/libraries/environment/IntrfAdc.h new file mode 100644 index 0000000..a27634a --- /dev/null +++ b/libraries/environment/IntrfAdc.h @@ -0,0 +1,161 @@ +//----------------------------------------------------------------------------- +// Thema: Social Manufacturing Network / Development Environment +// Datei: IntrfAdc.h +// Editor: Robert Patzke +// URI/URL: www.mfp-portal.de +//----------------------------------------------------------------------------- +// Lizenz: CC-BY-SA (wikipedia: Creative Commons) +// Datum: 03. Oktober 2022 +// +// Eine Schnittstelle zur A/D-Wandlung +// + +#ifndef IntrfAdc_h +#define IntrfAdc_h +// ---------------------------------------------------------------------------- + +#include "arduinoDefs.h" + +class IntrfAdc +{ +public: + // -------------------------------------------------------------------------- + // Spezifische Datentypen und Zuordnungen + // -------------------------------------------------------------------------- + // ACHTUNG! + // Dies ist eine Übermenge für alle eingesetzten Mikrocontroller. + // Bei Bedarf werden diese Festlegungen erweitert. + +typedef struct _Statistic +{ + dword interrupts; +} Statistic, *StatisticPtr; + +// Konfiguration des ADC-Eingangs +// +typedef struct _chnConf +{ + dword inpResistorP : 1; // Widerstand zugeschaltet an P-Eingang + dword inpPullUpP : 1; // P-Eingangswiderstand als Pull-Up + dword inpVoltP : 1; // Spannung am P-Eingang + dword inpResistorN : 1; // Widerstand zugeschaltet an N-Eingang + dword inpPullUpN : 1; // N-Eingangswiderstand als Pull-Up + dword inpVoltN : 1; // Spannung am N-Eingang + dword diffMode : 1; // Differenzmodus + dword burst : 1; // Oversampling aktiviert + dword externRef : 1; // externe Referenz +} ChnConf; + +// Kennzeichnung des ADC-Kanals (PIN-Zuweisung extra) +// +enum ChnNr +{ + sc1, // Single-ended Kanal 1 + sc2, + sc3, + sc4, + sc5, + sc6, + sc7, + sc8, + dc1, // Differenzkanal 1 + dc2, + dc3, + dc4, + sAll, // Alle SE-Kanäle (gleiche Konfiguration) + dAll, // Alle Differenzkanäle (gleiche Konfiguration) + mc1, // Mix-Messung, 1xDiff, 2xSE, Kanal 1 + mc2, + mc3, + mc4 +}; + +// Kennzeichnung der Eingansanschlüsse (Pins) +// Das orientiert sich an durchnummerierten festen Pins für Analogeingänge +// Wenn mehr Pins nutzbar sind, als ADC-Kanäle existieren, dann muss ein +// spezifisches Mapping erfolgen +// Besondere Eingänge (z.B. Versorgungsspannung, Temperatur, etc.) sind +// spezifisch für den jeweiligen Mikrocontroller auszuweisen +// +enum PinNr +{ + noConn, // nicht angeschlossen + aInp1, // Analogeingang 1 + aInp2, + aInp3, + aInp4, + aInp5, + aInp6, + aInp7, + aInp8, + aInpSp1, // Spezialeingang 1 (z.B. VDD) + aInpSp2, + aInpSp3, + aInpChn // Direkte Kanalzuordnung +}; + +// Einstellung der Haltezeit (Kondensator) am Eingang des ADC +// +enum AcqTime +{ + acqtUndefined, + acqt1us, // Haltezeit 1 Mikrosekunde + acqt2us, + acqt3us, + acqt5us, + acqt10us, + acqt15us, + acqt20us, + acqt30us, + acqt40us, + acqt50us, + acqt100us +}; + +// Einstellung der Vorverstärkung +// +enum PreGain +{ + pgUndefined, + pg1_6, // 1/6 + pg1_5, + pg1_4, + pg1_3, + pg1_2, // 1/2 + pg1, + pg2, + pg4, // 4 + pg8, + pg16 +}; + + // -------------------------------------------------------------------------- + // Konfigurationen + // -------------------------------------------------------------------------- + // + virtual void config // Konfigurieren eines Adc-Kanals + ( + PinNr pinNrP, // Anschlusspin + (Analogeingang) + PinNr pinNrN, // Anschlusspin - (noConn bei Single-Ended) + ChnNr chnNr, // Kanalnummer + ChnConf conf, // Konfigurationsdetails (Auswahl) + AcqTime acqt, // Haltezeit + PreGain pg // Vorverstärkung + ); + + // -------------------------------------------------------------------------- + // Steuerfunktionen + // -------------------------------------------------------------------------- + // + virtual void begin(); // Starten des Betriebs nach der Konfiguration + + + // -------------------------------------------------------------------------- + // Datenzugriffe + // -------------------------------------------------------------------------- + // + +}; + +// ---------------------------------------------------------------------------- +#endif // IntrfAdc_h diff --git a/libraries/environment/IntrfMeas.h b/libraries/environment/IntrfMeas.h new file mode 100644 index 0000000..556b7ed --- /dev/null +++ b/libraries/environment/IntrfMeas.h @@ -0,0 +1,69 @@ +//----------------------------------------------------------------------------- +// Thema: Social Manufacturing Network / Development Environment +// Datei: IntrfMeas.h +// Editor: Robert Patzke +// URI/URL: www.mfp-portal.de +//----------------------------------------------------------------------------- +// Lizenz: CC-BY-SA (wikipedia: Creative Commons) +// Datum: 23. September 2022 +// +// Eine Schnittstelle zur Messwererfassung +// + +#ifndef IntrfMeas_h +#define IntrfMeas_h +// ---------------------------------------------------------------------------- + +#include "arduinoDefs.h" + +#define signX 0x01 +#define deltaSignX 0x02 +#define signY 0x04 +#define deltaSignY 0x08 +#define signZ 0x10 +#define deltaSignZ 0x20 +#define signAll 0x40 +#define deltaSignAll 0x80 +#define chkSignAll 0x15 + +typedef struct _TriFloat +{ + float x; + float y; + float z; +} TriFloat, *TriFloatPtr; + +typedef struct _TriSenseSigns +{ + byte signsAcc; + byte signsGyro; + byte signsMag; +} TriSenseSigns, *TriSenseSignsPtr; + +class IntrfMeas +{ +public: + // -------------------------------------------------------------------------- + // Konfigurationen + // -------------------------------------------------------------------------- + // + + // -------------------------------------------------------------------------- + // Steuerfunktionen + // -------------------------------------------------------------------------- + // + + + // -------------------------------------------------------------------------- + // Datenzugriffe + // -------------------------------------------------------------------------- + // + virtual void sync(int type, int code); + virtual bool available(int type, int code); + virtual int getValues(int type, int code, void *dataPtr); + virtual byte getSigns(int type, int code); + +}; + +// ---------------------------------------------------------------------------- +#endif // IntrfMeas_h diff --git a/libraries/environment/IntrfRadio.h b/libraries/environment/IntrfRadio.h index 470277a..798ded9 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 // @@ -131,7 +132,7 @@ public: virtual bool disabled(TxMode txMode); // Abfrage, ob ausgeschaltet virtual void cont(TxMode txMode); // aktuellen Vorgang fortsetzen virtual bool fin(TxMode txMode, bool *err); // Abfrage ob aktueller Vorgang beendet -// virtual int getRecData(bcPduPtr data, TxMode txMode, int max); // Lennard: Deaktiviert + virtual int getRecData(bcPduPtr data, TxMode txMode, int max); virtual int startRec(); // Datenempfang starten virtual int contRec(); // Datenempfang fortsetzen diff --git a/libraries/environment/library.json b/libraries/environment/library.json index 9e3641f..13cd151 100644 --- a/libraries/environment/library.json +++ b/libraries/environment/library.json @@ -1,4 +1,4 @@ { "name": "environment", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/nRF52840Adc/library.json b/libraries/nRF52840Adc/library.json new file mode 100644 index 0000000..34aead1 --- /dev/null +++ b/libraries/nRF52840Adc/library.json @@ -0,0 +1,4 @@ +{ + "name": "nRF52840Adc", + "version": "0.0.1+20221111" + } \ No newline at end of file diff --git a/libraries/nRF52840Adc/nRF52840Adc.cpp b/libraries/nRF52840Adc/nRF52840Adc.cpp new file mode 100644 index 0000000..29ca6a9 --- /dev/null +++ b/libraries/nRF52840Adc/nRF52840Adc.cpp @@ -0,0 +1,265 @@ +//----------------------------------------------------------------------------- +// Thema: Social Manufacturing Network / Development Environment +// Datei: nRF52840Gpio.cpp +// Editor: Robert Patzke +// URI/URL: www.mfp-portal.de +//----------------------------------------------------------------------------- +// Lizenz: CC-BY-SA (wikipedia: Creative Commons) +// Datum: 29. Juni 2021 +// + +#include "nRF52840Adc.h" + +// -------------------------------------------------------------------------- +// Konstruktoren +// -------------------------------------------------------------------------- +// + nRF52840Adc::nRF52840Adc() + { +#ifdef nrfClockTASKS_HFCLKSTART + if((*nrfClock_HFCLKSTAT & nrfClock_HFCLKisRunning) == 0) + *nrfClockTASKS_HFCLKSTART = 1; +#endif + + } + +// -------------------------------------------------------------------------- +// Unterklasse Channels +// -------------------------------------------------------------------------- +// +void nRF52840Adc::Channels::clrLists() +{ + for(int i = 0; i < 8; i++) + { + unsList[i] = 0; + srtList[i] = 0; + nrOfChannels = 0; + } +} + +int nRF52840Adc::Channels::add(int chnNr) +{ + for(int i = 0; i < 8; i++) + { + if(unsList[i] == 0) + { + unsList[i] = chnNr; + nrOfChannels++; + return(i); + } + } + return(-1); +} + +void nRF52840Adc::Channels::sort() +{ + int minPos; + int cnt; + int tmp; + + for(cnt = 0; cnt < 8; cnt++) + { + if(unsList[cnt] == 0) break; + srtList[cnt] = unsList[cnt]; + } + + for(int i = 0; i < cnt; i++) + { + minPos = i; // Position des kleinsten Elementes auf Durchgang + + // Position minPos des kleinsten Elementes bestimmen + for(int j = i+1; j < cnt; j++) + if(srtList[j] < srtList[minPos]) + minPos = j; + // minPos zeigt jetzt auf das kleinste Element im unsortierten Bereich + + if(minPos != i) // Wenn ein späteres Element kleiner ist + { // Vertauschen der Felder von i und minPos + tmp = srtList[i]; + srtList[i] = srtList[minPos]; + srtList[minPos] = tmp; + } + } +} + + + +// -------------------------------------------------------------------------- +// Konfigurationen +// -------------------------------------------------------------------------- +// + +// Einstellen der Kanalparameter (CH[].CONFIG) +// +dword nRF52840Adc::cnfChn(int chnIdx, ChnConf conf, AcqTime acqt, PreGain pg) +{ + dword confVal = 0; + + if(conf.inpResistorP) // Beschaltung am Pluseingang + { + if(conf.inpPullUpP) + confVal |= ChnConfPullUpInP; + else + confVal |= ChnConfPullDownInP; + } + else if(conf.inpVoltP) + confVal |= ChnConfV1_2InpP; + + if(conf.inpResistorN) // Beschaltung am Minuseingang + { + if(conf.inpPullUpN) + confVal |= ChnConfPullUpInN; + else + confVal |= ChnConfPullDownInN; + } + else if(conf.inpVoltN) + confVal |= ChnConfV1_2InpN; + + // Einstellen des Vorverstärkers + // + if(pg == pg1_5) + confVal |= ChnConfGain1_5; + else if(pg == pg1_4) + confVal |= ChnConfGain1_4; + else if(pg == pg1_3) + confVal |= ChnConfGain1_3; + else if(pg == pg1_2) + confVal |= ChnConfGain1_2; + else if(pg == pg1) + confVal |= ChnConfGain1; + else if(pg == pg2) + confVal |= ChnConfGain2; + else if(pg == pg4) + confVal |= ChnConfGain4; + + // Auswahl der Referenzspannung + // + if(conf.externRef) + confVal |= ChnConfRefV1_4; + + // Einstellen der Wartezeit vor Wandlung (Ladezeit, Erfassungszeit) + // + if(acqt == acqt5us) + confVal |= ChnConfAcqT5; + else if (acqt == acqt10us) + confVal |= ChnConfAcqT10; + else if (acqt == acqt15us) + confVal |= ChnConfAcqT15; + else if (acqt == acqt20us) + confVal |= ChnConfAcqT20; + else if (acqt == acqt40us) + confVal |= ChnConfAcqT40; + + // Differenzmessung einstellen + // + if(conf.diffMode) + confVal |= ChnConfDiffMode; + + // Burst (Oversampling) aktivieren + // + if(conf.burst) + confVal |= ChnConfBurst; + + return(confVal); +} + +// Zuordnen der Eingänge +// +dword nRF52840Adc::cnfPin(PinNr pinNr) +{ + if(pinNr < aInpSp1) + return((dword) pinNr); + if(pinNr == aInpSp1) + return(9); + if(pinNr == aInpSp2) + return(0x0D); + return(0); +} + + +void nRF52840Adc::config(PinNr pinNrP, PinNr pinNrN, ChnNr chnNr, + ChnConf conf, AcqTime acqt, PreGain pg) +{ + int chnIdx; + volatile ChnConfigs *chnCfgPtr; + + if(chnNr < dc1) // Single-Ended Kanäle + { + // Zeiger auf die Konfigurationsregister festlegen + chnIdx = chnNr; + chnCfgPtr = &(NrfAdcPtr->CH[chnIdx]); + + // Konfigurationsdaten (vom Anwender) eintragen + conf.diffMode = false; // Mögliche Fehler vermeiden + chnCfgPtr->CONFIG = cnfChn(chnIdx,conf,acqt,pg); + + // Eingänge zuordnen + chnCfgPtr->PSELP = cnfPin(pinNrP); + chnCfgPtr->PSELN = 0; // Negativeingang nicht benutzt + + // Vorerst Einzelabtastungen über Task-Anweisung + NrfAdcPtr->RESULT_MAXCNT = 1; + NrfAdcPtr->SAMPLERATE = 0; + + // Speicher zuweisen + NrfAdcPtr->RESULT_PTR = (dword) &channels.seResult; + + // Kanalliste aufbauen + channels.add(chnIdx+1); + } + +} + +// ---------------------------------------------------------------------------- +// Anwendungsfunktionen +// ---------------------------------------------------------------------------- +// +void nRF52840Adc::begin() +{ + // Auflösung vorerst fest eingestellt + NrfAdcPtr->RESOLUTION = 2; // 12 Bit + + // Einschalten des ADC + NrfAdcPtr->ENABLE = 1; + + // Temperatur-Kalibrierung wird später gemacht + // + + // Kanäle sortieren in der Liste + // + channels.sort(); + + // Interrupt-Handling + // ---------------------------------------------------------------------- + // + NrfAdcPtr->INTENCLR = 0xFFFFFFFF; // Vorsichtshalber keine Interrupts + + instPtr0 = this; // Statischen Zeiger auf diese Instanz setzen + + // Interruptvektor setzen + // + __NVIC_SetVector((IRQn_Type) 7, (dword) nRF52840Adc::irqHandler0); + __NVIC_SetPriority((IRQn_Type) 7, 1); + __NVIC_EnableIRQ((IRQn_Type) 7); + +} + + + // ---------------------------------------------------------------------------- + // Ereignisbearbeitung und Interrupts + // ---------------------------------------------------------------------------- + // + +nRF52840Adc *nRF52840Adc::instPtr0 = NULL; + +void nRF52840Adc::irqHandler0() +{ + if(instPtr0 == NULL) return; + instPtr0->irqHandler(); +} + +void nRF52840Adc::irqHandler() +{ + statistic.interrupts++; + +} diff --git a/libraries/nRF52840Adc/nRF52840Adc.h b/libraries/nRF52840Adc/nRF52840Adc.h new file mode 100644 index 0000000..24bb1bf --- /dev/null +++ b/libraries/nRF52840Adc/nRF52840Adc.h @@ -0,0 +1,235 @@ +//----------------------------------------------------------------------------- +// Thema: Social Manufacturing Network / Development Environment +// Datei: nRF52840Adc.h +// Editor: Robert Patzke +// URI/URL: www.mfp-portal.de +//----------------------------------------------------------------------------- +// Lizenz: CC-BY-SA (wikipedia: Creative Commons) +// Datum: 03. Oktober 2022 +// + +#ifndef NRF52840ADC_H +#define NRF52840ADC_H + +#include <stdio.h> +#include "arduinoDefs.h" +#include "IntrfAdc.h" +#include "nrf52840.h" + +#ifndef nrfAdcDef +// ---------------------------------------------------------------------------- +typedef struct _ChnLimits +{ + dword Low; + dword High; +} ChnLimits; + +typedef struct _ChnConfigs +{ + dword PSELP; + dword PSELN; + dword CONFIG; + dword LIMIT; +} ChnConfigs; + +#define ChnConfPullDownInP 0x00000001 +#define ChnConfPullUpInP 0x00000002 +#define ChnConfV1_2InpP 0x00000003 +#define ChnConfPullDownInN 0x00000010 +#define ChnConfPullUpInN 0x00000020 +#define ChnConfV1_2InpN 0x00000030 +#define ChnConfGain1_6 0x00000000 +#define ChnConfGain1_5 0x00000100 +#define ChnConfGain1_4 0x00000200 +#define ChnConfGain1_3 0x00000300 +#define ChnConfGain1_2 0x00000400 +#define ChnConfGain1 0x00000500 +#define ChnConfGain2 0x00000600 +#define ChnConfGain4 0x00000700 +#define ChnConfRefV1_4 0x00001000 +#define ChnConfAcqT3 0x00000000 +#define ChnConfAcqT5 0x00010000 +#define ChnConfAcqT10 0x00020000 +#define ChnConfAcqT15 0x00030000 +#define ChnConfAcqT20 0x00040000 +#define ChnConfAcqT40 0x00050000 +#define ChnConfDiffMode 0x00100000 +#define ChnConfBurst 0x01000000 + + +typedef struct _nrfAdc +{ + volatile dword TASKS_START; // 000 + volatile dword TASKS_SAMPLE; // 004 + volatile dword TASKS_STOP; // 008 + volatile dword TASKS_CALIBRATEOFFSET; // 00C + volatile dword Reserve01[60]; // 010 + volatile dword EVENTS_STARTED; // 100 + volatile dword EVENTS_END; // 104 + volatile dword EVENTS_DONE; // 108 + volatile dword EVENTS_RESULTDONE; // 10C + volatile dword EVENTS_CALIBRATEDONE; // 110 + volatile dword EVENTS_STOPPED; // 114 + volatile ChnLimits EVENTS_CHNLIMIT[8]; // 118 + volatile dword Reserve02[106]; // 158 + volatile dword INTEN; // 300 + volatile dword INTENSET; // 304 + volatile dword INTENCLR; // 308 + volatile dword Reserve03[61]; // 30C + volatile dword STATUS; // 400 + volatile dword Reserve04[63]; // 404 + volatile dword ENABLE; // 500 + volatile dword Reserve05[03]; // 504 + volatile ChnConfigs CH[8]; // 510 + volatile dword Reserve06[24]; // 590 + volatile dword RESOLUTION; // 5F0 + volatile dword OVERSAMPLE; // 5F4 + volatile dword SAMPLERATE; // 5F8 + volatile dword Reserve07[12]; // 5FC + volatile dword RESULT_PTR; // 62C + volatile dword RESULT_MAXCNT; // 630 + volatile dword RESULT_AMOUNT; // 634 +} nrfAdc, *nrfAdcPtr; + +#define NrfAdcBase 0x40007000 +#define NrfAdcPtr ((nrfAdcPtr) NrfAdcBase) + +// Falls noch kein Zugriff auf die Taktfestlegung erfolgte +// +#ifndef NrfClockBase +#define NrfClockBase 0x40000000 +#endif + +#ifndef nrfClockTASKS_HFCLKSTART +#define nrfClockTASKS_HFCLKSTART ((dword *) 0x40000000) +#endif + +#ifndef nrfClock_HFCLKSTAT +#define nrfClock_HFCLKSTAT ((dword *) 0x4000040C) +#endif + +#ifndef nrfClock_HFCLKisRunning +#define nrfClock_HFCLKisRunning 0x00010000 +#endif + +#define nrfAdcDef +// ---------------------------------------------------------------------------- +#endif + +#define P0(x) (x) +#define P1(x) (32+x) + +#ifdef smnNANOBLE33 +// ---------------------------------------------------------------------------- +#define ArdA0Bit 4 +#define ArdA1Bit 5 +#define ArdA2Bit 30 +#define ArdA3Bit 29 +#define ArdA4Bit 31 +#define ArdA5Bit 2 +#define ArdA6Bit 28 +#define ArdA7Bit 3 + +#define ArdA0 P0(4) +#define ArdA1 P0(5) +#define ArdA2 P0(30) +#define ArdA3 P0(29) +#define ArdA4 P0(31) +#define ArdA5 P0(2) +#define ArdA6 P0(28) +#define ArdA7 P0(3) + +#define ArdA0Mask (1 << 4) +#define ArdA1Mask (1 << 5) +#define ArdA2Mask (1 << 30) +#define ArdA3Mask (1 << 29) +#define ArdA4Mask (1 << 31) +#define ArdA5Mask (1 << 2) +#define ArdA6Mask (1 << 28) +#define ArdA7Mask (1 << 3) + +enum AdcChnPin +{ + seC1P = 4, + seC2P = 5, + seC3P = 30, + seC4P = 29, + seC5P = 31, + seC6P = 2, + seC7P = 28, + seC8P = 3 +}; + +// ---------------------------------------------------------------------------- +#endif + +class nRF52840Adc : IntrfAdc +{ + // -------------------------------------------------------------------------- + // Spezifische Datentypen + // -------------------------------------------------------------------------- + // + class Channels + { + public: + int unsList[8]; + int srtList[8]; + int nrOfChannels; + short seResult[8]; + short diResult[4]; + + void clrLists(); + int add(int chnNr); + void sort(); + }; + +private: + // -------------------------------------------------------------------------- + // lokale Variablen + // -------------------------------------------------------------------------- + // + Channels channels; + Statistic statistic; + + // -------------------------------------------------------------------------- + // lokale Funktionen + // -------------------------------------------------------------------------- + // + dword cnfChn(int chnIdx, ChnConf conf, AcqTime acqt, PreGain pg); + dword cnfPin(PinNr pinNr); + +public: + // -------------------------------------------------------------------------- + // Konstruktoren + // -------------------------------------------------------------------------- + // + nRF52840Adc(); + + // -------------------------------------------------------------------------- + // Konfigurationen + // -------------------------------------------------------------------------- + // + void config(PinNr pinNrP, PinNr pinNrN, ChnNr chnNr, ChnConf conf, AcqTime acqt, PreGain pg); + void begin(); + + // -------------------------------------------------------------------------- + // Anwendungsfunktionen + // -------------------------------------------------------------------------- + // + + // ---------------------------------------------------------------------------- + // Ereignisbearbeitung und Interrupts + // ---------------------------------------------------------------------------- + // + static nRF52840Adc *instPtr0; + static void irqHandler0(); + void irqHandler(); + + // -------------------------------------------------------------------------- + // Debugging und globale Variablen + // -------------------------------------------------------------------------- + // + +}; + +#endif //NRF52840ADC_H diff --git a/libraries/nRF52840Gpio/library.json b/libraries/nRF52840Gpio/library.json index a099c0c..1a10197 100644 --- a/libraries/nRF52840Gpio/library.json +++ b/libraries/nRF52840Gpio/library.json @@ -1,4 +1,4 @@ { "name": "nRF52840Gpio", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/nRF52840Gpio/nRF52840Gpio.cpp b/libraries/nRF52840Gpio/nRF52840Gpio.cpp index 47a25dd..57f3a89 100644 --- a/libraries/nRF52840Gpio/nRF52840Gpio.cpp +++ b/libraries/nRF52840Gpio/nRF52840Gpio.cpp @@ -85,7 +85,7 @@ GpioError nRF52840Gpio::config(int nrFrom, int nrTo, unsigned int cnfBits, GpioE tmpMask = IfDrvPullDown | IfDrvPullUp; if((cnfBits & tmpMask) == tmpMask) return (GEcdictPar); - cnfValue = getCnfValue(cnfBits); + cnfValue = getCnfValue(cnfBits); // spezifische Bits setzen tmpMask = 0; // Bedienen des angegebenen Bereiches @@ -93,9 +93,9 @@ GpioError nRF52840Gpio::config(int nrFrom, int nrTo, unsigned int cnfBits, GpioE for(int i = nrFrom; i <= nrTo; i++) { portNum = (i & 0x0E0) >> 5; - pinNum = i & 0x01F; + pinNum = i & 0x01F; // 0 ... 31 - tmpMask |= (1 << i); + tmpMask |= (1 << pinNum); if(portNum == 0) gpioPtr = NrfGpioPtr0; @@ -116,7 +116,7 @@ GpioError nRF52840Gpio::config(int nr, unsigned int cnfBits, GpioExtRefPtr refPt return(config(nr,nr,cnfBits, refPtr)); } -GpioError nRF52840Gpio::config(GpioExtMask mask, unsigned int cnfBits, GpioExtRefPtr refPtr) +GpioError nRF52840Gpio::config(GpioExtMask *maskPtr, unsigned int cnfBits, GpioExtRefPtr refPtr) { GpioError retv = GEnoError; dword cnfVal; @@ -135,12 +135,12 @@ GpioError nRF52840Gpio::config(GpioExtMask mask, unsigned int cnfBits, GpioExtRe for(int i = 0; i < 32; i++) { - if(mask.port == 0) + if(maskPtr->port == 0) gpioPtr = NrfGpioPtr0; else gpioPtr = NrfGpioPtr1; - if(mask.pins & chkMask) + if(maskPtr->pins & chkMask) gpioPtr->PIN_CNF[i] = cnfVal; chkMask <<= 1; @@ -149,7 +149,7 @@ GpioError nRF52840Gpio::config(GpioExtMask mask, unsigned int cnfBits, GpioExtRe if(refPtr != NULL) { refPtr->ioPtr = (dword *) gpioPtr; - refPtr->pins = mask.pins; + refPtr->pins = maskPtr->pins; } return(retv); @@ -183,7 +183,7 @@ GpioError nRF52840Gpio::configArd(ArdMask ardMask, unsigned int cnfBits) break; } - return config(ioMask, cnfBits, NULL); + return config(&ioMask, cnfBits, NULL); } @@ -192,6 +192,25 @@ GpioError nRF52840Gpio::configArd(ArdMask ardMask, unsigned int cnfBits) // Anwendungsfunktionen // -------------------------------------------------------------------------- // +bool nRF52840Gpio::isSet(GpioExtRefPtr ioRefPtr) +{ + gpioPtr = (nrfGpioPtr) ioRefPtr->ioPtr; + return(gpioPtr->IN & ioRefPtr->pins); +} + +bool nRF52840Gpio::anySet(GpioExtRefPtr ioRefPtr) +{ + gpioPtr = (nrfGpioPtr) ioRefPtr->ioPtr; + return(gpioPtr->IN & ioRefPtr->pins); +} + +bool nRF52840Gpio::allSet(GpioExtRefPtr ioRefPtr) +{ + gpioPtr = (nrfGpioPtr) ioRefPtr->ioPtr; + return((gpioPtr->IN & ioRefPtr->pins) == ioRefPtr->pins); +} + + void nRF52840Gpio::read(GpioExtRefPtr ioRefPtr, GpioExtValPtr valPtr) { gpioPtr = (nrfGpioPtr) ioRefPtr->ioPtr; diff --git a/libraries/nRF52840Gpio/nRF52840Gpio.h b/libraries/nRF52840Gpio/nRF52840Gpio.h index addf5ad..0bf899d 100644 --- a/libraries/nRF52840Gpio/nRF52840Gpio.h +++ b/libraries/nRF52840Gpio/nRF52840Gpio.h @@ -110,6 +110,7 @@ typedef struct _nrfGpio #define ArdD11 P1(1) #define ArdD12 P1(8) #define ArdD13 P0(13) +#define ArdLedGn P1(9) #define ArdD2Mask (1 << 11) #define ArdD3Mask (1 << 12) @@ -150,7 +151,7 @@ public: dword getCnfValue(unsigned int cnfBits); GpioError config(int nr, unsigned int cnfBits, GpioExtRefPtr refPtr); GpioError config(int nrFrom, int nrTo, unsigned int cnfBits, GpioExtRefPtr refPtr); - GpioError config(GpioExtMask mask, unsigned int cnfBits, GpioExtRefPtr refPtr); + GpioError config(GpioExtMaskPtr maskPtr, unsigned int cnfBits, GpioExtRefPtr refPtr); GpioError configArd(ArdMask ardMask, unsigned int cnfBits); @@ -158,6 +159,9 @@ public: // Anwendungsfunktionen // -------------------------------------------------------------------------- // + bool isSet(GpioExtRefPtr ioRef); + bool allSet(GpioExtRefPtr ioRef); + bool anySet(GpioExtRefPtr ioRef); void read(GpioExtRefPtr ioRef, GpioExtValPtr valPtr); dword readArd(ArdMask ardMask); diff --git a/libraries/nRF52840Radio/library.json b/libraries/nRF52840Radio/library.json index a18f8f0..8568e9f 100644 --- a/libraries/nRF52840Radio/library.json +++ b/libraries/nRF52840Radio/library.json @@ -1,4 +1,4 @@ { "name": "nRF52840Radio", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/nRF52840Radio/nRF52840Radio.cpp b/libraries/nRF52840Radio/nRF52840Radio.cpp index 5639480..27c14c9 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 0e61246..a463c96 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/libraries/nRF52840Ser/library.json b/libraries/nRF52840Ser/library.json index fa5d175..bbed5cb 100644 --- a/libraries/nRF52840Ser/library.json +++ b/libraries/nRF52840Ser/library.json @@ -1,4 +1,4 @@ { "name": "nRF52840Ser", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/libraries/nRF52840Twi/library.json b/libraries/nRF52840Twi/library.json index 16ae392..80e483a 100644 --- a/libraries/nRF52840Twi/library.json +++ b/libraries/nRF52840Twi/library.json @@ -1,4 +1,4 @@ { "name": "nRF52840Twi", - "version": "0.0.0+20220823165932" + "version": "0.0.1+20221111" } \ No newline at end of file diff --git a/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.h b/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.h index 29a71a4..9bb0445 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 1aaf110..b2577ce 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 0000000..fc5dd65 --- /dev/null +++ b/sketches/SoaapBleSlave/SoaapBleSlave.h @@ -0,0 +1,71 @@ +/* + * 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 "GpioCtrl.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 smTestIO(); +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 0000000..70acbc9 --- /dev/null +++ b/sketches/SoaapBleSlave/SoaapBleSlave.ino @@ -0,0 +1,1250 @@ +// ---------------------------------------------------------------------------- +// 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 20221107-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 Testen von Peripheriezugriffen\r\n" + "c5 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 + +GpioExtRef LedRot; +// Handle für den Zugriff auf eine rote LED an Pin D11 +GpioExtRef LedGreen; +// Handle für die grüne LED auf dem Nano Board + +nRF52840Gpio gpio; +// Zugriff auf die digitalen Anschlüsse des Board + +#define GpioCycleTime 500 +// Zykluszeit (in Mikrosekunden) bei der Ansteuerung digitaler I/Os + +GpioCtrl ioCtrl((IntrfGpio *) &gpio, GpioCycleTime); +// Instanz zur Ansteuerung der Peripherie (Blinken, etc.) + +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; +// Anwendung des A/D-Wandlers + +void setup() +{ + TwiParams twiPar; // Parameter für den I2C-Bus + + // Einschalten der roten LED (am Pin D11 des Arduino-Board) + // bei der SOAAP-Anwendung + // + gpio.config(ArdD11, IfDrvOutput | IfDrvOpenDrain | IfDrvStrongLow, &LedRot); + //ioCtrl.blink(&LedRot, 0, 2, 998, true); + ioCtrl.blink(&LedRot, 0, 2, 200, 398, 2, true); + + // Ausschalten der grünen LED (auf dem Arduino-Board) + // + gpio.config(ArdLedGn, IfDrvInput, &LedGreen); + +#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(); + + // Alle 500 Mikrosekunden erfolgt der Aufruf der Peripheriesteuerung + // + if(lc.timerMicro(lcTimer3, GpioCycleTime, 0)) + ioCtrl.run(); + +#ifdef DebugTerminal + // Alle 5 Millisekunden wird die Zustandsmaschine für + // betriebliche Abläufe aufgerufen + // + if(lc.timerMilli(lcTimer4, smCycleTime, 0)) + { + sm.run(); + } + + // Jede halbe Sekunde erfolgt die Ausgabe der Version + // + if(lc.timerMilli(lcTimer5, 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(smTestIO); + else if(mon.cFlag[5] && !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) Testen von Peripheriezugriffen +// ---------------------------------------------------------------------------- +// + +void smTestIO() +{ + if(sm.firstEnter()) + { + mon.print((char *) "Testen der Peripheriezugriffe "); + 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 == 's' || mon.lastKeyIn == 'S') + { + mon.print("ConfStru = "); + mon.print((byte *) &LedRot.ioPtr,4,' '); + mon.print(" / "); + mon.println((byte *) &LedRot.pins,4,' '); + } + sm.resetEnter(); +} + + +// ---------------------------------------------------------------------------- +// (5) 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[5] = 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 0000000..80c8b92 --- /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 0000000..fb14e55 --- /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 0000000..0e4279e --- /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 -- GitLab