Page 2 of 2

Re: Gui und Eingänge lesen in Python

Posted: 04 May 2017, 10:15
by Tommy
Hallo Volker,
vielen Dank für dein Code Beispiel. Ich habe leider nur noch ein Problem. Ich hoffe du hast dafür auch eine Idee.
Ich zeige dir mal eben ein kleines Code Beispiel, das zeigt es wohl am besten:

Code: Select all


import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.uic import*

import threading
from time import sleep

#dein Code Beispiel
Inputs = 0       # this is 2 bytes (INT) or any other type of data which holds the input states of the DIO
Outputs = 0    # this is 2 bytes (INT) or any other type of data which holds the output states of the DIO

def IO_Thread():
   global Inputs
   global Outputs
       #init this thread 
   
   # opening piControl interface
   f=open("/dev/piControl0","wb+",0)
   print("driver successfully opened!")

   while 1:
      #poll DIO inputs
      f.seek(InputOffsetDIO1) # do replace the "InputOffsetDIO1" with the offset in your configuration!
      x=f.read(2)
      Inputs = x[0] + 256 * x[1] # works only in python 3. For python 2 you will need to use struct library to get numbers out of the byte array
      
      #set DIO outputs
      f.seek(OutputOffsetDIO1) # do replace the "OutputOffsetDIO1" with the offset in your configuration!
      x=(Outputs).to_bytes(2, 'little') # this works only with python 3. Process image is organized in little Endian!
      f.write(x)
      
      sleep(0.1) # do not loop with maximum velocity in order to give the system a chance to do other stuff...
      
thread2 = threading.Thread.Thread(target=IO_Thread)
thread2.start()

app = QApplication(sys.argv)
from = loadUi("MeineGUI")
from.show()
sys.exit(app.exec_())
Ich denke, dies wären wohl die minimalen nötigen Eingaben um eine GUI mit einem Thread zum Pollen der Ein und Ausgänge zu kombinieren.
Ich verstehe es so, dass ich den Thread für die RevPi Signale starte. Dann baue ich mir eine Applikation, lade meine GUI und den Rest des Programms wird in der app.exec_() Funktion verweilt.
Doch wie kriege ich jetzt meine Signale und Auswertungen in der app.exec_() Funktion ausgeführt?
In "MeineGui" steckt ja nur meine classe zum Bau des Aussehens meiner Oberfläche.
Ich kann jetzt hier noch Signale definieren damit ich bei einem Knopfdruck in eine Funktion komme, aber dass ist ja was anderes.
Ich weiss jetzt nicht genau, wie ich mit den GLOBALEN Variablen meine nötigen Funktionen auslösen kann, da ich ja hauptsächlich in app.exec_() stecke.
Hast du da vielleicht noch eine Idee?

Re: Gui und Eingänge lesen in Python

Posted: 04 May 2017, 11:51
by RevPiModIO
Hi Tommy!

Wenn du dich selber um das Prozessabbild kümmerst, musst du selber auch die Wertänderungen überwachen und dementsprechend darauf reagieren, z.B. wenn du die Werte abrufst in der while 1: Schleife... Je nach Wert musst du dann auswerten, welcher Input gesetzt ist und eine Funktion aufrufen.

Ich habe deine Anmerkung mit dem blockierenden mainloop aber auch mal aufgegriffen. Das RevPiModIO-Modul habe ich dementsprechend erweitert, dass man den mainloop auch "nicht blockierend" aufrufen kann. Dann würde der Quellcode so aussehen, wobei die "eventfunktion" immer aufgerufen wird, wenn der Input "I_1" auf True geht (edge=revpimodio.RISING). Und alles was in der "eventfunktion" steht wird dann ausgeführt (Threadsicherheit inkl.).

Code: Select all

#!/usr/bin/python3
import revpimodio
import time

# RevPiModIO Instantieren und Module in den auto_refresh setzen
revpi = revpimodio.RevPiModIO(auto_refresh=True)


def eventfunktion(ioname, iovalue):
    """Wird nur ausgefuehrt, wenn ein Input Pin den Status aendert.
    @param ioname: Wird automatisch uebergeben und enthaelt den IO-Namen
    @param iovlaue: Wert, den der IO zum ausloesezeitpunkt hat"""
    
    # Hier arbeitest du mit deinem Gerät am COM und fragst Daten ab
    
    # oder schreibst einfach nur etwas in die Console :D
    print(time.time(), ioname, iovalue)


# Auf einen Input eine Funktion anmelden, welche ausgeführt werden soll
revpi.devices[32].reg_event("I_1", eventfunktion, edge=revpimodio.RISING)

# Eventüberwachung starten ohne zu blockieren!
revpi.devices.mainloop(blocking=False)
print("mainloop() gestartet, ohne zu blockieren")

while True:
    print("Hier ist die GUI, welche Werte abfragt oder setzt: Input:",
        revpi.devices[32]["I_1"].value)
    time.sleep(2)
Die Namen der Inputs kommen direkt aus piCtory, so wie du sie da angibst kannst du sie dann in Python verwenden - In meinem Fall "I_1" für den ersten Input vom DIO an Position 32 (steht auch in piCtory oben).
Vorteil ist eben mit den Namen, dass man sich nicht um die Offsets und Datenumwandlungen kümmern muss, das erledigt das Modul. Auch wenn du in piCtory etwas änderst - solange die Namen gleich bleiben ist keine Änderung im Quellcode nötig... (statt Positionsnummern kann man für Devices auch deren piCtory-Namen verwenden "dio01" z.B.)

Über das globale Objekt "revpi" hast du dann Zugriff auf alle Werte von den IO-Modulen.

Der nicht blockierende mainloop Funktioniert ab Version 0.9.6 welche ich eben hochgeladen habe https://revpimodio.org/quellen/

Gruß, Sven

Re: Gui und Eingänge lesen in Python

Posted: 04 May 2017, 13:14
by volker
jetzt wird es kompliziert, weil ich a) nicht weiß, auf welchem level Du software selber umsetzten willst und b) ich selber nicht mit QT arbeite und daher die Details nicht kenne.

Ich gehe aber mal davon aus, dass Du ganz prinzipiell auch in QT die Möglichkeit hast, auf globale Variablen zuzugreifen (die müssten dann in der QT-Task als "global" definiert werden, so wie bei meiner IO-task zu sehen). Dann hättest du die Möglichkeit, dort eben mit der Variablen Input deine Prozesse auszulösen. lege dazu in der GUI ein Timerelement an, welches Du alle 100 ms aufrufst. Dort genau könntest du dann zyklisch die Variable Inputs mit einer 2^bit Maske maskieren und auf >0 abfagen, wenn zum Beispiel an einem DIO Eingang ein Taster 24V anlegt um deine serielle Kommunikation zu starten, ganz analog zu wie es das Klicken auf eine Schaltfläche der GUI macht.

Re: Gui und Eingänge lesen in Python

Posted: 04 May 2017, 13:26
by Tommy
Hallo Sven,
erstmal danke für dein Beispiel. An meinem Code-Beispiel von oben habe ich das Problem, dass das Programm in die Routine sys.exit(app.exec_()) reinläuft und dann dort verweilt. Würde ich zum Beispiel in meinem Hauptprogramm ein while benutzen und dann die Routine sys.exit(app.exec_()) durchführen, würde das ja nichts ändern, weil er aus der sys..... Routine ja nicht mehr rauskommt. Oder verstehe ich es falsch?
Ist es vielleicht so gemeint, dass ich in dem Thread wo gepollt wird, eine Funktion einfüge die zum Beispiel nur durchläuft wird wenn die gewollten Eingänge gesetzt sind. Und dort führe ich dann die Funktion aus, die zum Beispiel meinen Transponder Programmiervorgang durchführt.
Gruß Tommy

Re: Gui und Eingänge lesen in Python

Posted: 04 May 2017, 14:06
by Tommy
Hallo Volker,
kann ich nicht einfach in dem thread über die Eingänge Pollen und wenn der gewollte Zustand eintrifft, führe ich die dazugehörige Funktion durch. Ich werte dazu einfach die Inputs aus. Ich bräuchte doch dazu noch nicht mals globale variable.
Wenn zum Beispiel das Startsignal am RevPi high ist, wird die Funktion programmiere Transponder ausgeführt. Oder übersehe ich da was?
Gruß Tommy

Re: Gui und Eingänge lesen in Python

Posted: 04 May 2017, 15:07
by Tommy
Hallo Volker,
also ich glaub ich weiss jetzt so langsam was du meinst. Nachrichten, von einem thread zu einem anderen scheinen nicht zu funktionieren. Qt erlaubt keine events in unterschiedlichen threads.

Re: Gui und Eingänge lesen in Python

Posted: 04 May 2017, 15:22
by Tommy
Irgendwie auch logisch. Sind ja zwei verschiedene parallel laufende unabhängige Prozesse. Versuche dann mal dein Vorschlag mit dem Timerelement.
Vielen Dank für die Info

Re: Gui und Eingänge lesen in Python

Posted: 04 May 2017, 16:23
by Tommy
Hallo Volker,
dein Vorschlag scheint zu funktionieren. Vielen Dank.
Grüße Tommy

Re: Gui und Eingänge lesen in Python

Posted: 04 May 2017, 19:02
by volker
Super!
Natürlich könntest Du auch die Aktionen in den pollenden thread rein tun. Aber dann hast Du den Code eben doppelt - einmal in der GUI bei Schaltflächen (on click event) und dann zusätzlich in dem Io thread.