Auswertung von ankommenden Daten

Hallo Leute,

hier mal der relevante Skriptausschnitt, der mir ein wenig Kopfzerbrechen bereitet im Ganzen:

elseif (($MessageLen / 12) == intval($MessageLen / 12)) {
	    		// wenn es sich um mehrere Notifikationen handelt
	    		$DataArray = str_split($Message, 12);
	    		//IPS_LogMessage("IPS2GPIO ReceiveData", "Überlänge: ".Count($DataArray)." Notify-Datensätze");
	    		$PinNotify = unserialize(GetValueString($this->GetIDForIdent("PinNotify")));
	    		for ($i = 0; $i < min(5, Count($DataArray)); $i++) {
				$MessageParts = unpack("L*", $DataArray[$i]);
				for ($j = 0; $j < Count($PinNotify); $j++) {
	    				$Bitvalue = boolval($MessageParts[3]&(1<<$PinNotify[$j]));
	    				If ($this->ReadPropertyBoolean("Serial_Used") == false) {
	    					// Serieller Port ist deaktiviert
	    					IPS_LogMessage("IPS2GPIO Notify: ","Pin ".$PinNotify[$j]." Value ->".$Bitvalue);
	    					$this->SendDataToChildren(json_encode(Array("DataID" => "{8D44CA24-3B35-4918-9CBD-85A28C0C8917}", "Function"=>"notify", "Pin" => $PinNotify[$j], "Value"=> $Bitvalue, "Timestamp"=> $MessageArray[2])));
	    				}
	    				else {
	    					If ($PinNotify[$j] <> 15) {
	    						// alle Pins außer dem RxD werden normal verarbeitet
	    						IPS_LogMessage("IPS2GPIO Notify: ","Pin ".$PinNotify[$j]." Value ->".$Bitvalue);
	    						$this->SendDataToChildren(json_encode(Array("DataID" => "{8D44CA24-3B35-4918-9CBD-85A28C0C8917}", "Function"=>"notify", "Pin" => $PinNotify[$j], "Value"=> $Bitvalue, "Timestamp"=> $MessageArray[2])));
	    					}
	    					elseif (($PinNotify[$j] == 15) AND ($i < 2)) {
	    						If ($this->GetBuffer("SerialNotify") <> $Bitvalue) {
		    						// Einlesen der Seriellen Daten veranlassen
		    						IPS_LogMessage("IPS2GPIO Notify: ","Pin ".$PinNotify[$j]." Value ->".$Bitvalue);
		    						//IPS_LogMessage("IPS2GPIO Check Bytes Serial", "Handle: ".GetValueInteger($this->GetIDForIdent("Serial_Handle")));
			   					IPS_Sleep(75);
			   					$this->CommandClientSocket(pack("L*", 82, GetValueInteger($this->GetIDForIdent("Serial_Handle")), 0, 0), 16);
			   				 	$this->SetBuffer("SerialNotify", $Bitvalue);	
	    						}
	    					}
	    				}
				}
			}
		}

Das erschlägt einen wahrscheinlich erst einmal…:smiley:

Was soll dort eigentlich passieren:
Zunächst einmal kommen dort Daten herein (immer zwölf Zeichen-Länge), die den Zustand der Raspberry Pi GPIO melden. Dieses passiert jede Minute einmal quasi als „KeepAlive“-Signal, aber auch sofort wenn sich eine Zustand ändert (Notification).

Da die angeschlossenen Taster doch sehr stark prellen, kann es durchaus sein, dass in einem Schwung mehr als ein Datensatz kommt.
Das ist quasi dieser Teil:

for ($i = 0; $i < min(5, Count($DataArray)); $i++) {
				$MessageParts = unpack("L*", $DataArray[$i]);
				for ($j = 0; $j < Count($PinNotify); $j++) {
	    				$Bitvalue = boolval($MessageParts[3]&(1<<$PinNotify[$j]));
	    				If ($this->ReadPropertyBoolean("Serial_Used") == false) {
	    					// Serieller Port ist deaktiviert
	    					IPS_LogMessage("IPS2GPIO Notify: ","Pin ".$PinNotify[$j]." Value ->".$Bitvalue);
	    					$this->SendDataToChildren(json_encode(Array("DataID" => "{8D44CA24-3B35-4918-9CBD-85A28C0C8917}", "Function"=>"notify", "Pin" => $PinNotify[$j], "Value"=> $Bitvalue, "Timestamp"=> $MessageArray[2])));
	    				}

Die Zählschleife habe ich aus Sicherheitsgründen schon auf fünf Zyklen begrenzt (falls all zu viele Prellvorgänge). Die ankommenden Daten werden dann auf eine Änderung an den Pins geprüft, welche für mich interessant sind und zur weiteren Verarbeitung weitergeleitet.

Eine besondere Situation tritt jedoch ein, wenn der serielle Port (GPIO 15) als Rx/Tx genutzt wird. Ich bekomme so keine Information, ob Daten aus dem seriellen Gerät gekommen sind, so dass ich auch diese Funktion genutzt habe, um eine Notification zu erhalten. Jedoch kann man sich vorstellen, dass dieses zu extrem vielen Pegelwechseln an GPIO 15 führen kann.

	    				else {
	    					If ($PinNotify[$j] <> 15) {
	    						// alle Pins außer dem RxD werden normal verarbeitet
	    						IPS_LogMessage("IPS2GPIO Notify: ","Pin ".$PinNotify[$j]." Value ->".$Bitvalue);
	    						$this->SendDataToChildren(json_encode(Array("DataID" => "{8D44CA24-3B35-4918-9CBD-85A28C0C8917}", "Function"=>"notify", "Pin" => $PinNotify[$j], "Value"=> $Bitvalue, "Timestamp"=> $MessageArray[2])));
	    					}
	    					elseif (($PinNotify[$j] == 15) AND ($i < 2)) {
	    						If ($this->GetBuffer("SerialNotify") <> $Bitvalue) {
		    						// Einlesen der Seriellen Daten veranlassen
		    						IPS_LogMessage("IPS2GPIO Notify: ","Pin ".$PinNotify[$j]." Value ->".$Bitvalue);
		    						//IPS_LogMessage("IPS2GPIO Check Bytes Serial", "Handle: ".GetValueInteger($this->GetIDForIdent("Serial_Handle")));
			   					IPS_Sleep(75);
			   					$this->CommandClientSocket(pack("L*", 82, GetValueInteger($this->GetIDForIdent("Serial_Handle")), 0, 0), 16);
			   				 	$this->SetBuffer("SerialNotify", $Bitvalue);	
	    						}

Erfolgt eine Aktivität auf GPIO 15 werden im Nachgang die eingetroffenen Daten abgerufen und verarbeitet.

Insgesamt scheint mir dieses Konstrukt sehr fragwürdig, obwohl es so in der Regel funktioniert.

Das Prellen wird softwareseitig reduziert, d.h. eine Weiterleitung erfolgt erst, wenn der Zustand x ms stabil ist).

Ich poste Euch das mal in der Hoffnung, dass mir jemand vielleicht einen Weg zeigen kann, wie ich diesen „gewachsenen“ Code vielleicht deutlich einfacher und „sicherer“ erstellen kann.

Ich versuche noch mal eine Zusammenfassung:

  • 12 Zeichen-Ketten kommen zyklisch (ohne eine Änderung) oder aufgrund einer Änderung als Trigger herein (eine Unterscheidung ist nicht möglich)
  • die „markierten“ GPIO werden herausgesucht und der Zustand weitergeleitet
  • bei Nutzung der seriellen Schnittstelle kann ich nur durch Aktivität am GPIO 15 feststellen das Daten eingetroffen sind (nicht die Daten selbst) und diese dann „abholen“

„Theoretische“ Annahme:

  • Tritt eine Zustandsänderung am GPIO ein, dann müsste der erste Trigger ja eigentlich das „korrekte“ Ergebnis sein (weil der Taster ja offenbar seinen Zustand geändert hat, jedes weitere Prellen ist eigentlich irrelevant)
  • das Abholen der Daten für seriellen Daten sollte eigentlich erst erfolgen, wenn die Aktivitäten auf GPIO 15 „vorbei“ sind (die Datensendung ist dann offensichtlich zunächst einmal beendet)

Vielleicht hat ja jemand schon einmal so eine ähnliche Aufgabenstellung gehabt…

Joachim