Funktion beenden

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist doch grosser Quatsch. Wieso soll denn irgendwie ein Task aus dem NEC_16 werden? Das hast du doch vorher auch nicht gemacht. Ein simples

Code: Alles auswählen

ir = NEC_16 (Pin(16, Pin.IN), lambda val, addr, ext : callback(command_queue, val, addr, ext))
sollte reichen. Achtung, da ist ein ext drin, weil das der callback wohl braucht. Das habe ich uebersehen, aber hatte dein callback ja auch schon.. ein bisschen mitdenken ist schon erwuenscht.

Laut Code sollte aber auch das hier klappen:

Code: Alles auswählen

ir = NEC_16 (Pin(16, Pin.IN), callback, callback_queue)
weil zusaetzliche Argumente einfach weitergeleitet werden. Dann muss die Signatur des Callbacks so aussehen:

Code: Alles auswählen

def callback(val, addr, ext, queue):
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ich habe jetzt das ganze nochmal ausführlich getestet. In der Callback-Funktion ist immer der 1. Parameter data, also die daten, der 2. ist die adresse und der 3. ist ctl (was auch immer das ist) queue ist dann als 4. parameter (durch print getestet).

Dann bin ich nochmal das Beispiel von __deets__ (2. Seite ganz oben) durchgegangen, das zeigte mir, das was dort in der Funktion callback bei dem code 'uasyncio.create_task(queue.put(val))' als Parameter bei 'queue.put' stehen kann was will, denn das kann man in der Funktion dispatcher per 'await queue.get()' ausgeben lassen, bzw wird übermittelt.

Soweit so gut, alles verstanden. Nur genau das macht es in meinen Code nicht. Habe das nochmal geändert wie vorgeschlagen (vielen dank dafür), aber wenn ich das Programm starte, wird startet bei der Funktion dispatcher die while-Schleife nicht.

Hier nochmal der Code, ich denke mal es liegt an der Callback Methode.
Das Objekt queue wird aber am Anfang der Methode dispatcher als print ausgegeben

Code: Alles auswählen

<Queue object at 2000b910>
, also sollte das Prinzip ja funktionieren. Nur die while-Schleife im dispatcher startet nicht.

Code: Alles auswählen

def callback(data, addr, ctl,queue):
    if data > 0:  # NEC protocol sends repeat codes.
        print('Data {:05x} Addr {:04x}'.format(data, addr))
        uasyncio.create_task(queue.put(data))
    
async def dispatcher(queue):
    print(queue)
    task = None
    while True:
        command = await queue.get()
        print(command)
        print("dispatcher")
   
async def main():
    command_queue = Queue()
    ir = NEC_16 (Pin(16, Pin.IN), callback, command_queue)
    await dispatcher(command_queue)
    
if __name__ == '__main__':
    uasyncio.run(main())
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Kann ich erstmal nach Studium des NEC_16 Codes so nicht erklaeren - meines Erachtens laeuft das alles nur in IRQs und Timern (die denke ich auch IRQs sind), und sollte dann *eigentlich* problemlos gehen. Die while-Schleife startet auch, das Problem ist eher, dass das queue.put nie durchgefuehrt wird, bzw. nicht die gewuenschten Ergebnisse hat. Denn ich vermute mal das print("Data...") findet statt?

Es kann sein, dass die IRQ/Timer Funktionalitaet da doch irgendwas komisches machen. Ggf. hilft im callback

https://docs.micropython.org/en/latest/ ... n.schedule

einzusetzen, um dadurch dann die Daten in die Queue zu packen via create_task. Also so in etwa:

Code: Alles auswählen

def callback(data, addr, ctl,queue):
    if data > 0:  # NEC protocol sends repeat codes.
        print('Data {:05x} Addr {:04x}'.format(data, addr))
        micropython.schedule(lambda: uasyncio.create_task(queue.put(data)))
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Ja genau, print("Data...") findet statt.

Was mir als Fehler auf die Füße fällt ist, dass mir angezeigt wird, das micropython.schedule 2 Argumente erwartet wird, aber nur 1 gegeben ist.
Laut der Dokumentation sollte aber 1 Argument reichen 'micropython.schedule(func, arg)'.

Jetzt habe ich mal nach dem lambda-Argument einfach ein String angehängt, da wären wieder 3 Argumente gegeben, aber nur 2 würden akzeptiert werden.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann muss das lambda einfach ein Argument bekommen, das du ja auch ignorieren kannst.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

auch mir Argument(en) ist laut Ausgabe nur 1 gegeben.
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Das Problem dürfte sein, dass `schedule()` *zwei* Argumente will, eine Funktion und ein Argument, und hier egal ob nun mit ``lambda`` oder nicht, nur *eins* übergeben wird, nämlich der Rückgabewert der Funktion die mit dem Argument aufgerufen wurde — statt dort beides zu übergeben, statt die Funktion schon aufzurufen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ah. Klar. Beides natürlich. Ein dummy Argument beim Aufruf, und im lambda muss das angegeben werden, aber kann ignoriert werden.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Das ganze habe ich in

Code: Alles auswählen

 micropython.schedule(lambda x:uasyncio.create_task(queue.put(data)),"y")
geändert.
Es läuft ohne Fehler durch, nur die while-Schleife im dispatcher will nicht starten.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann ist da erstmal das Ende meiner Fahnenstange erreicht. Um das tiefgreifender zu analysieren, müsste ich das selbst auf einem Micro laufen lassen, und ggf. alles auf uasyncio umschreiben. Ob und wann ich dazu komme, kann ich nicht sagen.

Eine Alternative, die aber nicht wirklich deiner Forderung nach einem Task zum abbrechen entspricht , sondern ein ganz anderes Vorgehen bedeutet: Bau einen superloop, der mittels verschiedener Zustandsmaschinen die Aufgabe erledigt. Das ist allerdings eher ätzend, uasyncio ist eigentlich genau das, was man da will. Aber wenn es nicht tut…
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

OK trotzdem vielen dank für die Hilfe.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Oder kann man das auch noch anders lösen?

Ziel ist: Beim Tastendruck der IR- Fernbedienung soll eine bestimmte Funktion ausgeführt werden, darunter sollen auch Funktionen sein, die eine "while True" Schleife haben (z.b. unendliche Laufleiste der Led's).

Meine nächste Überlegung wäre, in der "while True" -Schleife ein Wert zu überprüfen ob eine Taste gedrückt wurde.
Nur leider fällt mir nichts dazu ein wie und ob überhaupt man das realisieren kann.
Hat dazu jemand noch ein Tipp für mich?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Alternative habe ich ja skizziert. Um es ganz klar zu sagen: while True in den Funktionen geht nicht. Das Modell funktioniert nur mit Tasks, weil die cancelbar sind. Eine Hauptschleife mit Zustandsmaschine hingegen geht. Schrieb ich ja schon.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Wie meinst du das mit einer Hauptschleife mit Zustandsmaschine?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Eine Schleife & abhängig vom Zustand in verschiedene Funktionen springen, die aber natürlich schnell wiederkehren müssen. Ein verwandtes Stichwort ist superloop. Kannst du mal suchen.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist ja am Ende nur algebraisch umgeformt, sozusagen:

Code: Alles auswählen

def eins():
    while True:
        print("eins")
        sleep(0.5)
    
def zwei():
    while True:
        print("zwei")
        sleep(0.5)
Das war dein Code. Daraus wird (in Naeherung, und ungetestet)

Code: Alles auswählen

def eins():
    print("eins")
    
def zwei():
    print("zwei")

def hauptschleife():
     while True:
         modus = pruefe_ir_eingabe()
         if modus == 1:
              eins()
         elif modus == 2:
              zwei()
Du kannst pro Programm (ohne Scheduler wie asyncio oder threading) halt nur eine Hauptschleife haben.
Benutzeravatar
Kebap
User
Beiträge: 687
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Sieht ja so ähnlich aus wie mein Ansatz oben..
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Voellig richtig, aber es ist ja auch nur die Notloesung. Man will einen solchen Scheduler eigentlich nicht selbst schreiben.
egon11
User
Beiträge: 354
Registriert: Mittwoch 14. Dezember 2016, 20:59

Irgenwie ist das mit der Callback-Funktion alles triggi. Wenn ich darin eine While-True Schleife ausführen lasse um auf bestimmte Dinge zu reagieren dann läuft sie nicht weiter...
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Im callback darf man das *niemals* machen. Du darfst im callback nur die Information ueber den geaenderten Modus oder Werte an eine staendig laufende Hauptschleife schicken.
Antworten