diff --git a/libraries/BlePoll/BlePoll.cpp b/libraries/BlePoll/BlePoll.cpp index 09c8e64ff9cbe18e405e047be8663a4e2e041b22..878c420cc61a195ee1a37fd8f130a84a298c79bb 100644 --- a/libraries/BlePoll/BlePoll.cpp +++ b/libraries/BlePoll/BlePoll.cpp @@ -64,6 +64,8 @@ void BlePoll::init(IntrfRadio *refRadio, dword inCycleMics, MicsecFuPtr inMicroF cntAllTo = 0; pollStopped = false; pollStop = false; + recStopped = false; + recStop = false; runCounter = 0; newValue = false; cbData = NULL; @@ -73,11 +75,15 @@ void BlePoll::init(IntrfRadio *refRadio, dword inCycleMics, MicsecFuPtr inMicroF slaveList[i].cntNakEP = 0; slaveList[i].cntTo = 0; slaveList[i].pIdx = 0; - slaveList[i].delayCnt = 10; + slaveList[i].delayCnt = 5; + slaveList[i].newPdu = false; + slaveList[i].newMeas = false; pollList[i].prioCnt = 0; pollList[i].slIdx = 0; pollList[i].status = 0; } + + DataExchange = false; } // ---------------------------------------------------------------------------- @@ -123,7 +129,7 @@ void BlePoll::begin(ComType typeIn, int adrIn, AppType appType, dword watchDog) next(smInit); } - if(appType == atSOAAP || appType == atTestSend) + if(appType == atSOAAP || appType == atTestSend || appType == atDevSOAAP) { pduOut.adr5 = 0x53; pduOut.adr4 = 0x4F; @@ -150,17 +156,35 @@ void BlePoll::begin(ComType typeIn, int adrIn, AppType appType, dword watchDog) { if(master) { - valuePdu.appId = plptMeas6; + valuePdu.appId = plptMeas9Ctrl4; + ctrlPdu.appId = plptCtrlX; + plMode = plmSoaapM; + fullCycle = true; + } + else + { + valuePdu.appId = plptMeas9Ctrl4; + ctrlPdu.appId = plptCtrlX; + plMode = plmSoaapS; + } + } + else if (appType == atDevSOAAP) + { + if(master) + { + valuePdu.appId = plptMeas13; + ctrlPdu.appId = plptCtrl2; plMode = plmSoaapM; fullCycle = true; } else { - valuePdu.appId = plptMeas6; + valuePdu.appId = plptMeas13; + ctrlPdu.appId = plptCtrl2; plMode = plmSoaapS; - //plMode = plmSoaapM; } } + valuePdu.measCnt = 0; valuePdu.counter = 0; valuePdu.type = appType; @@ -216,8 +240,15 @@ void BlePoll::setCbDataPtr(cbDataPtr cbPtr) cbData = cbPtr; } +void BlePoll::setCbCtrlPtr(cbCtrlPtr cbPtr) +{ + cbCtrl = cbPtr; +} +dword smStartComESCnt; +bcPdu recBeacon; +int lenBeacon = 0; // -------------------------------------------------------------------------- // Hilfsfunktionen @@ -257,16 +288,25 @@ bool BlePoll::timeOut() } } -bool BlePoll::getValues(bcPduPtr pduPtr) +bool BlePoll::getValues(bcPduPtr pduPtr, PlpType appId) { - bool retv = false; + bool retv = false; - pduPtr->len = 28; + switch (appId) + { + case plptMeas6: + pduPtr->len = sizeof(PlpMeas6) + 6; + break; + + case plptMeas9Ctrl4: + pduPtr->len = sizeof(PlpM9C4) + 6; + break; + } pduPtr->data[0]++; // Pdu-Counter pduPtr->data[1] = valuePdu.type; - pduPtr->data[2] = valuePdu.appId; + pduPtr->data[2] = appId; - newValue = cbData(plptMeas6, &pduPtr->data[4]); + newValue = cbData(appId, &pduPtr->data[4]); if(newValue) { @@ -277,6 +317,21 @@ bool BlePoll::getValues(bcPduPtr pduPtr) } +bool BlePoll::getCtrls(bcPduPtr pduPtr, PlpType appId) +{ + int ctrlLen; + + if(recBeacon.len > 6) + ctrlLen = recBeacon.len - 6; + else + ctrlLen = 4; + + newCtrl = cbCtrl((PlpType) appId, &pduPtr->data[22], &recBeacon.data[0], ctrlLen); + + return(newCtrl); +} + + // -------------------------------------------------------------------------- // Steuerung des Polling // -------------------------------------------------------------------------- @@ -313,6 +368,28 @@ bool BlePoll::stoppedEP() return(pollStopped); } +// Anhalten des Empfangs beim Slave +// +void BlePoll::stopSR() +{ + recStop = true; +} + +// Weiterlaufen des Empfangs beim Slave +// +void BlePoll::resumeSR() +{ + recStop = false; + recStopped = false; +} + +// Abfrage, ob Slaveempfang gestoppt +// +bool BlePoll::stoppedSR() +{ + return(recStopped); +} + // Eintritt in die Zustandsmaschine // @@ -791,58 +868,89 @@ void BlePoll::smEvalPoll() // D a t e n ü b e r t r a g u n g // ---------------------------------------------------------------------------- // + +// Vorbereitung der Datenübertragung +// void BlePoll::smStartCom() { bleState = 2000; - if(pollStop) // Der Start der Datenübertragung kann + if(pollStop || pollStopped) // Der Start der Datenübertragung kann { // verzögert werden pollStopped = true; return; } - pduOut.len = 6; + // -------------------------------------------- + // Auswahl des Funkkanals (Frequenz) + // -------------------------------------------- + // radio->setChannel(chn); + // -------------------------------------------- + // Voreinstellungen für den Master + // -------------------------------------------- + // if(master) { + // Aufbau der Polling-Liste + // for(int i = 1; i <= pollMaxNr; i++) { int slIdx = pollList[i].slIdx; pollList[i].prioCnt = slaveList[slIdx].prioSet; } - nak = false; pollIdx = 1; + + // Vorbereitung der mit dem Polling übermittelten Daten + // + pduOut.len = 13; // Adresse (6) + 7 Byte Steuerung + ctrlPdu.counter = 0; // Zähler im Steuertelegramm + ctrlPdu.appId = plptMeas9Ctrl4; // Info für Slave zur Antwort + next(smReqComS); } + // -------------------------------------------- + // Voreinstellungen für den Slave + // -------------------------------------------- + // else { nak = true; next(smWaitEadr); } + + DataExchange = true; } // ---------------------------------------------------------------------------- // Datenübertragung Master S l a v e - > M a s t e r // ---------------------------------------------------------------------------- // + +// M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M +// Polling : Anfordern von Daten beim Slave +// ---------------------------------------------------------------------------- +// void BlePoll::smReqComS() { bleState = 2100; - if(pollStop) // Das Polling kann + if(pollStop || pollStopped) // Das Polling kann { // angehalten werden pollStopped = true; return; } + // Es ist von einem vorherigen Funkempfang auszugehen + // Die Hardware muss erst ausgeschaltet werden + // if(!radio->disabled(txmPoll)) { radio->disable(txmPoll); return; } - // Der aufzufordernde Teilnehmer wird der Poll-Liste entnommen // curPoll = &pollList[pollIdx]; @@ -867,13 +975,14 @@ void BlePoll::smReqComS() // Slave-spezifische Parameter setzen // - eadr = false; - nak = false; + eadr = false; // Ist true, wenn Daten nur zum Slave übertragen werden + nak = false; // Ist true, wenn keine Daten übertragen werden (empty poll) adr = curSlave->adr; area = curSlave->area; setPduAddress(); setTimeOut(curSlave->timeOut); + // Statistic-Daten einholen für evt. Auswertung // radio->getStatistics(&statistic); @@ -886,13 +995,18 @@ void BlePoll::smReqComS() next(smWaitAckComS); } -int tmpInt1, tmpInt2, tmpInt3; - +// M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M M +// Warten auf die Antwort vom Slave +// ---------------------------------------------------------------------------- +// void BlePoll::smWaitAckComS() { byte tmpByte; short tmpShort; + // Zeiger zur spezifischen Betrachtung von Empfangsdaten + PlPduMeasPtr resPtr; + bleState = 2110; if(timeOut()) @@ -974,32 +1088,64 @@ void BlePoll::smWaitAckComS() // Die Daten werden in der Slave-Struktur abgelegt // - curSlave->result.counter = pduIn.data[0]; - curSlave->result.type = pduIn.data[1]; - curSlave->result.appId = pduIn.data[2]; - curSlave->result.measCnt = pduIn.data[3]; - curSlave->result.meas[0] = *(word *) &pduIn.data[4]; - curSlave->result.meas[1] = *(word *) &pduIn.data[6]; - curSlave->result.meas[2] = *(word *) &pduIn.data[8]; - curSlave->result.meas[3] = *(word *) &pduIn.data[10]; - curSlave->result.meas[4] = *(word *) &pduIn.data[12]; - curSlave->result.meas[5] = *(word *) &pduIn.data[14]; + resPtr = (PlPduMeasPtr) &curSlave->result; - if(curSlave->delayCnt == 0) + resPtr->counter = pduIn.data[0]; + resPtr->type = pduIn.data[1]; + resPtr->appId = pduIn.data[2]; + resPtr->measCnt = pduIn.data[3]; + + // Die Inhalte sind abhängig von der <appId> + // + switch(resPtr->appId) { + case plptMeas9Ctrl4: + ((PlpM9C4Ptr) resPtr)->meas[0] = *(word *) &pduIn.data[4]; + ((PlpM9C4Ptr) resPtr)->meas[1] = *(word *) &pduIn.data[6]; + ((PlpM9C4Ptr) resPtr)->meas[2] = *(word *) &pduIn.data[8]; + ((PlpM9C4Ptr) resPtr)->meas[3] = *(word *) &pduIn.data[10]; + ((PlpM9C4Ptr) resPtr)->meas[4] = *(word *) &pduIn.data[12]; + ((PlpM9C4Ptr) resPtr)->meas[5] = *(word *) &pduIn.data[14]; + ((PlpM9C4Ptr) resPtr)->meas[6] = *(word *) &pduIn.data[16]; + ((PlpM9C4Ptr) resPtr)->meas[7] = *(word *) &pduIn.data[18]; + ((PlpM9C4Ptr) resPtr)->meas[8] = *(word *) &pduIn.data[20]; + ((PlpM9C4Ptr) resPtr)->ctrlPath = pduIn.data[22]; + ((PlpM9C4Ptr) resPtr)->procCnt = pduIn.data[23]; + ((PlpM9C4Ptr) resPtr)->ctrl[0] = pduIn.data[24]; + ((PlpM9C4Ptr) resPtr)->ctrl[1] = pduIn.data[25]; + break; + + case plptMeas6: + ((PlpM9C4Ptr) resPtr)->meas[0] = *(word *) &pduIn.data[4]; + ((PlpM9C4Ptr) resPtr)->meas[1] = *(word *) &pduIn.data[6]; + ((PlpM9C4Ptr) resPtr)->meas[2] = *(word *) &pduIn.data[8]; + ((PlpM9C4Ptr) resPtr)->meas[3] = *(word *) &pduIn.data[10]; + ((PlpM9C4Ptr) resPtr)->meas[4] = *(word *) &pduIn.data[12]; + ((PlpM9C4Ptr) resPtr)->meas[5] = *(word *) &pduIn.data[14]; + ((PlpM9C4Ptr) resPtr)->meas[6] = *(word *) &pduIn.data[16]; + break; + } + + // Zählen der verlorenen Telegramme und Messwerte + // beginnt um <delayCnt> Pollzyklen verzögert + // + if(curSlave->delayCnt == 0) + { tmpByte = curSlave->result.counter - curSlave->oldPduCount; if(tmpByte > 1) curSlave->cntLostPdu += tmpByte - 1; - tmpByte = curSlave->result.measCnt - curSlave->oldMeasCount; + tmpByte = resPtr->measCnt - curSlave->oldMeasCount; + if(tmpByte != 0) + curSlave->newMeas = true; if(tmpByte > 1) curSlave->cntLostMeas += tmpByte - 1; } else curSlave->delayCnt--; curSlave->oldPduCount = curSlave->result.counter; - curSlave->oldMeasCount = curSlave->result.measCnt; + curSlave->oldMeasCount = resPtr->measCnt; curSlave->newPdu = true; curSlave->cntAckDP++; @@ -1121,26 +1267,43 @@ void BlePoll::smEndComE() } +// S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S // ---------------------------------------------------------------------------- // Datenübertragung Slave M a s t e r < - > S l a v e // ---------------------------------------------------------------------------- // -dword smStartComESCnt; +// S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S +// Vorbereitungen für den Empfang (Polling durch Master) +// ---------------------------------------------------------------------------- +// void BlePoll::smStartComES() { bool newValues; + bool newCtrl; byte lenValues; + byte appId; bleState = 1310; smStartComESCnt++; + if(recStop || recStopped) + { + recStopped = true; + return; + } + + // Wenn keine Daten von der Anwendung zur Verfügung gestellt werden, + // dann macht der Betrieb hier keinen Sinn und der Slave geht in IDLE + // if(cbData == NULL) { next(smIdle); return; } + // Falls der Sender noch nicht ausgeschaltet ist, muss gewartet werden + // if(!radio->disabled(txmResp)) { radio->disable(txmResp); @@ -1148,17 +1311,31 @@ void BlePoll::smStartComES() return; } + // Vorbereiten des erwarteten Inhalts beim Polling durch den Master + // nak = true; eadr = true; setPduAddress(&pduIn); pduIn.len = 6; + // Vorbereiten des zu sendenden Inhalts als Antwort auf das Polling + // nak = false; eadr = false; setPduAddress(&pduOut); - newValues = getValues(&pduOut); + // Eintragen der Messwerte in das Sendetelegramm + // + if(lenBeacon == 0) // Wenn noch kein Empfangszyklus vorliegt + appId = valuePdu.appId; // dann wird der voreingestellte Satz gewählt + else + appId = recBeacon.data[2]; // ansonsten der speziell angeforderte + + newValues = getValues(&pduOut, (PlpType) appId); + + if((appId == plptMeas9Ctrl4) && (cbCtrl != NULL)) + getCtrls(&pduOut, (PlpType) appId); radio->setChannel(chn); radio->send(&pduIn, &pduOut, txmResp, newValues); @@ -1167,6 +1344,7 @@ void BlePoll::smStartComES() next(smWaitComES); } +// S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S void BlePoll::smWaitComES() { bleState = 1320; @@ -1177,10 +1355,153 @@ void BlePoll::smWaitComES() next(smStartComES); return; } + if(!radio->fin(txmResp, &crcError)) return; + // + // Übertragung beendet, Daten empfangen (polling) und versendet (response) + // + //lenBeacon = radio->getRecData(&recBeacon, txmResp, sizeof(recBeacon)); next(smStartComES); } +// -------------------------------------------------------------------------- +// Anwenderfunktionen +// -------------------------------------------------------------------------- +// + +// neue Steuerungsdaten für einen Slave +// +void BlePoll::updControl(int adr, byte *ctrlList, int nr) +{ + if(adr <= 0) return; + if(adr >= MAXSLAVE) return; + if(nr <= 1) return; + if(nr > 27) return; + + SlavePtr slavePtr = &slaveList[adr]; + PlpCtrl27Ptr ctrlPtr = (PlpCtrl27Ptr) &slavePtr->control; + for(int i = 0; i < nr; i++) + ctrlPtr->ctrl[i] = ctrlList[i]; + ctrlPtr->ctrlCnt++; + slavePtr->rspOk = false; +} + +// Feststellenn, ob Übertragung der Steuerungsdaten erfolgt ist +// +bool BlePoll::ackTrans(int adr) +{ + if(adr <= 0) return(false); + if(adr >= MAXSLAVE) return(false); + + SlavePtr slavePtr = &slaveList[adr]; + return(slavePtr->rspOk); +} + +// Feststellen, ob Steuerungsdaten beim Slave verarbeitet sind +// +bool BlePoll::ackControl(int adr) +{ + if(adr <= 0) return(false); + if(adr >= MAXSLAVE) return(false); + + SlavePtr slavePtr = &slaveList[adr]; + PlpCtrl27Ptr ctrlPtr = (PlpCtrl27Ptr) &slavePtr->control; + if(ctrlPtr->ctrlCnt == slavePtr->rspCtrlCount) + return(true); + else + return(false); +} + +// ---------------------------------------------------------------------------- +// Zugriff auf Slavedaten über die Adresse +// ---------------------------------------------------------------------------- +// + +// Feststellen, ob ein Slave neue Messwerte hat +// +bool BlePoll::measAvail(int slAdr) +{ + if(slAdr < 1) return(false); + if(slAdr >= MAXSLAVE) return(false); + + SlavePtr slavePtr = &slaveList[slAdr]; + + if(!slavePtr->newMeas) + return(false); + + slavePtr->newMeas = false; + return(true); +} + +// Auslesen der Netzwerk-Area +// +int BlePoll::getArea(int slAdr) +{ + if(slAdr < 1) return(false); + if(slAdr >= MAXSLAVE) return(false); + + SlavePtr slavePtr = &slaveList[slAdr]; + + return(slavePtr->area); +} + +// Auslesen der AppId aus Sicht der Klasse BlePoll +// +PlpType BlePoll::getAppId(int slAdr) +{ + if(slAdr < 1) return(plptError); + if(slAdr >= MAXSLAVE) return(plptError); + + SlavePtr slavePtr = &slaveList[slAdr]; + + return((PlpType) slavePtr->result.plData[0]); +} + +// Auslesen der Messwerte +// +int BlePoll::getMeas(int slAdr, byte *dest) +{ + int anzByte; + PlpType appId; + + if(slAdr < 1) return(false); + if(slAdr >= MAXSLAVE) return(false); + + SlavePtr slavePtr = &slaveList[slAdr]; + + appId = (PlpType) slavePtr->result.plData[0]; + + switch(appId) + { + case plptMeas6: + anzByte = 12; + break; + + case plptMeas9: + anzByte = 18; + break; + + case plptMeas9Ctrl4: + anzByte = 22; + break; + + case plptMeas13: + anzByte = 26; + break; + + default: + anzByte = 18; + break; + } + + for (int i = 0; i < anzByte; i++) + { + dest[i] = slavePtr->result.plData[i+2]; + } + + return(anzByte); +} + // -------------------------------------------------------------------------- // Debugging diff --git a/libraries/BlePoll/BlePoll.h b/libraries/BlePoll/BlePoll.h index 4bd05ce26aa48617e37fe2e52028da4fa19d7131..0a5cd9c66417896d310e87852550579e08511b3e 100644 --- a/libraries/BlePoll/BlePoll.h +++ b/libraries/BlePoll/BlePoll.h @@ -38,48 +38,71 @@ typedef enum _PlMode plmXchg // Daten übertragen (Slave, beide Richtungen) } PlMode; -// Grundsätzliche Datenstruktur für die Nutzdaten +// Grundsätzliche Datenstruktur für die Nutzdaten (ohne 6 Bytes Adresse) // -typedef struct _PlPduBase +typedef struct _PlPduBase // maximale Länge Beacon = 31 Bytes { byte counter; // zyklischer Telegrammmzähler byte type; // Kennzeichnung der Datenstruktur (AppType) byte plData[29]; // weitere spezifische Nutzdaten } PlPduBase, *PlPduBasePtr; -// Erweiterte Datenstruktur für die Nutzdaten +// Grundsätzliche Datenstruktur für Messwerte (ohne 6 Bytes Adresse) // -typedef struct _PlPduExtd +typedef struct _PlPduMeas // maximale Länge Beacon = 31 Bytes +{ + byte counter; // zyklischer Telegrammmzähler + byte type; // Kennzeichnung der Datenstruktur (AppType) + byte appId; // Kennzeichnung für Dateninhalte (PlpType) + byte measCnt; // Zähler für Messwertaktualisierung + byte plData[27]; // weitere spezifische Nutzdaten +} PlPduMeas, *PlPduMeasPtr; + +// Erweiterte Datenstruktur für die Nutzdaten (ohne 6 Bytes Adresse) +// zur Zeit noch nicht genutzt +// +typedef struct _PlPduExtd // grundsätzliche maximale Länge = 249 Bytes { byte counter; // zyklischer Telegrammmzähler byte type; // Kennzeichnung der Datenstruktur (AppType) byte plData[247]; // weitere spezifische Nutzdaten } PlPduExtd, *PlPduExtdPtr; -// Datentypen (type in plPduBase) +// Datentypen (appId in plPduBase) // typedef enum _PlpType { + plptError, // Fehler erkannt plptEmpty, // Leeres Telegramm (nur adresse) plptBasic, // Grundlegende Bytestruktur plptFullMeas, // Maximale Belegung mit 16-Bit Messwerten (word) plptMeas3, // 3 Messwerte (1 Raumsensor) plptMeas6, // 6 Messwerte (2 Raumsensoren) - plptMeas9 // 9 Messwerte (3 Raumsensoren) + plptMeas9, // 9 Messwerte (3 Raumsensoren) + plptMeas9Ctrl4, // 9 Messwerte + 4 Byte Steuerung + plptMeas10Ctrl4, // 10 Messwerte + 4 Byte Steuerung + plptMeas12, // 12 Messwerte (9 + 6 Byte Extradaten) + plptMeas13, // 13 Messwerte (9 + 8 Byte Extradaten) + plptMeasX, // Variable Anzahl Messwerte + plptCtrl0, // Keine Steuerung + plptCtrl2, // 2 Byte Steuerung + plptCtrl27, // 27 Byte Steuerung + plptCtrlX, // Variable Anzahl Steuerbytes + plptMsg // (Quittierte) Meldung an Slave } PlpType, *PlpTypePtr; // Spezifische Datenstrukturen // -typedef struct _PlpFullMeas +typedef struct _PlpFullMeas // Ausnahme für vordefinierte Spezialfälle { byte counter; // zyklischer Telegrammmzähler byte type; // Kennzeichnung der Datenstruktur (AppType) - word meas[12]; // Liste von 12 Messwerten + word meas[14]; // Liste von 14 Messwerten byte appId; // Kennzeichnung für Dateninhalte (PlpType) byte align; // Wird nicht gesendet, kennzeichnet Alignement } PlpFullMeas, *PlpFullMeasPtr; -typedef struct _PlpMeas3 +typedef struct _PlpMeas3 // Länge 10 (+ 6 Bytes Adresse) { byte counter; // zyklischer Telegrammmzähler byte type; // Kennzeichnung der Datenstruktur (AppType) @@ -88,7 +111,7 @@ typedef struct _PlpMeas3 word meas[3]; // Liste von 3 Messwerten } PlpMeas3, *PlpMeas3Ptr; -typedef struct _PlpMeas6 +typedef struct _PlpMeas6 // Länge 16 (+ 6 Bytes Adresse) { byte counter; // zyklischer Telegrammmzähler byte type; // Kennzeichnung der Datenstruktur (AppType) @@ -97,7 +120,7 @@ typedef struct _PlpMeas6 word meas[6]; // Liste von 6 Messwerten } PlpMeas6, *PlpMeas6Ptr; -typedef struct _PlpMeas9 +typedef struct _PlpMeas9 // Länge 22 (+ 6 Bytes Adresse) { byte counter; // zyklischer Telegrammmzähler byte type; // Kennzeichnung der Datenstruktur (AppType) @@ -106,6 +129,56 @@ typedef struct _PlpMeas9 word meas[9]; // Liste von 9 Messwerten } PlpMeas9, *PlpMeas9Ptr; +typedef struct _PlpM9C4 // Länge 26 (+ 6 Bytes Adresse) +{ + byte counter; // zyklischer Telegrammmzähler + byte type; // Kennzeichnung der Datenstruktur (AppType) + byte appId; // Kennzeichnung für Dateninhalte (PlpType) + byte measCnt; // Zähler für Messwertaktualisierung + word meas[9]; // Liste von 9 Messwerten + byte ctrlPath; // Steuerungspfad (für Verzweigungen/Funktionen) + byte procCnt; // Prozesszähler + byte ctrl[2]; // Steuerungsdaten +} PlpM9C4, *PlpM9C4Ptr; + +typedef struct _PlpMeas12 // Länge 28 (+ 6 Bytes Adresse) +{ + byte counter; // zyklischer Telegrammmzähler + byte type; // Kennzeichnung der Datenstruktur (AppType) + byte appId; // Kennzeichnung für Dateninhalte (PlpType) + byte measCnt; // Zähler für Messwertaktualisierung + word meas[12]; // Liste von 12 Messwerten +} PlpMeas12, *PlpMeas12Ptr; + +typedef struct _PlpMeas13 // Länge 30 (+ 6 Bytes Adresse) +{ + byte counter; // zyklischer Telegrammmzähler + byte type; // Kennzeichnung der Datenstruktur (AppType) + byte appId; // Kennzeichnung für Dateninhalte (PlpType) + byte measCnt; // Zähler für Messwertaktualisierung + word meas[13]; // Liste von 13 Messwerten +} PlpMeas13, *PlpMeas13Ptr; + +typedef struct _PlpCtrl2 // Länge 7 (+ 6 Bytes Adresse) +{ + byte counter; // zyklischer Telegrammmzähler + byte type; // Kennzeichnung der Datenstruktur (AppType) + byte appId; // Kennzeichnung für Dateninhalte (PlpType) + byte ctrlCnt; // Zähler für Kommandoaktualisierung + byte procCnt; // Zähler für Prozessaktualisierung + byte ctrl[2]; // Liste von 2 Steuerbytes +} PlpCtrl2, *PlpCtrl2Ptr; + +typedef struct _PlpCtrl27 // Länge 31 (+ 6 Bytes Adresse) +{ + byte counter; // zyklischer Telegrammmzähler + byte type; // Kennzeichnung der Datenstruktur (AppType) + byte appId; // Kennzeichnung für Dateninhalte (PlpType) + byte ctrlCnt; // Zähler für Kommandoaktualisierung + byte procCnt; // Zähler für Prozessaktualisierung + byte ctrl[26]; // Liste von bis zu 26 Steuerbytes +} PlpCtrl27, *PlpCtrl27Ptr; + // Identifikator für die Art der Daten // typedef enum _MeasId @@ -115,24 +188,28 @@ typedef enum _MeasId typedef struct _Slave { - dword timeOut; - dword cntTo; - dword cntErrCrc; - dword cntNakEP; - dword cntAckDP; - dword cntLostPdu; - dword cntLostMeas; - dword delayCnt; - byte adr; - byte area; - byte chn; - byte pIdx; - word prioSet; - word minPrio; - PlpMeas6 result; - bool newPdu; - byte oldPduCount; - byte oldMeasCount; + dword timeOut; // Wartezeit beim Polling in Mikrosekunden + dword cntTo; // Zähler für ausbleibende Antworten + dword cntErrCrc; // Zähler für CRC-Fehler bei der Übertragung + dword cntNakEP; // Zähler für NAK-Antworten beim Empty-Polling + dword cntAckDP; // Zähler für ACK-Antworten beim Data-Polling + dword cntLostPdu; // Zähler für verlorene Telegramme + dword cntLostMeas; // Zähler für verlorene Messwerte + dword delayCnt; // Verzögerung (Polldurchläufe) vor Fehlerzählung + byte adr; // Adresse (Nummer) des Slave (1-255) + byte area; // Einsatzgebiet des Slave (Adresserweiterung) + byte chn; // Aktueller Übertragungskanal (0-39) + byte pIdx; // Index in der aktuellen Pollingliste + word prioSet; // Anfangspriorität (rel. Häufigkeit) beim Polling + word minPrio; // Minimale Priorität (maximale Prioritätszahl) + PlPduBase result; // Daten vom Slave + PlPduBase control; // Daten zum Slave + bool newPdu; // Kennzeichnung für neues Telegramm + bool rspOk; // Rücksetz-Kennnzeichnung für neues Telegramm + bool newMeas; // Kennzeichnung für neuen Messwert + byte oldPduCount; // Merker für die Telegrammüberwachung + byte oldMeasCount; // Merker für die Messwertüberwachung + byte rspCtrlCount; // Merker für Steuerungsüberwachung } Slave, *SlavePtr; @@ -150,6 +227,7 @@ typedef struct _PollState } PollState, *PollStatePtr; typedef bool (*cbDataPtr)(PlpType dataType, byte *dest); +typedef bool (*cbCtrlPtr)(PlpType plpType, byte *dest, byte *src, int sSize); #define psSlaveWasPresent 0x01 #define psSlaveIsPresent 0x02 @@ -178,9 +256,16 @@ public: atDefault, // Standard-Default-Anwendung atTestSend, // einfacher Sendetest (Soaap) atSOAAP, // Steuerung optischer und akustischer Ausgaben für Performance-Künstler + atDevSOAAP, // Entwicklerbetrieb für SOAAP atDHA // Dezentrale Hausautomatisierung } AppType; + // -------------------------------------------------------------------------- + // Öffentliche Daten + // -------------------------------------------------------------------------- + // + bool DataExchange; + private: // ------------------------------------------------------------------------- // Private Datentypen @@ -200,6 +285,7 @@ private: cbVector nextState; MicsecFuPtr micSec; cbDataPtr cbData; + cbCtrlPtr cbCtrl; dword toSet; dword toValue; dword cycleMics; @@ -241,10 +327,14 @@ private: dword bleState; dword runCounter; + bool recStop; + bool recStopped; TxStatistics statistic; - PlpMeas6 valuePdu; + PlPduMeas valuePdu; + PlpCtrl27 ctrlPdu; bool newValue; + bool newCtrl; // Einstellungen für den Anwendungsbetrieb // @@ -262,7 +352,8 @@ private: void setPduAddress(bcPduPtr pduPtr); void setTimeOut(dword value); bool timeOut(); - bool getValues(bcPduPtr pduPtr); + bool getValues(bcPduPtr pduPtr, PlpType appId); + bool getCtrls(bcPduPtr pduPtr, PlpType appId); // Zustandsmaschine // ----------------------------- @@ -320,6 +411,7 @@ public: void begin(ComType typeIn, int adrIn, AppType appType, dword watchDog); void setCbDataPtr(cbDataPtr cbPtr); + void setCbCtrlPtr(cbCtrlPtr cbPtr); // -------------------------------------------------------------------------- // Konfiguration @@ -333,8 +425,12 @@ public: // Steuerung des Telegrammaustausches (Polling) // -------------------------------------------------------------------------- // + void run(); // Ablaufsteuerung (CPU-Übergabe) dieses Moduls + + void updControl(int adr, byte *ctrlList, int nr); // neue Steuerungsdaten + bool ackTrans(int adr); // Bestätigung Steuerungsdaten übertragen + bool ackControl(int adr); // Bestätigung Steuerung ausgeführt - void run(); // Test // @@ -345,10 +441,18 @@ public: void resumeEP(); bool stoppedEP(); + // Empfangsbetrieb beim Slave + // + void stopSR(); + void resumeSR(); + bool stoppedSR(); + // Laufender Betrieb // void start(PlMode inPlMode); + + // -------------------------------------------------------------------------- // Zugriff auf Polling-Informationen // -------------------------------------------------------------------------- @@ -356,6 +460,20 @@ public: int getSlaveList(byte *dest, int maxByte); void resetPollCounters(); + // -------------------------------------------------------------------------- + // Zugriff auf Slavedaten + // -------------------------------------------------------------------------- + // Der Index wird von 0 an ausgewertet. Allerdings ist [0] in der Slave-Liste + // auf den Index [1] abzubilden, weil Slave[0] für besondere Aufgaben + // reserviert und für den Anwender nicht zugänglich ist. + // + bool measAvail(int slIdx); // Feststellen, ob neue Messwerte da sind + int getArea(int slIdx); // Wert der Area auslesen + PlpType getAppId(int slIdx); // Wert der AppId (BlePoll) auslesen + int getMeas(int slIdx, byte *dest); // Messwerte übergeben + + + // -------------------------------------------------------------------------- // Debugging // -------------------------------------------------------------------------- diff --git a/libraries/LoopCheck/LoopCheck.cpp b/libraries/LoopCheck/LoopCheck.cpp index bd6ee3c0fef20cb0523c74be9e29d0bafe8a6c23..b01795b4f033ebb0286340840a3b1507c6ef0302 100755 --- a/libraries/LoopCheck/LoopCheck.cpp +++ b/libraries/LoopCheck/LoopCheck.cpp @@ -458,6 +458,16 @@ return(timerMicro(taskIdx,repeatTime * 1000,repetitions,0)); } + bool LoopCheck::once(int taskIdx) + { + if(taskIdx < 0) return(false); + if(taskIdx >= NrOfOnceTasks) return(false); + + if(onceTaskList[taskIdx].finished == true) return(false); + onceTaskList[taskIdx].finished = true; + return(true); + } + bool LoopCheck::once(int taskIdx, unsigned int nrOfLoops) { if(taskIdx < 0) return(false); @@ -484,6 +494,26 @@ return(true); } + bool LoopCheck::onceDelayed(int taskIdx, unsigned long delay) + { + if(taskIdx < 0) return(false); + if(taskIdx >= NrOfOnceTasks) return(false); + + if(onceTaskList[taskIdx].finished == true) return(false); + + if(onceTaskList[taskIdx].firstRun == true) + { + onceTaskList[taskIdx].firstRun = false; + onceTaskList[taskIdx].startCount = loopStartMicros; + } + + if(loopStartMicros - onceTaskList[taskIdx].startCount < delay) + return(false); + + onceTaskList[taskIdx].finished = true; + return(true); + } + bool LoopCheck::toggle(int taskIdx) { bool toggleBit; diff --git a/libraries/LoopCheck/LoopCheck.h b/libraries/LoopCheck/LoopCheck.h index a27f7d51699b9c000c64a29208997a6ab117eac0..9588f3e56dc3ebe52890b772533793e533aad05d 100755 --- a/libraries/LoopCheck/LoopCheck.h +++ b/libraries/LoopCheck/LoopCheck.h @@ -149,6 +149,7 @@ class LoopCheck bool finished; bool firstRun; unsigned int waitCounter; + unsigned long startCount; } OnceTask; private: @@ -270,10 +271,17 @@ public: bool timerMilli(int taskIdx, unsigned long repeatTime, unsigned int repetitions); bool timerMilli(int taskIdx, unsigned long repeatTime, unsigned int repetitions, unsigned long delay); + bool once(int taskIdx); + // Diese Funktion liefert nur einmal den Wert <true> + bool once(int taskIdx, unsigned int nrOfLoops); // Diese Funktion liefert nur einmal den Wert <true> // nach Ablauf von nrOfLoops Aufrufen + bool onceDelayed(int taskIdx, unsigned long delay); + // Diese Funktion liefert nur einmal den Wert <true> + // nach Ablauf von <delay> Mikrosekunden + bool toggle(int taskIdx); // Diese Funktion liefert abwechselnd die Werte <true> oder <false> diff --git a/libraries/MidiNotes/MidiNotes.cpp b/libraries/MidiNotes/MidiNotes.cpp index 28ed61a665e1d8afc50d52440437c9085691f33c..ec91464f7411b1f25f33b3b536faf3b8dc1e8dcd 100644 --- a/libraries/MidiNotes/MidiNotes.cpp +++ b/libraries/MidiNotes/MidiNotes.cpp @@ -18,7 +18,7 @@ // ---------------------------------------------------------------------------- // -void MidiNotes::begin(int inBpm, NoteDiv inRes, int inMidiCycle, ComRingBuf *inCRB) +void MidiNotes::begin(int inBpm, NoteDiv inRes, int inMidiCycle, IntrfBuf *inCRB) { dword stdNoteMicroTick; @@ -30,32 +30,46 @@ void MidiNotes::begin(int inBpm, NoteDiv inRes, int inMidiCycle, ComRingBuf *inC stdNoteTick = 60000 / bpm; // Viertelnotenlänge in Millisekunden minNoteTick = stdNoteTick / inRes; // Zu erwartende kürzeste Note (ms) - typeList[nti0].length = 10 * stdNoteCount; + typeList[nti0].length = 8 * stdNoteCount; setNoteType(nti0); + typeList[nti1].length = 4 * stdNoteCount; setNoteType(nti1); - typeList[nti2].length = 2 * stdNoteCount; - setNoteType(nti2); + typeList[nti2p].length = 3 * stdNoteCount; setNoteType(nti2p); - typeList[nti4].length = stdNoteCount; - setNoteType(nti4); + + typeList[nti2].length = 2 * stdNoteCount; + setNoteType(nti2); + typeList[nti4p].length = stdNoteCount + stdNoteCount / 2; setNoteType(nti4p); + + // Standard-Note = Viertelnote ( + typeList[nti4].length = stdNoteCount; + setNoteType(nti4); + typeList[nti8].length = stdNoteCount / 2; setNoteType(nti8); + typeList[nti8p].length = stdNoteCount / 2 + stdNoteCount / 4; setNoteType(nti8p); + typeList[nti16].length = stdNoteCount / 4; setNoteType(nti16); + typeList[nti16p].length = stdNoteCount / 4 + stdNoteCount / 8; setNoteType(nti16p); + typeList[nti32].length = stdNoteCount / 8; setNoteType(nti32); + typeList[nti32p].length = stdNoteCount / 8 + stdNoteCount / 16; setNoteType(nti32p); + typeList[nti64].length = stdNoteCount / 16; setNoteType(nti64); + typeList[nti64p].length = stdNoteCount / 16 + stdNoteCount / 32; setNoteType(nti64p); @@ -80,31 +94,31 @@ void MidiNotes::setNoteType(NoteTypeIdx nt) typePtr->decay = 0; typePtr->sustain = typePtr->length; typePtr->release = 0; + typePtr->pause = (typePtr->length * 20) / 100; typePtr->deltaAttack = 0; typePtr->deltaDecay = 0; typePtr->percentSustain = 70; typePtr->deltaRelease = 0; - typePtr->percentPause = 20; } -void MidiNotes::setNoteType(NoteTypeIdx nt, dword att, dword dec, dword sus, dword rel, - byte dAtt, byte dDec, byte pSus, byte dRel, byte pPau) +void MidiNotes::setNoteType(NoteTypeIdx nt, byte pAttL, byte pDecL, byte pSusL, byte pRelL, + byte pPauL, byte dAtt, byte dDec, byte pSusV, byte dRel) { NoteTypePtr typePtr; typePtr = &typeList[nt]; - typePtr->attack = att; - typePtr->decay = dec; - typePtr->sustain = sus; - typePtr->release = rel; + typePtr->attack = (typePtr->length * pAttL) / 100; + typePtr->decay = (typePtr->length * pDecL) / 100; + typePtr->sustain = (typePtr->length * pSusL) / 100; + typePtr->release = (typePtr->length * pRelL) / 100; + typePtr->pause = (typePtr->length * pPauL) / 100; typePtr->deltaAttack = dAtt; typePtr->deltaDecay = dDec; - typePtr->percentSustain = pSus; + typePtr->percentSustain = pSusV; typePtr->deltaRelease = dRel; - typePtr->percentPause = pPau; } int MidiNotes::addChordNote(NoteTypeIdx nti, byte val, byte vel) @@ -144,23 +158,21 @@ void MidiNotes::setOpMode(MidiOpMode mom) } -void MidiNotes::setChordNote(int idx, int type, int val, int vel) +void MidiNotes::setChordNote(int idx, NoteTypeIdx nti, int val, int vel) { if(idx < 0) return; if(idx >= MaxNrNoteSim) return; - newNote.chordIdx = idx; - - if(type >= 0 && type < ntiNr) - newNote.typeIdx = type; + if(nti >= 0 && nti < ntiNr) + newNote[idx].typeIdx = nti; if(val >= 0 && val <= 127) - newNote.value = val; + newNote[idx].value = val; if(vel >= 0 && vel <= 127) - newNote.veloc = vel; + newNote[idx].veloc = vel; - newNote.newVal = true; + newNote[idx].newVal = true; } @@ -216,73 +228,82 @@ void MidiNotes::smNoteOn() bool doAttack; dword attack, sustain; - if(stopRun || stoppedRun) - { + if(stopRun || stoppedRun) // Unterbrechen/Stoppen des Ablaufs + { // vor dem Einschalten einer Note stoppedRun = true; return; } - if(crb == NULL) + if(crb == NULL) // Ohne Ausgabepuffer in Wartezustand { next(smIdle); return; } - doAttack = false; + doAttack = false; // Voreinstellung kein Aufklingen + + // Auslesen der Noten aus dem Akkordspeicher + // j = 0; for(i = 0; i < MaxNrNoteSim; i++) { notePtr = &chord[i]; - if(i == 0) + if(i == 0) // erste Note { - if(notePtr->mode == NoteModeEmpty) - { + if(notePtr->mode == NoteModeEmpty) // Wenn die erste Note leer ist + { // dann in den Wartezustand next(smIdle); return; } - noteSeq[j++] = 0x90 | chn; + noteSeq[j++] = 0x90 | chn; // ansonsten startet die Notenfolge ** } - else + else // weitere Noten { - if(notePtr->mode == NoteModeEmpty) + if(notePtr->mode == NoteModeEmpty) // bei leerer Note Schleife beendet break; } - if(newNote.newVal && (newNote.chordIdx == i)) + // Die Noten im Akkordspeicher können durch aktuelle Noten + // ersetzt werden. + + if(newNote[i].newVal) // wenn neue Note vorliegt { - newNote.newVal = false; - notePtr->typeIdx = newNote.typeIdx; - notePtr->value = newNote.value; - notePtr->veloc = newNote.veloc; + newNote[i].newVal = false; // neue Note quittieren + notePtr->typeIdx = newNote[i].typeIdx; // und Inhalte im + notePtr->value = newNote[i].value; // Akkordspeicher + notePtr->veloc = newNote[i].veloc; // überschreiben } - noteSeq[j++] = notePtr->value; + noteSeq[j++] = notePtr->value; // Notenwert in Sequenz eintragen ** + // Daten für die Note aus der Typenliste holen + // tIdx = notePtr->typeIdx; typePtr = &typeList[tIdx]; - notePtr->cntAttack = typePtr->attack; - notePtr->cntDecay = typePtr->decay; - notePtr->cntSustain = typePtr->sustain; - notePtr->cntRelease = typePtr->release; - notePtr->cntPause = (typePtr->length * typePtr->percentPause) / 100; + notePtr->cntAttack = typePtr->attack; // Aufklingzeit in Zähler + notePtr->cntDecay = typePtr->decay; // Abklingzeit in Zähler + notePtr->cntSustain = typePtr->sustain; // Klingzeit in Zähler + notePtr->cntRelease = typePtr->release; // Ausklingzeit in Zähler + notePtr->cntPause = typePtr->pause; // Pausenzeit in Zähler - if(notePtr->cntAttack != 0) + if(notePtr->cntAttack != 0) // Wenn ein Attack-Wert gegeben ist { - doAttack = true; - attack = (typePtr->deltaAttack * notePtr->veloc) / 100; + doAttack = true; // dann attack markieren + attack = // und den Wert auf den erste Schritt setzen + (typePtr->deltaAttack * notePtr->veloc) / 100; if(attack > 127) attack = 127; - noteSeq[j++] = attack; + noteSeq[j++] = attack; // Lautstärke in Sequenz eintragen ** } - else + else // ohne Attack-Wert geht es hier gleich in Sustain weiter { sustain = (typePtr->percentSustain * notePtr->veloc) / 100; if(sustain > 127) sustain = 127; - noteSeq[j++] = sustain; + noteSeq[j++] = sustain; // Lautstärke in Sequenz eintragen ** } } - crb->putSeq(noteSeq, j); + crb->putSeq(noteSeq, j); // Sequenz an Puffer übergeben ***** if(doAttack) next(smAttack); @@ -300,6 +321,11 @@ void MidiNotes::smDecay() } +// TODO +// Es können noch nicht Noten unterschiedlicher Länge in einem Akkord +// verarbeitet werden. Bei mehreren eingetragenen Noten würde die +// kürzeste Note den Ablauf bestimmen. + void MidiNotes::smSustain() { int i; @@ -312,7 +338,7 @@ void MidiNotes::smSustain() if(notePtr->mode == NoteModeEmpty) break; - if(notePtr->cntSustain > 0) + if(notePtr->cntSustain > 0) // Die Sustain-Zeit in diesem Zustand verweilen notePtr->cntSustain--; else sustFin = true; @@ -332,7 +358,7 @@ void MidiNotes::smNoteOff() int i,j; j = 0; - for(i = 0; i < MaxNrNoteSim; i++) + for(i = 0; i < MaxNrNoteSim; i++) // Alle Noten im Akkord bearbeiten { notePtr = &chord[i]; if(notePtr->mode == NoteModeEmpty) @@ -340,15 +366,15 @@ void MidiNotes::smNoteOff() if(i == 0) { - noteSeq[j++] = 0x80 | chn; + noteSeq[j++] = 0x80 | chn; // Erste Note bestimmt den Befehl AUS ** absPause = notePtr->cntPause; } - noteSeq[j++] = notePtr->value; + noteSeq[j++] = notePtr->value; //Erste und weitere Noten liefern Liste ** noteSeq[j++] = 0; } - crb->putSeq(noteSeq, j); + crb->putSeq(noteSeq, j); // Sequenz an Puffer übergeben ***** next(smPause); } diff --git a/libraries/MidiNotes/MidiNotes.h b/libraries/MidiNotes/MidiNotes.h index 30a3a7c6a509c4fe337a20b9c94e27e82bf40ba5..0f09fccd7d1a19c3c9171b0cf96c8320f5ad0b44 100644 --- a/libraries/MidiNotes/MidiNotes.h +++ b/libraries/MidiNotes/MidiNotes.h @@ -20,6 +20,11 @@ #define MaxNrNoteSim 4 #define MaxMidiSeq (2 * MaxNrNoteSim + 1) +// Definierte Noten +// +#define SchlossC 60 +#define Kammerton 69 + typedef enum _NoteDiv { nd4 = 1, @@ -84,11 +89,11 @@ private: dword decay; dword sustain; dword release; + dword pause; byte deltaAttack; byte deltaDecay; byte percentSustain; byte deltaRelease; - byte percentPause; } NoteType, *NoteTypePtr; typedef struct _Note @@ -97,6 +102,7 @@ private: byte typeIdx; byte value; byte veloc; + int state; dword cntAttack; dword cntDecay; dword cntSustain; @@ -107,7 +113,6 @@ private: typedef struct _NewNote { bool newVal; - int chordIdx; byte typeIdx; byte value; byte veloc; @@ -121,7 +126,7 @@ private: // Lokale Daten // -------------------------------------------------------------------------- // - ComRingBuf *crb; + IntrfBuf *crb; cbVector nextState; MidiOpMode opMode; @@ -144,7 +149,7 @@ private: NoteTypePtr typePtr; // Temporärer Notentyp dword absPause; // Pause für den zyklischen Ablauf - NewNote newNote; // Übergabe neuer Notenwerte + NewNote newNote[MaxNrNoteSim]; // Übergabe neuer Noten bool stopRun; // Anhalten der Midi-Schleife bool stoppedRun; // Midi-Schleife angehalten @@ -178,7 +183,7 @@ public: // -------------------------------------------------------------------------- // Initialisierungen // -------------------------------------------------------------------------- - void begin(int inBpm, NoteDiv inRes, int inMidiCycle, ComRingBuf *inCRB); + void begin(int inBpm, NoteDiv inRes, int inMidiCycle, IntrfBuf *inCRB); // -------------------------------------------------------------------------- @@ -187,8 +192,8 @@ public: // void setNoteType(NoteTypeIdx nt); - void setNoteType(NoteTypeIdx nt, dword att, dword dec, dword sus, dword rel, - byte dAtt, byte dDec, byte dSus, byte dRel, byte pPau); + void setNoteType(NoteTypeIdx nt, byte pAttL, byte pDecL, byte pSusL, byte pRelL, + byte dAtt, byte dDec, byte pSusV, byte dRel, byte pPauL); int addChordNote(NoteTypeIdx nti, byte val, byte vel); @@ -199,7 +204,7 @@ public: // -------------------------------------------------------------------------- // void setOpMode(MidiOpMode mom); - void setChordNote(int idx, int type, int val, int vel); + void setChordNote(int idx, NoteTypeIdx nti, int val, int vel); // -------------------------------------------------------------------------- // Steuerung, Zustandsmaschine diff --git a/libraries/Monitor/Monitor.cpp b/libraries/Monitor/Monitor.cpp index 6f2e3a8650b6aa4646ca320ffe5b9f6e621f0fe3..9c30d24b20011e8d22623c261a295ccfb42fe1ea 100644 --- a/libraries/Monitor/Monitor.cpp +++ b/libraries/Monitor/Monitor.cpp @@ -38,6 +38,13 @@ void Monitor::init(int inMode, int inCpu, LoopCheck *inLcPtr, IntrfTw *inTwPtr) twiPtr = inTwPtr; nrOfChnChar = '@'; +#ifdef smnNANOBLE33 + + microTicValPtr = (dword *) 0x40009548; + microTicCapPtr = (dword *) 0x40009048; + +#endif + nextState = &Monitor::waitEnter; } @@ -146,6 +153,8 @@ void Monitor::sendConfig() //----------------------------------------------------------------------------- // +volatile dword calcTest1, calcTest2, calcTest3; + void Monitor::waitEnter() { char c; @@ -167,6 +176,35 @@ void Monitor::waitEnter() GoPrm } +void doSomeCode() +{ + for(int i = 0; i < 500; i++) + { + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + calcTest1++; + } +} + +volatile dword micTime; + void Monitor::getKey() { char cin,c1,c0; @@ -288,8 +326,10 @@ void Monitor::getKey() } break; - case 't': - case 'T': + // ------------------------------------------------------------------------ + case 't': // Zeitmessungen + case 'T': // + // ------------------------------------------------------------------------ if(inIdx == 0) { inChar[inIdx] = cin; @@ -311,6 +351,17 @@ void Monitor::getKey() { cmdMode1 = 'C'; } +#ifdef smnNANOBLE33 + else if(cin == 'p' || cin == 'P') + { + micTime = micsecs(); + doSomeCode(); + micTime = (micsecs() - micTime - 11) / 10; + out(' '); + out(micTime); + GoPrm + } +#endif else if(cin == 'r' || cin == 'R') { if(lcPtr != NULL) @@ -320,6 +371,33 @@ void Monitor::getKey() } GoPrm } + else if(cin == 't' || cin == 'T') + { + dword micTime = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + calcTest2 = micros(); + micTime = (micros() - micTime) / 20; + out(' '); + out(micTime); + GoPrm + } else { GoPrm diff --git a/libraries/Monitor/Monitor.h b/libraries/Monitor/Monitor.h index 28b68a9f60bff737588d7c9b96173c91314e9ec2..1ee2bb11830c716703e5489655355c93a039d131 100644 --- a/libraries/Monitor/Monitor.h +++ b/libraries/Monitor/Monitor.h @@ -62,6 +62,11 @@ private: int cpu; int mode; +#ifdef smnNANOBLE33 + dword *microTicValPtr; + dword *microTicCapPtr; +#endif + char buffer[BufSize]; int wrIdx; int rdIdx; @@ -121,6 +126,16 @@ private: void print(unsigned int iVal, int eol); void prints(int iVal, int eol); +#ifdef smnNANOBLE33 + + dword micsecs() + { + *microTicCapPtr = 1; + return(*microTicValPtr); + } + +#endif + // -------------------------------------------------------------------------- // Datenaufbereitung // -------------------------------------------------------------------------- diff --git a/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp b/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp index 2349207da8b5618a35be89e481564fbb33a82038..5a57198a5bb3b3c340ffa5a725f7f7c009725d9a 100644 --- a/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp +++ b/libraries/SensorLSM9DS1/SensorLSM9DS1.cpp @@ -436,6 +436,18 @@ void SensorLSM9DS1::run1() */ +void SensorLSM9DS1::stop() +{ + enableMeasAG = false; + enableMeasM = false; +} + +void SensorLSM9DS1::resume() +{ + enableMeasAG = true; + enableMeasM = true; +} + void SensorLSM9DS1::run() { runStateCntTotal++; @@ -719,6 +731,10 @@ void SensorLSM9DS1::run() } } +void SensorLSM9DS1::syncValuesM() +{ + newValueM = false; +} bool SensorLSM9DS1::getValuesM(RawDataMPtr rdptr) { @@ -846,6 +862,14 @@ dword SensorLSM9DS1::debGetDword(int code) } +dword SensorLSM9DS1::debGetRunState(int code) +{ + if(0 <= code < 9) + return(runStateCntArray[code]); + else + return(0); +} + diff --git a/libraries/SensorLSM9DS1/SensorLSM9DS1.h b/libraries/SensorLSM9DS1/SensorLSM9DS1.h index 6ce65b67a378947f9728ba32f5b298c8dc6bd80f..63cb831c96688b30a85397927a14a52dcb6a15f2 100644 --- a/libraries/SensorLSM9DS1/SensorLSM9DS1.h +++ b/libraries/SensorLSM9DS1/SensorLSM9DS1.h @@ -86,8 +86,9 @@ typedef enum _MaxG #define M_Id 0x0F #define M_Ctrl1 0x20 #define M_Ctrl2 0x21 -#define M_Ctrl3 0x23 -#define M_Ctrl4 0x24 +#define M_Ctrl3 0x22 +#define M_Ctrl4 0x23 +#define M_Ctrl5 0x24 #define M_Status 0x27 #define M_Out 0x28 @@ -312,6 +313,8 @@ public: void run(); void run0(); void run1(); + void stop(); + void resume(); // -------------------------------------------------------------------------- // Datenaustausch @@ -336,6 +339,7 @@ public: bool getValuesAG(RawDataAGPtr rdptr); bool getValuesAG(CalValueAGPtr calPtr); bool getAvgValuesAG(CalValueAGPtr calPtr); + void syncValuesM(); bool getValuesM(RawDataMPtr rdptr); bool getValuesM(CalValuePtr calPtr); @@ -351,6 +355,7 @@ public: dword runStateCntArray[NrOfRunStates]; dword runStateCntTotal; dword debGetDword(int code); + dword debGetRunState(int code); }; diff --git a/libraries/SoaapMsg/SoaapMsg.cpp b/libraries/SoaapMsg/SoaapMsg.cpp index d2f66c5f028eaac9a0b3beea4bc2d04263c44cbd..0f3f29704b3b1d5e02528071b0527804940435bd 100644 --- a/libraries/SoaapMsg/SoaapMsg.cpp +++ b/libraries/SoaapMsg/SoaapMsg.cpp @@ -48,7 +48,11 @@ int SoaapMsg::getMsgA(int area, int slvNr, SoaapApId appId, char *dest, byte * measLen = 18; break; - case saiMaximalMeas: + case saiDefaultMeasCtrl: + measLen = 18; + break; + + case saiMaximalMeas: measLen = 26; break; } @@ -70,6 +74,23 @@ int SoaapMsg::getMsgA(int area, int slvNr, SoaapApId appId, char *dest, byte * dest[msgIdx++] = measChar; } + if(appId == saiDefaultMeasCtrl) + { + measByte = meas[20]; + + // Erst das niederwertige Nibble als Hex-Ascii eintragen + // + measChar = (measByte & 0x0F) | 0x30; + if (measChar > 0x39) measChar += 7; + dest[msgIdx++] = measChar; + + // dann das höherwertige Nibble + // + measChar = (measByte >> 4) | 0x30; + if (measChar > 0x39) measChar += 7; + dest[msgIdx++] = measChar; + } + dest[msgIdx] = '\0'; return(msgIdx); } @@ -100,6 +121,10 @@ int SoaapMsg::measRes(SoaapApId appId) retv = 4; break; + case saiDefaultMeasCtrl: + retv = 4; + break; + case saiMaximalMeas: retv = 4; break; @@ -120,6 +145,10 @@ int SoaapMsg::measCnt(SoaapApId appId) retv = 9; break; + case saiDefaultMeasCtrl: + retv = 9; + break; + case saiMaximalMeas: retv = 13; break; diff --git a/libraries/SoaapMsg/SoaapMsg.h b/libraries/SoaapMsg/SoaapMsg.h index ef210b094873804d4afd373513c2207b7fc28081..20df5732381c353181e02ce74cf3cf193789c5a0 100644 --- a/libraries/SoaapMsg/SoaapMsg.h +++ b/libraries/SoaapMsg/SoaapMsg.h @@ -15,14 +15,13 @@ #ifndef SoaapMsg_h #define SoaapMsg_h -#ifndef byte -#define byte unsigned char -#endif +#include "arduinoDefs.h" typedef enum { saiDefaultMeas = 0x68, - saiMaximalMeas = 0x69 + saiMaximalMeas = 0x69, + saiDefaultMeasCtrl = 0x6A } SoaapApId; class SoaapMsg diff --git a/libraries/environment/IntrfBuf.h b/libraries/environment/IntrfBuf.h index 89651bc82ccbdbb534f50ae58402e0fe44a1dc9a..c2f41d77dacb2618fee37685820740222e70b8b3 100644 --- a/libraries/environment/IntrfBuf.h +++ b/libraries/environment/IntrfBuf.h @@ -40,6 +40,8 @@ public: virtual void putByteRec(byte b); // Byte vom Empfang an Puffer geben + virtual int putSeq(byte *msg, int n); // Bytefolge an Puffer übergeben + }; // ---------------------------------------------------------------------------- diff --git a/libraries/nRF52840Gpio/nRF52840Gpio.cpp b/libraries/nRF52840Gpio/nRF52840Gpio.cpp index 872b9222fc9e8236bb6555f8925f96c60842e50b..47a25ddebcff11a2d9ef003cf83ddf1be250d057 100644 --- a/libraries/nRF52840Gpio/nRF52840Gpio.cpp +++ b/libraries/nRF52840Gpio/nRF52840Gpio.cpp @@ -257,6 +257,22 @@ void nRF52840Gpio::write(GpioExtRefPtr refPtr, GpioExtValPtr valPtr) ((nrfGpioPtr) refPtr->next->ioPtr)->OUTCLR = ~valPtr->next->value & refPtr->next->pins; } +void nRF52840Gpio::set(GpioExtRefPtr refPtr) +{ + ((nrfGpioPtr) refPtr->ioPtr)->OUTSET = refPtr->pins; + if(refPtr->next == NULL) return; + ((nrfGpioPtr) refPtr->next->ioPtr)->OUTSET = refPtr->next->pins; +} + +void nRF52840Gpio::clr(GpioExtRefPtr refPtr) +{ + ((nrfGpioPtr) refPtr->ioPtr)->OUTCLR = refPtr->pins; + if(refPtr->next == NULL) return; + ((nrfGpioPtr) refPtr->next->ioPtr)->OUTCLR = refPtr->next->pins; +} + + + void nRF52840Gpio::writeArd(ArdMask ardMask, dword value) { dword set0 = 0, set1 = 0; diff --git a/libraries/nRF52840Gpio/nRF52840Gpio.h b/libraries/nRF52840Gpio/nRF52840Gpio.h index 4096efe4a5fc6b4f0179b2c9c46ee9a333558921..addf5ad533ddfecabd2c540824238c278a117998 100644 --- a/libraries/nRF52840Gpio/nRF52840Gpio.h +++ b/libraries/nRF52840Gpio/nRF52840Gpio.h @@ -163,6 +163,8 @@ public: void write(GpioExtRefPtr refPtr, GpioExtValPtr valPtr); void writeArd(ArdMask ardMask, dword value); + void set(GpioExtRefPtr refPtr); + void clr(GpioExtRefPtr refPtr); // ---------------------------------------------------------------------------- // Ereignisbearbeitung und Interrupts diff --git a/libraries/nRF52840Radio/nRF52840Radio.cpp b/libraries/nRF52840Radio/nRF52840Radio.cpp index 47063590d0d33a8132084d4affe4c2a34a302834..5639480f98f812bc2170a24674d34534dd95d5e6 100644 --- a/libraries/nRF52840Radio/nRF52840Radio.cpp +++ b/libraries/nRF52840Radio/nRF52840Radio.cpp @@ -163,11 +163,20 @@ void nRF52840Radio::send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, NrfRadioPtr->EVENTS_TXREADY = 0; NrfRadioPtr->EVENTS_ADDRESS = 0; + // TODO + // Das muss Alles noch einmal überarbeitet werden. + // Hier stecken zu viele Redundanzen drin, Altlast aus diversen Tests mit der Hardware + memcpy((void *)pduMem, (void *)inPduPtrE, sizeof(bcPdu)); // Daten in Funkpuffer kopieren + memcpy((void *)pduSentE, (void *)inPduPtrE, sizeof(bcPdu)); // Daten in extra Puffer kopieren - if(inPduPtrS != NULL) - memcpy((void *)pduSentS, (void *)inPduPtrS, sizeof(bcPdu));// Daten in extra Puffer kopieren + // Die übergebenen Daten werden in einen Extrapuffer kopiert zur Entkopplung für eventuelle + // lokale Modifikationen + if(inPduPtrS != NULL) // Falls Daten für eine Antwort gegeben sind + memcpy((void *)pduSentS, (void *)inPduPtrS, sizeof(bcPdu));// Daten in extra Puffer kopieren + // Die übergebenen Daten werden in einen Extrapuffer kopiert zur Entkopplung für eventuelle + // lokale Modifikationen comFin = false; comError = false; @@ -184,6 +193,21 @@ void nRF52840Radio::send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, switch(txMode) { + case txmPoll: + recMode = false; + NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN | NrfScRXREADY_START; + NrfRadioPtr->INTENSET = NrfIntRXREADY; + NrfRadioPtr->TASKS_TXEN = 1; + break; + + case txmResp: + case txmRespE: + recMode = true; + NrfRadioPtr->SHORTS = NrfScREADY_START; + NrfRadioPtr->INTENSET = NrfIntEND; + NrfRadioPtr->TASKS_RXEN = 1; + break; + case txmBase: NrfRadioPtr->SHORTS = NrfScREADY_START | NrfScEND_DISABLE; NrfRadioPtr->TASKS_TXEN = 1; @@ -220,21 +244,6 @@ void nRF52840Radio::send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, NrfRadioPtr->INTENSET = NrfIntADDRESS | NrfIntEND; NrfRadioPtr->TASKS_TXEN = 1; break; - - case txmPoll: - recMode = false; - NrfRadioPtr->SHORTS = NrfScTXREADY_START | NrfScEND_DISABLE | NrfScDISABLED_RXEN | NrfScRXREADY_START; - NrfRadioPtr->INTENSET = NrfIntRXREADY; - NrfRadioPtr->TASKS_TXEN = 1; - break; - - case txmResp: - case txmRespE: - recMode = true; - NrfRadioPtr->SHORTS = NrfScREADY_START; - NrfRadioPtr->INTENSET = NrfIntEND; - NrfRadioPtr->TASKS_RXEN = 1; - break; } } @@ -412,6 +421,50 @@ void nRF52840Radio::cont(TxMode txMode) } } +int nRF52840Radio::getRecData(bcPduPtr data, TxMode txMode, int max) +{ + byte *bPtr = (byte *) data; + int retv = 0; + + switch(txMode) + { + case txmResp: + data->head = pduSentE[0]; + retv = data->len = pduSentE[1]; + + for(int i = 2; i < (retv + 2); i++) + { + if(i == max) break; + bPtr[i] = pduSentE[i]; + } + + break; + + case txmBase: + break; + + case txmRepStart: + break; + + case txmRepCont: + break; + + case txmRepEnd: + break; + + case txmReadPrep: + break; + + case txmRead: + break; + } + + + return(retv); +} + + + // ---------------------------------------------------------------------------- // E m p f a n g e n // ---------------------------------------------------------------------------- @@ -729,6 +782,7 @@ void nRF52840Radio::irqHandler() // -------------------------------------------------------------------- if(NrfRadioPtr->EVENTS_END == 1) // Übertragung beendet + // Polling-Daten empfangen // -------------------------------------------------------------------- { NrfRadioPtr->EVENTS_END = 0; // Event quittieren @@ -783,8 +837,10 @@ void nRF52840Radio::irqHandler() else { // Sendeaufforderung + // Polling-Steuerdaten in Empfangspuffer und // Sadr-Ack-Daten in Funkpuffer kopieren // + memcpy((void *)pduSentE, (void *)pduMem, sizeof(bcPdu)); memcpy((void *)pduMem, (void *)pduSentS, sizeof(bcPdu)); } @@ -829,128 +885,6 @@ void nRF52840Radio::irqHandler() break; - /* - // ---------------------------------------------------------------------- - case txmResp: // Datenübertragung Slave - // ---------------------------------------------------------------------- - - // -------------------------------------------------------------------- - if(NrfRadioPtr->EVENTS_END == 1) // Übertragung beendet - // -------------------------------------------------------------------- - { - NrfRadioPtr->EVENTS_END = 0; // Event quittieren - - if(recMode) // im Empfangsmodus (SADR/EADR) - { // ---------------------------------------------------------------- - NrfRadioPtr->SHORTS = 0; // keine direkte Kopplung mehr - - // ---------------------------------------------------------------- - // Reaktion - // ---------------------------------------------------------------- - // - if((pduSentE[5] == pduMem[5]) && (pduSentE[6] == pduMem[6]) && (pduSentE[7] == pduMem[7])) - { - // Die richtige Protokollumgebung (z.B. Soaap) - // - if(pduSentE[2] != pduMem[2]) - { - // aber die falsche Adresse - // Datenempfang fortsetzen - statisticPtr->wrongs++; - NrfRadioPtr->TASKS_START = 1; - } - else - { // richtige Adresse, Antwort schicken - // ------------------------------------------------------------ - eadM = ((pduMem[3] & SOAAP_EADR) != 0); - nakM = ((pduMem[3] & SOAAP_NAK) != 0); - - if(nakM) - statisticPtr->pollNaks++; - else - statisticPtr->pollAcks++; - - // zunächst alle Funk-Interrupts sperren - NrfRadioPtr->INTENCLR = 0xFFFFFFFF; - - // Interrupt freigeben für "Abgeschaltet" - NrfRadioPtr->INTENSET = NrfIntDISABLED; - - // Empfangsbetrieb abschalten - NrfRadioPtr->TASKS_DISABLE = 1; - } - - } - else - { - // Fremde Umgebung (nicht akzeptierte PDU) - // Datenempfang fortsetzen - statisticPtr->aliens++; - NrfRadioPtr->TASKS_START = 1; - } - } - else // im Sendemodus - { // ---------------------------------------------------------------- - // - // Das wäre ein Fehler, kein END beim Senden erwartet sondern DISABLED - } - } - - // -------------------------------------------------------------------- - if(NrfRadioPtr->EVENTS_DISABLED == 1) // ausgeschaltet - // -------------------------------------------------------------------- - { - NrfRadioPtr->EVENTS_DISABLED = 0; // quittieren - - if(recMode) // *** im Empfangsmodus *** - { - // zunächst alle Funk-Interrupts sperren - NrfRadioPtr->INTENCLR = 0xFFFFFFFF; - - // Interrupt freigeben für "Abgeschaltet" (nach dem Senden) - NrfRadioPtr->INTENSET = NrfIntDISABLED; - - // Kopplung automatisch starten und abschalten nach Ende - NrfRadioPtr->SHORTS = NrfScREADY_START | NrfScEND_DISABLE; - - // Daten in Funkpuffer kopieren - if(eadM) - // ToDo: Hier auch auf Empfangspolling reagieren - memcpy((void *)pduMem, (void *)pduSentE, sizeof(bcPdu)); - else - { - // Sendepolling, Daten je nach Modus manipulieren - // -------------------------------------------------------------- - - if(newValues || !nakM) - // neue Messwerte oder Polling ohne Nak-Bit - { - newValues = false; // neue Messwerte quittieren - memcpy((void *)pduMem, (void *)pduSentS, sizeof(bcPdu)); - // ansonsten ist das Telegramm in pduSentS schon das Richtige - } - else - // keine Daten, nur NAK (vom Master mit Nak-Bit gefordert) - { - memcpy((void *)pduMem, (void *)pduSentS, PollPduSize); - BLE_LEN = PollAdrSize; - BLE_ADR1 |= SOAAP_NAK; - } - } - - NrfRadioPtr->TASKS_TXEN = 1; // Sender einschalten - recMode = false; - } - else // *** im Sendemodus *** - { - NrfRadioPtr->SHORTS = 0; - statisticPtr->sendings++; - comFin = true; // Pollvorgang abgeschlossen - } - } - - break; - */ } } @@ -963,16 +897,6 @@ int nRF52840Radio::getStatistics(TxStatisticsPtr dest) int retv = 0; *dest = *statisticPtr; - /* - dest->aliens = statisticPtr->aliens; - dest->interrupts = statisticPtr->interrupts; - dest->mode = statisticPtr->mode; - dest->pollAcks = statisticPtr->pollAcks; - dest->pollNaks = statisticPtr->pollNaks; - dest->recs = statisticPtr->recs; - dest->sendings = statisticPtr->sendings; - dest->wrongs = statisticPtr->wrongs; - */ return(retv); } diff --git a/libraries/nRF52840Radio/nRF52840Radio.h b/libraries/nRF52840Radio/nRF52840Radio.h index 4bbc7f5bb3db38c122c948dd17780cdac7795dd9..0e61246043b8b3bd78928b3e33e31f81e180d011 100644 --- a/libraries/nRF52840Radio/nRF52840Radio.h +++ b/libraries/nRF52840Radio/nRF52840Radio.h @@ -269,6 +269,7 @@ public: void send(bcPduPtr inPduPtr, TxMode txMode); void send(bcPduPtr inPduPtrE, bcPduPtr inPduPtrS, TxMode txMode, bool newValues); + int getRecData(bcPduPtr data, TxMode txMode, int max); // Empfangene Daten lesen void disable(TxMode txMode); bool disabled(TxMode txMode); // Abfrage, ob ausgeschaltet diff --git a/libraries/nRF52840Twi/nRF52840Twi.h b/libraries/nRF52840Twi/nRF52840Twi.h index 17294d28f9a08246334135e9b232b5074cfdd8eb..e33ca74b72c254311a695ab5ea7fd3152a8ebf4d 100644 --- a/libraries/nRF52840Twi/nRF52840Twi.h +++ b/libraries/nRF52840Twi/nRF52840Twi.h @@ -75,7 +75,7 @@ typedef enum _TwiTrfMode ttmReadByteRegSeq } TwiTrfMode; -#ifndef nrfGpio +#ifndef nrfGpioDef typedef struct _nrfGpio { @@ -121,6 +121,7 @@ typedef struct _nrfGpio #define GpioSenseHigh 2 #define GpioSenseLow 3 +#define nrfGpioDef #endif // Festlegungen für die Paketkonfigurationsregister diff --git a/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.ino b/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.ino index 0679032916d0a32d5c06fa3fcd136f096ba61091..1aaf110af91edb270cd1165e6261a89eff15a437 100644 --- a/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.ino +++ b/sketches/SoaapBleMidiMaster/SoaapBleMidiMaster.ino @@ -200,13 +200,13 @@ void setup() // für die Übergabe zu sendender Zeichen setParM1(); - midi1.begin(120, nd32, MidiCycle, &crb); + midi1.begin(120, nd32, MidiCycle, (IntrfBuf *) &crb); midi1.setChannel(1); setParM2(); - midi2.begin(120, nd32, MidiCycle, &crb); + midi2.begin(120, nd32, MidiCycle, (IntrfBuf *) &crb); midi2.setChannel(2); - midi2.stop(); + //midi2.stop(); } // ============================================================================ @@ -301,10 +301,10 @@ void apInit() #endif midi1.setNoteType(MidiNotes::nti8); - lastNoteIdxM1 = midi1.addChordNote(MidiNotes::nti8, 60, 100); + lastNoteIdxM1 = midi1.addChordNote(MidiNotes::nti8, SchlossC, 10); midi1.setOpMode(momSequence); midi2.setNoteType(MidiNotes::nti8); - lastNoteIdxM2 = midi2.addChordNote(MidiNotes::nti8, 60, 100); + lastNoteIdxM2 = midi2.addChordNote(MidiNotes::nti8, Kammerton, 10); midi2.setOpMode(momSequence); ap.enter(apWaitDE); } @@ -400,12 +400,13 @@ short accXold, accYold, accZold; void apCheckValues() { - bool newData = false; + //bool newData = false; short accX = * (short *) &apMeasByteArray[6]; short accY = * (short *) &apMeasByteArray[8]; short accZ = * (short *) &apMeasByteArray[10]; + /* newData |= (accX != accXold); newData |= (accY != accYold); newData |= (accZ != accZold); @@ -415,10 +416,12 @@ void apCheckValues() ap.enter(apWaitMeas); return; } + */ accXold = accX; accYold = accY; accZold = accZ; + ap.enter(apCalcResult); } @@ -496,9 +499,9 @@ void apCalcResult() void apSetResult() { if(slNr == 1) - midi1.setChordNote(lastNoteIdxM1, resultAx, resultAz, 100); + midi1.setChordNote(lastNoteIdxM1, (MidiNotes::NoteTypeIdx) resultAx, resultAz, 100); else if(slNr == 2) - midi2.setChordNote(lastNoteIdxM2, resultAx, resultAz, 100); + midi2.setChordNote(lastNoteIdxM2, (MidiNotes::NoteTypeIdx) resultAx, resultAz, 100); ap.enter(apWaitMeas); } diff --git a/sketches/ctrlMidi/SoaapMidi.ino b/sketches/ctrlMidi/SoaapMidi.ino index 4dd337d3e30810a831fc87fbd26b04dd473d5b51..7dbe7c1d6e70c3325faa99eb58640cff191c2098 100644 --- a/sketches/ctrlMidi/SoaapMidi.ino +++ b/sketches/ctrlMidi/SoaapMidi.ino @@ -1,12 +1,14 @@ #include "Arduino.h" +#include "SoaapMidi.h" + #include "LoopCheck.h" #include "StateMachine.h" #include "Monitor.h" #include "ComRingBuf.h" #include "nRF52840Ser.h" -#include "Midi.h" +#include "MidiNotes.h" #include "nRF52840Twi.h" #include "SensorLSM9DS1.h" @@ -16,7 +18,6 @@ LoopCheck lc; #define SmCycle 5 -void smInit(); StateMachine sm(smInit, NULL, SmCycle); Monitor mon(modeEcho | modeNl,0,&lc); SerParams ttyParams; @@ -27,7 +28,7 @@ ComRingBuf crb; byte sndBuffer[sndBufSize]; #define MidiCycle 1000 -Midi midi; +MidiNotes midi; nRF52840Twi twi; #define SensorCycle 500 @@ -41,6 +42,8 @@ FilterResult fi10, fi100; void setup() { + Serial.begin(115200); + TwiParams twiPar; // Parameter für den I2C-Bus ttyParams.inst = 0; // Instanzindex der Schnittstelle @@ -69,7 +72,7 @@ void setup() twi.begin(&twiPar); // Initialisierung des I2C-Bus - sens.begin(FreqAG119, 12, MaxAcc4g, MaxGyro2000dps, FreqM_OFF, 0, MaxMag4G); + sens.begin(FreqAG119, 12, MaxAcc4g, MaxGyro2000dps, FreqM10, 0, MaxMag4G); sens.syncValuesAG(); rmAz.begin(RmBufSize, rmBuffer); @@ -112,8 +115,8 @@ int lastNoteIdx = 0; void smInit() { - midi.setNoteType(Midi::nti8); - lastNoteIdx = midi.addChordNote(Midi::nti8, 60, 100); + midi.setNoteType(MidiNotes::nti8); + lastNoteIdx = midi.addChordNote(MidiNotes::nti8, 60, 100); midi.setOpMode(momSequence); rmAz.setEdge(0, 10); rmAz.setEdge(1, 100); @@ -123,7 +126,14 @@ void smInit() void smIdle() { + //sm.enter(smTestValues); sm.enter(smGetValues); + //mon.printcr("Hier Test Midi"); + //sm.setDelay(500); + //if(mon.cFlag[0]) + //{ + //sm.enter(smGetValues); + //} } @@ -145,33 +155,37 @@ void smGetValues() if(!sens.getValuesAG(&rawData)) return; - rmAz.enterValue(rawData.valueAG.G.x); - rmAz.filter(0, &fi10); - rmAz.filter(1, &fi100); + //rmAz.enterValue(rawData.valueAG.G.x); + //rmAz.filter(0, &fi10); + //rmAz.filter(1, &fi100); // Test if(mon.cFlag[1]) { - mon.print(rawData.valueAG.G.x); - mon.putBuf(' '); - mon.print(fi10.avg); - mon.putBuf('|'); - mon.print(fi100.avg); - mon.putBuf(' '); - mon.putBuf(' '); - mon.print(fi10.hp); - mon.putBuf('|'); - mon.print(fi100.hp); + mon.print(rawData.valueAG.A.x); mon.putBuf(' '); - mon.print(fi10.intI); - mon.putBuf('|'); - mon.print(fi100.intI); + mon.print(rawData.valueAG.A.y); mon.putBuf(' '); - mon.print(fi10.intII); - mon.putBuf('|'); - mon.println(fi100.intII); + mon.println(rawData.valueAG.A.z); + //mon.print(fi10.avg); + //mon.putBuf('|'); + //mon.print(fi100.avg); + //mon.putBuf(' '); + //mon.putBuf(' '); + //mon.print(fi10.hp); + //mon.putBuf('|'); + //mon.print(fi100.hp); + //mon.putBuf(' '); + //mon.print(fi10.intI); + //mon.putBuf('|'); + //mon.print(fi100.intI); + //mon.putBuf(' '); + //mon.println(fi10.intII); + //mon.putBuf('|'); + //mon.println(fi100.intII); } + //sm.setDelay(1000); sm.enter(smCheckValues); } @@ -194,14 +208,15 @@ void smCheckValues() short borderLowAz = 100; -short borderHighAz = 8300; +short borderHighAz = 8000; short borderLowAy = 100; short borderHighAy = 8300; short borderLowAx = 100; -short borderHighAx = 2000; +short borderHighAx = 4000; byte lowNote = 23; -byte highNote = 72; +//byte highNote = 72; +byte highNote = 96; byte resultAz; byte resultAy; @@ -215,7 +230,8 @@ void smCalcResult() return; } - int result = lowNote + (highNote * rawData.valueAG.A.z) / borderHighAz; + short testY = rawData.valueAG.A.z + rawData.valueAG.A.y / 4; + int result = lowNote + (highNote * testY) / borderHighAz; if(result > highNote) resultAz = highNote; else if (result < lowNote) @@ -223,9 +239,10 @@ void smCalcResult() else resultAz = result; - result = (Midi::ntiNr * rawData.valueAG.A.x) / borderHighAz; - if(result < Midi::nti2) result = Midi::nti2; - if(result > Midi::nti64) result = Midi::nti64; + testY = rawData.valueAG.A.x + rawData.valueAG.A.y / 4; + result = (MidiNotes::nti32 * testY) / borderHighAz; + if(result < MidiNotes::nti2) result = MidiNotes::nti2; + if(result > MidiNotes::nti32) result = MidiNotes::nti32; resultAx = result; sm.enter(smSetResult); @@ -246,7 +263,7 @@ byte testValue = 0; void smTestValues() { - midi.setChordNote(lastNoteIdx, Midi::nti4, testValue, 60); + midi.setChordNote(lastNoteIdx, MidiNotes::nti4, testValue, 60); testValue++; if(testValue > 127) testValue = 0; diff --git a/sketches/pollingBLE/SoaapBleMaster.ino b/sketches/pollingBLE/SoaapBleMaster.ino index 35420344d060a3223c31c7bda5e4949706c800cd..decd131a6598887088ff37ba22cc54d2f2a81ace 100644 --- a/sketches/pollingBLE/SoaapBleMaster.ino +++ b/sketches/pollingBLE/SoaapBleMaster.ino @@ -5,53 +5,34 @@ // P o l l i n g - M a s t e r // ---------------------------------------------------------------------------- // Editor: Robert Patzke -// URI/URL: www.mfp-portal.de +// URI/URL: www.hs-hannover.de //----------------------------------------------------------------------------- // Lizenz: CC-BY-SA (wikipedia: Creative Commons) // Datum: 1. November 2021 -// Letzte Bearbeitung: 1. November 2021 +// Letzte Bearbeitung: 4. Februar 2022 // -#include "Arduino.h" -#include "LoopCheck.h" -#include "StateMachine.h" -#include "nRF52840Radio.h" -#include "BlePoll.h" -#include "Monitor.h" - -#define DebugTerminal -// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden -// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist +#include "Arduino.h" +#include "SoaapBleMaster.h" +// ---------------------------------------------------------------------------- LoopCheck lc; +// ---------------------------------------------------------------------------- // Eine statische Instanz der Klasse LoopCheck // Darüber wird das Zeitverhalten gesteuert (Software-Timer) und geprüft -#ifdef DebugTerminal -Monitor mon(modeEcho | modeNl,0,&lc); -// Eine statische Instanz (mit Konstruktordaten) der Klasse Monitor -// Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert -// Unter Linux werden hier GtkTerm (siehe Internet) und -// ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt. -// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeigent, -// weil damit keine direkte Kommunikation (getipptes Zeichen sofort gesendet) -// möglich ist. -// ----- Parameter ------------------------------------------------------------ -// <mode Echo> Alle eintreffenden Zeichen werden sofort zurückgesendet -// <mode NL> Vor der Ausgabe des Prompt (M>) erfolgt CR/LF -// <0> Für Speicherzugriffe wird von 32 Bit ARM ausgegangen -// <&lc> Für Zeitüberwachungen und entsprechende statisctische Daten -// greift die Monitor-Klasse auf die LoopCheck-Klasse zu -#endif - +// ---------------------------------------------------------------------------- nRF52840Radio bleCom; +// ---------------------------------------------------------------------------- // Eine statische Instanz der Klasse nRF52840Radio // Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und // Empfangen von BLE-Beacons angesprochen. -#define bleCycleTime 150 +#define bleCycleTime 250 +// ---------------------------------------------------------------------------- BlePoll blePoll((IntrfRadio *) &bleCom, micros); +// ---------------------------------------------------------------------------- // Eine statische Instanz der Klasse BlePoll // Darüber werden das Polling des Masters als auch die Antworten der Slaves // gesteuert. Es können Geräte entwickelt werden, die nur Master oder Slave @@ -67,11 +48,67 @@ BlePoll blePoll((IntrfRadio *) &bleCom, micros); // 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. +// was hier einer Auflösung von 250 Mikrosekunden entspricht. + +#define NrOfSlavesToPoll 5 +// Die Anzahl der Slaves, die der Master aufrufen soll (Polling). +// Es wird grundsätzlich mit der Adresse 1 begonnen und nach dem Aufruf die +// Adresse inkrementiert, also immer die Slaves Adr = 1 bis +// Adr = NrOfSlavesToPoll+1 aufgerufen. +// ACHTUNG! +// Diese Zahl muss kleiner/gleich der in BlePoll.h definierten maximalen +// Anzahl der Slaves (MAXSLAVE) sein, weil die Ressourcen darüber statisch +// festgelegt werden. + +SerParams ttyParams; +// ---------------------------------------------------------------------------- +nRF52840Ser tty; +// ---------------------------------------------------------------------------- +// Eine statische Instanz der Klasse nRF52840Ser (UART) +// Darüber werden die seriellen Schnittstellen (UARTE0 und UARTE1) des +// nRF52840 bedient. +// Die Parameter werden in einer Struktur <SerParams> über die Funktion +// <begin(...)> gesetzt. + +#define sndBufSize 256 +byte sndBuffer[sndBufSize]; +// ---------------------------------------------------------------------------- +ComRingBuf crb; +// ---------------------------------------------------------------------------- +// Eine statische Instanz der Klasse <ComRingBuf> +// Damit wird ein Ringpuffer aufgebaut, der eine serielle Schnittstelle bedient. +// Der Speicher muss extra eingerichtet und mit der Funktion +// <setWriteBuffer(sndBufSize, sndBuffer)> übergeben werden. +// Die Klasse für die serielle Schnittstelle muss von <IntrfSerial> abgeleitet +// sein, die Instanz wird mit der Funktion <begin(...)> übergeben. + +#define appCycleTime 500 +StateMachine ap(apInit, NULL, appCycleTime); +// Eine statische Instanz für die Zustandsmaschine, die hier für die +// Anwendung (App) von SOAAP eingesetzt wird +// ----- Parameter ------------------------------------------------------------ +// <smInit> Der zuerst aufgerufene Zustand (Funktion). Weitere Zustände +// werden in den weiteren Zustandsfunktionen eingesetzt. +// <NULL> Hier kann eine weitere Zustandsfunktion angegeben werden, +// die dann grundsätzlich vor dem Verzweigen in einen Zustand +// aufgerufen wird. +// <smCycleTime> Die Zukluszeit (Takt) der Zustandsmaschine in Mikrosekunden + + +// ---------------------------------------------------------------------------- +SoaapMsg sMsg; +// ---------------------------------------------------------------------------- +// Eine statische Instanz der Klasse <SoaapMsg> +// Damit werden SOAAP-spezifische Meldungen/Telegramme generiert und ausgewertet +// und SOAAP-spezifische Datentypen und Parameter definiert. #ifdef DebugTerminal +// ---------------------------------------------------------------------------- +// Zum Debuggen und weitere Analysen der Programmumgebung und Funktionstests +// Es ist ein (richtiges) Terminal erforderlich, mit dem einzelnen Zeichen +// direkt abgeschickt und die eintreffenden direkt angezeigt werden. +// ---------------------------------------------------------------------------- #define smCycleTime 5 -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 @@ -82,27 +119,35 @@ StateMachine sm(smInit, NULL, smCycleTime); // die dann grundsätzlich vor dem Verzweigen in einen Zustand // aufgerufen wird. // <smCycleTime> Die Zukluszeit (Takt) der Zustandsmaschine in Millisekunden + +Monitor mon(modeEcho | modeNl,0,&lc); +// Eine statische Instanz (mit Konstruktordaten) der Klasse Monitor +// Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert +// Unter Linux werden hier GtkTerm (siehe Internet) und +// ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt. +// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeigent, +// weil damit keine direkte Kommunikation (getipptes Zeichen sofort gesendet) +// möglich ist. +// ----- Parameter ------------------------------------------------------------ +// <mode Echo> Alle eintreffenden Zeichen werden sofort zurückgesendet +// <mode NL> Vor der Ausgabe des Prompt (M>) erfolgt CR/LF +// <0> Für Speicherzugriffe wird von 32 Bit ARM ausgegangen +// <&lc> Für Zeitüberwachungen und entsprechende statisctische Daten +// greift die Monitor-Klasse auf die LoopCheck-Klasse zu +// ---------------------------------------------------------------------------- #endif -#define NrOfSlavesToPoll 5 -// Die Anzahl der Slaves, die der Master aufrufen soll (Polling). -// Es wird grundsätzlich mit der Adresse 1 begonnen und nach dem Aufruf die -// Adresse inkrementiert, also immer die Slaves Adr = 1 bis -// Adr = NrOfSlavesToPoll+1 aufgerufen. -// ACHTUNG! -// Diese Zahl muss kleiner/gleich der in BlePoll.h definierten maximalen -// Anzahl der Slaves (MAXSLAVE) sein, weil die Ressourcen darüber statisch -// festgelegt werden. // ============================================================================ void setup() +// ============================================================================ { bleCom.begin(); // Initialisierung der Datenübertragung //bleCom.setPower(0x08); // Maximale Sendeleistung bei nRF52840 // TEST bleCom.setPower(0x0FC); // Reduzierte Sendeleistung beim Schreibtisch-Test - blePoll.begin(BlePoll::ctMASTER, NrOfSlavesToPoll, BlePoll::atSOAAP, 10000); + blePoll.begin(BlePoll::ctMASTER, NrOfSlavesToPoll, BlePoll::atDevSOAAP, 10000); // Initialisierung des Polling mit folgenden Parametern: // <BlePoll::ctMASTER> Es wird ein Master eingerichtet // <NrOfSlavesToPoll> Anzahl gepollter Slaves (s.o.) @@ -125,14 +170,39 @@ void setup() // <1> Priorität beim Aufruf, 0 = immer bis max 65535 = sehr selten // <10> minimale Priorität bei automatischer Prioritätsreduzierung // im Fall von Störungen (Time-Out) - // <1500> Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden + // <1000> Time-Out (Zeit für Slave zum Antworten) in Mikrosekunden - // TEST +#ifdef DebugTerminal blePoll.stopEP(); // Das Polling muss extra gestartet werden +#endif + + // Initialisierung von serieller Schnittstelle und Ringpuffer + // -------------------------------------------------------------------------- + ttyParams.inst = 0; // Instanzindex der Schnittstelle (0,1) + ttyParams.rxdPort = 1; // Nummer des IO-Port mit RxD-Pin + ttyParams.rxdPin = 10; // Nummer des RxD-Pin am Port + ttyParams.txdPort = 1; // Nummer des IO-Port mit TxD-Pin + ttyParams.txdPin = 3; // Nummer des TxD-Pin am Port + ttyParams.speed = Baud115200; // Enumerator für Bitrate + ttyParams.type = stStd; // Spannungsausgang + + tty.begin(&ttyParams, (IntrfBuf *) &crb); + // Übergeben von Parametern und Referenz auf Ringpufferverwaltung + // für die Übergabe empfangener Zeichen + + tty.startSend(); // Sendebetrieb aktivieren + + crb.setWriteBuffer(sndBufSize, sndBuffer); + // Speicher an Ringpufferverwaltung übergeben + + crb.begin((IntrfSerial *) &tty); + // Referenz auf Schnittstelle an Ringpufferverwaltung + // für die Übergabe zu sendender Zeichen } // ============================================================================ void loop() +// ============================================================================ { lc.begin(); // Muss am Anfang von LOOP aufgerufen werden // -------------------------------------------------------------------------- @@ -141,7 +211,7 @@ void loop() mon.run(); // Der Monitor bekommt bei jedem Durchlauf die CPU #endif - // Alle 500 Mikrosekunden erfolgt der Aufruf des Ble-Polling + // Alle 250 Mikrosekunden erfolgt der Aufruf des Ble-Polling // if(lc.timerMicro(lcTimer0, bleCycleTime, 0)) blePoll.run(); @@ -152,34 +222,180 @@ void loop() // hier in Mikrosekunden (timerMicro) // <0> Anzahl der Wiederholungen, 0 = unbegrenzt + // Alle 500 Mikrosekunden erfolgt der Aufruf der Anwendung + // + if(lc.timerMicro(lcTimer1, appCycleTime, 0, 10000)) + ap.run(); + + #ifdef DebugTerminal // Jede Sekunde erfolgt die Ausgabe einer Versionsmeldung // das kann über c0 am Terminal abgeschaltet werden // - if(lc.timerMilli(lcTimer1, 1000, 0)) + if(lc.timerMilli(lcTimer2, 1000, 0)) { if(!mon.cFlag[0]) - mon.printcr((char *)"%@TestBleMaster (ttyACM0), Version 20211104"); + mon.printcr((char *)"%@TestBleMaster (ttyACM0), Version 20220303"); } // Die Zeichen %@ am Anfang steuern die Ausgabe bei AndroidMonTerm in ein // Textfeld (Label) statt auf das Terminal-Display // Alle 5 Millisekunden erfolgt der Aufruf der Zustandsmaschine // - if(lc.timerMilli(lcTimer2, smCycleTime, 0)) + if(lc.timerMilli(lcTimer3, smCycleTime, 0)) { sm.run(); } #endif - // -------------------------------------------------------------------------- lc.end(); // Muss vor dem Ende von LOOP aufgerufen werden } +// **************************************************************************** +// Z u s t a n d s m a s c h i n e S O A A P - A n w e n d u n g (ap) +// **************************************************************************** +// +byte apTmpByteArray[256]; // Zwischenspeicher für Zeichenfolgen +int apNrOfMeasBytes; // Anzahl der empfangenen Messwertbytes +byte apMeasByteArray[32]; // Zwischenspeicher für Messwerte +byte apSlaveList[NrOfSlavesToPoll]; // Merker für gepollte Slaves +int apNrOfSlaves; // Aktuelle Anzahl von Slaves +int curListIdx; // Aktueller Index für Slaveliste +int area; // Area des aktuellen Slave +int sMsgLen; // Länge einer SOAAP-Meldung +int slNr; // Slave-Nummer (Adresse) +int txNr; // Anzahl versendeter Zeichen + +SoaapApId sAppId; // Anwendungs-Id aus Sicht SOAAP +PlpType pAppId; // Anwendungs-Id aus Polling-Sicht + +#ifdef TEST001 +char testMsgBuf[256]; +#endif +// ---------------------------------------------------------------------------- +// Initialisierungen +// +void apInit() +{ +#ifdef TEST001 + crb.putLine("Initialisierung"); +#endif + + // Eventuelle Initialisierung + ap.enter(apWaitDE); // in nächsten Zustand schalten +} + +// ---------------------------------------------------------------------------- +// Warten, bis Datenaustausch Master/Slave erfolgt +// +void apWaitDE() +{ + if(!blePoll.DataExchange) + return; // Verbleiben in diesem Zustand bis Leerpolling beendet + + apNrOfSlaves = blePoll.getSlaveList(apSlaveList, NrOfSlavesToPoll); + // Ermitteln der angeschlossenen Slaves + +#ifdef TEST001 + crb.putStr("Slaveliste\r\n"); +#endif + + ap.enter(apWaitMeas); +} + +// ---------------------------------------------------------------------------- +// Warten auf neuen Messwert von einem Slave +// +void apWaitMeas() +{ + // Ermitteln, ob einer der Slaves einen Messwert hat + // + for(curListIdx = 0; curListIdx < apNrOfSlaves; curListIdx++) + { + slNr = apSlaveList[curListIdx]; + if(blePoll.measAvail(slNr)) break; + } + if(curListIdx == apNrOfSlaves) return; + // Wenn kein Slave neue Messwerte hat, + // dann im nächsten Zustandstakt Abfrage wiederholen + +#ifdef TEST001 + crb.putStr("Messwerte\r\n"); +#endif + + // Slave (curListIdx) hat Messwerte übermittelt + // diese werden mit dem nächsten Takt verarbeitet + ap.enter(apProcMeas); +} + +// ---------------------------------------------------------------------------- +// Verarbeiten der Daten vom Slave +// +void apProcMeas() +{ +#ifdef TEST001 + if(ap.firstEnter()) + { + slNr = apSlaveList[curListIdx]; + sprintf(testMsgBuf,"Slave-Nr = %d\r\n",slNr); + crb.putStr(testMsgBuf); + } + //ap.enter(apWaitMeas); + //return; +#endif + + // Parameter und Daten für die SOAAP-Meldung holen + // + slNr = apSlaveList[curListIdx]; + area = blePoll.getArea(slNr); + pAppId = blePoll.getAppId(slNr); + apNrOfMeasBytes = blePoll.getMeas(slNr, apMeasByteArray); + +#ifdef TEST001 + ap.enter(apWaitMeas); + return; +#endif + + // Abbildung des Polling-Telegramm-Typs auf die SOAAP-Anwendungs-Id + // + switch(pAppId) + { + case plptMeas9: + sAppId = saiDefaultMeas; + break; + + case plptMeas13: + sAppId = saiMaximalMeas; + break; + + case plptMeas9Ctrl4: + sAppId = saiDefaultMeasCtrl; + break; + + default: + sAppId = saiDefaultMeas; + break; + } + + // Konstruktion der SOAAP-Meldung + // + sMsgLen = sMsg.getMsgA(area, slNr, sAppId, (char *) apTmpByteArray, apMeasByteArray); + + // Senden des Telegramm über serielle Schnittstelle + // + txNr = crb.putStr((char *) apTmpByteArray); + + // Auf nächsten Messwert von einem Slave warten + // + ap.enter(apWaitMeas); +} + + + #ifdef DebugTerminal // **************************************************************************** -// Z u s t a n d s m a s c h i n e +// Z u s t a n d s m a s c h i n e z u m D e b u g g e n (sm) // **************************************************************************** // dword debDword; @@ -204,10 +420,8 @@ void smCheckJobs() sm.enter(smCtrlPolling); else if(mon.cFlag[3] && !mon.busy) sm.enter(smReadPollValues); - /* else if(mon.cFlag[4] && !mon.busy) - sm.enter(smCheckSens); - */ + sm.enter(smCheckSer); } // ---------------------------------------------------------------------------- @@ -260,6 +474,8 @@ void smCtrlPolling() short tmpShort; int i; + PlpMeas6Ptr resPtr; + if(sm.firstEnter()) { mon.print((char *) "polling "); @@ -372,15 +588,19 @@ void smCtrlPolling() } mon.print(tmpDw); mon.cprint(' '); + resPtr = (PlpMeas6Ptr) &slPtr->result; + mon.print(slPtr->cntLostPdu); mon.cprint('|'); mon.print(slPtr->cntErrCrc); mon.cprint('|'); - mon.print(slPtr->result.measCnt); mon.cprint('|'); + //mon.print(slPtr->result.measCnt); mon.cprint('|'); + mon.print(resPtr->measCnt); mon.cprint('|'); mon.print(slPtr->cntLostMeas); mon.cprint(' '); for(i = 0; i < 6; i++) { - tmpShort = (short) slPtr->result.meas[i]; - mon.prints(tmpShort); mon.cprint(' '); + //tmpShort = (short) slPtr->result.meas[i]; + tmpShort = (short) resPtr->meas[i]; + mon.prints(tmpShort); mon.cprint(' '); } mon.print((char *) " Poll["); mon.print(slPtr->pIdx); @@ -411,6 +631,34 @@ void smWaitPolling() sm.enter(smCtrlPolling); } +// ---------------------------------------------------------------------------- +// Testen der seriellen Schnittstelle +// ---------------------------------------------------------------------------- +// +void smCheckSer() +{ + if(sm.firstEnter()) + { + mon.print((char *) "TestSer..."); + mon.lastKeyIn = ':'; + } + + if(mon.lastKeyIn == ':') return; + + if(mon.lastKeyIn == ' ') + { + mon.cFlag[4] = false; + mon.print((char *) "-- Schleifenabbruch - drücke Enter"); + sm.enter(smCheckJobs); + } + else + { + crb.putChr(mon.lastKeyIn); + mon.cprint(mon.lastKeyIn); + mon.lastKeyIn = ':'; + } +} + // ---------------------------------------------------------------------------- // Debug-Informationen // ---------------------------------------------------------------------------- diff --git a/sketches/pollingBLE/SoaapBleSlave.ino b/sketches/pollingBLE/SoaapBleSlave.ino index fb39344e1156617a5215a4bccb9b1fe985f7a616..8f0b563905cd0ea7afce718f68728bca692991bc 100644 --- a/sketches/pollingBLE/SoaapBleSlave.ino +++ b/sketches/pollingBLE/SoaapBleSlave.ino @@ -13,28 +13,16 @@ // #include "Arduino.h" -#include "LoopCheck.h" -#include "StateMachine.h" +#include "SoaapBleSlave.h" -#include "nRF52840Twi.h" -#include "SensorLSM9DS1.h" - -#include "nRF52840Radio.h" -#include "BlePoll.h" -#include "Monitor.h" - -#define DebugTerminal -// Mit dieser Definition werden die Klasse Monitor und weitere Testmethoden -// eingebunden, womit ein anwendungsorientiertes Debugging möglich ist - -#ifdef SlaveACM1 +#ifdef SlaveADR1 #define SlaveADR 1 -#define StartMsg "%@TestBleSlave (Adr=1, ttyACM1), Version 20211108 " +#define StartMsg "%@TestBleSlave (Adr=1), Version 20220424 " #endif -#ifdef SlaveACM2 +#ifdef SlaveADR4 #define SlaveADR 4 -#define StartMsg "%@TestBleSlave (Adr=4, ttyACM2), Version 20211108 " +#define StartMsg "%@TestBleSlave (Adr=4), Version 20220424 " #endif LoopCheck lc; @@ -47,7 +35,7 @@ Monitor mon(modeEcho | modeNl,0,&lc); // Darüber wird mit (direkten) Terminals (z.B. VT100) kommuniziert // Unter Linux werden hier GtkTerm (siehe Internet) und // ArduinoMonTerm (eigene Entwicklung mit grafischen Wertanzeigen) eingesetzt. -// Das in den IDEs integrierte Terminal ist dafür meistens nicht geeigent, +// 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 ------------------------------------------------------------ @@ -63,7 +51,7 @@ nRF52840Radio bleCom; // Darüber wird direkt die CPU (nRF52840) auf dem Arduino-Board zum Senden und // Empfangen von BLE-Beacons angesprochen. -#define bleCycle 150 +#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 @@ -118,12 +106,21 @@ SensorLSM9DS1 sens((IntrfTw *) &twi, SensorCycle); // in Mikrosekunden definiert ist. Siehe dazu entsprechenden // Timeraufruf in LOOP. -bool getValues(PlpType plpType, byte *dest); // Vorwärtsreferenz für Datenübergabe +nRF52840Gpio gpio; +// Zugriff auf die Anschlüsse des Board + +bool getValues(PlpType plpType, byte *dest); +// Vorwärtsreferenz für Datenübergabe + +bool xchgCtrl(PlpType plpType, byte *dest, byte *src, int sSize); +// Vorwärtsreferenz für Steuerungsaustausch void setup() { TwiParams twiPar; // Parameter für den I2C-Bus + gpio.configArd(ArdA0A3, IfDrvInput | IfDrvPullUp); + #ifdef DebugTerminal mon.config(6); // 6 Anzeigekanäle, die von ArduinoMonTerm aufgebaut werden @@ -148,7 +145,11 @@ void setup() // <10000> INT-Watchdog-Timeout in Mikrosekunden blePoll.setCbDataPtr(getValues); - // Callback für Datenübergabe setzen + 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 // @@ -162,7 +163,7 @@ void setup() twi.begin(&twiPar); // Initialisierung des I2C-Bus - sens.begin(FreqAG119, 12, MaxAcc4g, MaxGyro2000dps, FreqM_OFF, 0, MaxMag4G); + sens.begin(FreqAG119, 12, MaxAcc4g, MaxGyro2000dps, FreqM20, 10, MaxMag16G); // Initialisierung der Sensorabfrage mit folgenden Parametern // // <FreqAG119> Beschleunigungssensoren und Gyroskop mit 119 Hz abgefragt @@ -174,13 +175,14 @@ void setup() // // <MaxGyro2000dps> Maximalausschlag des Gyro ist 2000 Grad/s // - // <FreqM_OFF> Der Magnetfeldsensor ist AUS (funktioniert noch nicht) + // <FreqM40> Der Magnetfeldsensor wird mit 20 Hz abgetastet // - // <0> Keine Mittelwertbildung der Magnetfeldmessung + // <8> Mittelwertbildung über 10 Messwerte, also 2 Hz // - // <MaxMag4G> Der Maximalwert entspricht 4 Gauss + // <MaxMag16G> Der Maximalwert entspricht 16 Gauss sens.syncValuesAG(); + sens.syncValuesM(); // Rücksetzen des Ready-Bit für Messwertübergabe } @@ -248,29 +250,71 @@ void loop() // Übergabe der Daten an die BLE-Kommunikation // ---------------------------------------------------------------------------- // -RawDataAG rawData; +RawDataAG rawDataAG; +RawDataM rawDataM; bool getValues(PlpType plpType, byte *dest) { bool newData; - int i; + int si,di; + + memset(rawDataAG.byteArray,0,12); - memset(rawData.byteArray,0,12); + newData = sens.getValuesAG(&rawDataAG); - newData = sens.getValuesAG(&rawData); + si = di = 0; if(newData) { switch(plpType) { case plptMeas6: - for(i = 0; i < 12; i++) - dest[i] = rawData.byteArray[i]; + for(si = 0; si < 12; si++) + dest[di++] = rawDataAG.byteArray[si]; + break; + + case plptMeas9Ctrl4: + sens.getValuesM(&rawDataM); + + for(si = 0; si < 12; si++) + dest[di++] = rawDataAG.byteArray[si]; + for(si = 0; si < 6; si++) + dest[di++] = rawDataM.byteArray[si]; break; } } return(newData); } +int procSize; +byte procData[32]; +byte procPath; +byte procCnt; + + +bool xchgCtrl(PlpType plpType, byte *dest, byte *src, int sSize) +{ + int si,di; + bool retv; + + si = di = 0; + retv = false; + + switch(plpType) + { + case plptMeas9Ctrl4: + for(si = 0; si < sSize; si++) + procData[si] = src[si]; + procSize = sSize; + dest[di++] = procPath; + dest[di++] = procCnt; + dest[di++] = (byte) (gpio.readArd(ArdA0A3) & 0x0F); + dest[di++] = 0; + retv = true; + break; + } + + return(retv); +} #ifdef DebugTerminal // **************************************************************************** @@ -520,14 +564,14 @@ void smSensGetValues1() if(sm.firstEnter()) sens.syncValuesAG(); - if(!sens.getValuesAG(&rawData)) return; + if(!sens.getValuesAG(&rawDataAG)) return; mon.print((char *) "ValueA = "); - mon.print(rawData.valueAG.A.x); + mon.print(rawDataAG.valueAG.A.x); mon.print((char *) " "); - mon.print(rawData.valueAG.A.y); + mon.print(rawDataAG.valueAG.A.y); mon.print((char *) " "); - mon.println(rawData.valueAG.A.z); + mon.println(rawDataAG.valueAG.A.z); sm.enter(smCheckSens); } @@ -666,23 +710,23 @@ void smSensGetValues6() return; } - if(!sens.getValuesAG(&rawData)) return; + if(!sens.getValuesAG(&rawDataAG)) return; sm.setTimeOut(1000); mon.print((char *) "Values AGM = "); - sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.A.x); + sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.A.x); mon.print(outValue); - sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.A.y); + sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.A.y); mon.print(outValue); - sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.A.z); + sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.A.z); mon.print(outValue); - sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.G.x); + sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.G.x); mon.print(outValue); - sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.G.y); + sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.G.y); mon.print(outValue); - sprintf(outValue,"%4X ",(unsigned short) rawData.valueAG.G.z); + sprintf(outValue,"%4X ",(unsigned short) rawDataAG.valueAG.G.z); mon.println(outValue); /* @@ -716,23 +760,23 @@ void smSensGetValues7() return; } - if(!sens.getValuesAG(&rawData)) return; + if(!sens.getValuesAG(&rawDataAG)) return; sm.setTimeOut(1000); mon.print((char *) "%~Values AGM = $"); - sprintf(outValue,"#@%04X$",(unsigned short) rawData.valueAG.A.x); + sprintf(outValue,"#@%04X$",(unsigned short) rawDataAG.valueAG.A.x); mon.print(outValue); - sprintf(outValue,"#A%04X$",(unsigned short) rawData.valueAG.A.y); + sprintf(outValue,"#A%04X$",(unsigned short) rawDataAG.valueAG.A.y); mon.print(outValue); - sprintf(outValue,"#B%04X$",(unsigned short) rawData.valueAG.A.z); + sprintf(outValue,"#B%04X$",(unsigned short) rawDataAG.valueAG.A.z); mon.print(outValue); - sprintf(outValue,"#C%04X$",(unsigned short) rawData.valueAG.G.x); + sprintf(outValue,"#C%04X$",(unsigned short) rawDataAG.valueAG.G.x); mon.print(outValue); - sprintf(outValue,"#D%04X$",(unsigned short) rawData.valueAG.G.y); + sprintf(outValue,"#D%04X$",(unsigned short) rawDataAG.valueAG.G.y); mon.print(outValue); - sprintf(outValue,"#E%04X$",(unsigned short) rawData.valueAG.G.z); + sprintf(outValue,"#E%04X$",(unsigned short) rawDataAG.valueAG.G.z); mon.print(outValue); if(mon.lastKeyIn == ' ')