efinf:blcks2017:tetristable:python

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
efinf:blcks2017:tetristable:python [2018/01/05 14:52] – created Ivo Blöchligerefinf:blcks2017:tetristable:python [2018/05/22 11:23] (current) – [Wifi: Verbund von Tischen] Ivo Blöchliger
Line 1: Line 1:
 +===== Emulation und Driver (Helper) =====
 +{{ :efinf:blcks2017:tetristable:tigerjython.zip |nur Dateien vom tigerjython Ordner, neu mit Joystick-Emulation}}
 +
 +{{ :efinf:blcks2017:tetristable:helper.py |helper.py für den ESP32 (neu mit Joystick-Unterstützung)}}, Drähte von Eingängen D32 und D25 vertauschen, siehe [[efinf:blcks2017:tetristable:bauanleitung#verdrahtung|Verdrahtung]].
 +
 +{{ :efinf:blcks2017:tetristable:mcp.py |mcp.py}} für den ESP32.
 +
 +Verwenden Sie dieses Archiv für ein Update (die Datei helper.py unterhalb des tigerjython Verzeichnisses soll nicht überschrieben werden).
 +
 +<hidden Alte Version>
 +  * {{ :efinf:blcks2017:tetristable:tetris-table.zip |Zip-Archiv mit Demo (Lauffähig auch in TigerJython)}}
 + 
 +Die Datei ''helper.py'' unterhalb des tigerjython Verzeichnisses muss eventuell angepasst werden für den eigenen Tisch.
 +
 +Alle Zugriffe auf die Hardware müssen über die Helper-Klasse erfolgen. So sind die Programme auf allen Tischen lauffähig. Eigene Programme werden idealerweise wie die Demos erstellt. So sind diese sehr einfach auszutauschen und einzubauen.
 +</hidden>
 +
 +===== Wifi: Verbund von Tischen =====
 +Hier mal ein POC (Proof of concept). Die Benutzung ist wie folgt:
 +
 +  - Server starten
 +  - Clients starten
 +  - Beim Server einen der unteren Knöpfe drücken (-> warten auf eingehenden Verbindung).
 +  - Beim ersten client einen der unteren Knöpfe drücke (-> Verbindung mit Server)
 +  - Die letzten zwei Schritte für alle clients wiederholen
 +  - Beim Server einen der oberen Knöpfe drücken (-> Demo startet).
 +==== Client ====
 +<hidden Source code>
 +<code python wificlient.rb>
 +
 +import network
 +
 +import time
 +import usocket as socket
 +
 +# Hack to get ticks_ms() method in Tigerjython working
 +if not hasattr(time, 'ticks_ms'):
 +    from types import MethodType
 +    def ticks_ms(self):
 +        return int(round(self.time() * 1000))
 +    time.ticks_ms = MethodType(ticks_ms, time)
 +    
 +    def sleep_ms(self,a):
 +        time.sleep(a/1000.0)
 +    time.sleep_ms = MethodType(sleep_ms, time)
 +# END of Hack
 +
 +class WifiClient:
 +
 +    def __init__(self,helper):
 +        self.helper = helper
 +
 +    def setup(self):
 +        self.wlan = network.WLAN(network.STA_IF)
 +        self.wlan.active(True)
 +        self.wlan.connect('esp32')
 +        
 +        while not self.wlan.isconnected():
 +            print(self.wlan.status())
 +            time.sleep_ms(1000) # 1 second sleep
 +        print("WLAN ok")
 +            
 +    def connect(self):                    
 +        self.addr = socket.getaddrinfo('10.42.42.1', 80)[0][-1]
 +        self.sk = socket.socket()
 +        self.sk.connect(self.addr)
 +        print("Connected to server")
 +
 +    def update(self):
 +        bytesread = 0
 +        buf = b''
 +        while bytesread<450:
 +            chunk = self.sk.recv(450)
 +            buf+=chunk
 +            bytesread+=len(chunk)
 +        if bytesread==450 and self.helper:
 +            for y in range(15):
 +                for x in range(10):
 +                    p = 3*(y*10+x)
 +                    self.helper.setPixel(x,y,(buf[p], buf[p+1], buf[p+2]))
 +            self.helper.np.write()
 +            #print("Updated")
 +
 +
 +    def sendButtons(self):
 +        if self.helper:
 +            btns = bytearray([self.helper.getButtons()])
 +            self.sk.send(btns)
 +            
 +
 +    def play(self):
 +        self.setup()        
 +        if self.helper:
 +            while self.helper.getButtons()!=255:
 +                pass
 +            while self.helper.getButtons()==255:
 +                pass
 +        self.connect()
 +        while True:
 +            self.update()
 +
 +# Start with    execfile("wificlient.py")
 +
 +if __name__=="__main__":
 +    from helper import Helper  # Import der Klasse
 +    helper = Helper()   # Erzeugen der Instanz
 +#    helper = None
 +    c = WifiClient(helper)
 +    c.play()
 +    
 +
 +</code>
 +</hidden>
 +==== Server ====
 +<hidden Source code>
 +<code python wifiserver.rb>
 +# See https://docs.micropython.org/en/latest/esp8266/library/network.html
 +
 +import network
 +import socket
 +import math
 +import time
 +
 +# Hack to get ticks_ms() method in Tigerjython working
 +if not hasattr(time, 'ticks_ms'):
 +    from types import MethodType
 +    def ticks_ms(self):
 +        return int(round(self.time() * 1000))
 +    time.ticks_ms = MethodType(ticks_ms, time)
 +    
 +    def sleep_ms(self,a):
 +        time.sleep(a/1000.0)
 +    time.sleep_ms = MethodType(sleep_ms, time)
 +# END of Hack
 +
 +
 +
 +class WifiServer:
 +
 +    def __init__(self, helper):
 +        self.helper = helper
 +
 +
 +    def setup(self):
 +        self.ap = network.WLAN(network.AP_IF)
 +        self.ap.active(True)
 +        self.ap.config(essid='esp32', authmode=0)
 +        self.ap.ifconfig(('10.42.42.1', '255.255.255.0', '10.42.42.1', '10.42.42.1'))
 +        print("AP up an running")
 +        self.connections=[]
 +        # self.cfiles=[]
 +        self.graphBuffers=[]
 +        self.buttons=bytearray([])
 +        addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
 +        self.sk = socket.socket()
 +        self.sk.bind(addr)
 +        self.sk.listen(1)
 +        print("Server up an running")
 +
 +    def clearBuffers(self):
 +        if self.helper:
 +            for i in range(150):
 +                self.helper.np[i]=(0,0,0)
 +        for b in self.graphBuffers:
 +            for i in range(450):
 +                b[i]=0
 +
 +    def waitForConnection(self):
 +        print("Wait for connection...")
 +        cl, addr = self.sk.accept()
 +        self.connections.append(cl)
 +        print('client connected from', addr)
 +        #cl_file = cl.makefile('rwb', 0)
 +        #self.cfiles.append(cl_file)
 +        self.graphBuffers.append(bytearray([0 for i in range(450)]))
 +        self.buttons.append(255)
 +
 +    def setPixel(self,x,y,color):
 +        if (x<10):
 +            if self.helper:
 +                self.helper.setPixel(x,y,color)
 +        else:
 +            table = x//10-1
 +            if table<len(self.connections):
 +                n = y*10+x
 +                if n>=0 and n<149:
 +                    self.graphBuffers[table][3*n]=color[0]
 +                    self.graphBuffers[table][3*n+1]=color[1]
 +                    self.graphBuffers[table][3*n+2]=color[2]
 +                    
 +
 +
 +    def getButtons(self):
 +        # Get list with available bytes
 +        available = select.select(self.connections, (), (),0)
 +        for i in range(len(self.connections)):
 +            if self.connections[i] in available:                
 +                b = self.connections[i].recv(1)
 +                if b=='':
 +                    self.buttons[i]=255
 +                else:
 +                    self.buttons[i]=b[0]
 +                    
 +
 +    def write(self):
 +        if self.helper:
 +            self.helper.np.write()
 +        for i in range(len(self.connections)):
 +            totalsent = 0
 +            while totalsent<450:
 +                sent = self.connections[i].send(bytes(self.graphBuffers[i][totalsent:]))
 +                if sent == 0:
 +                    print("socket connection broken")
 +                    break
 +                totalsent+=sent
 +        time.sleep_ms(40) # 25 fps
 +        #print("sent")
 +
 +    def demo(self,i):
 +        xmax = (len(self.connections)+1)*10;
 +        self.clearBuffers()
 +        for x in range(xmax):
 +            y = int(math.sin(0.1*(x+i))*7+8)
 +            self.setPixel(x, y, (255,0,0))
 +            self.setPixel(x, y+1, (50,0,0))
 +            self.setPixel(x, y-1, (50,0,0))
 +            y = int(math.sin(0.06189*(x+i+5))*7+8)
 +            self.setPixel(x, y, (0,255,0))
 +            self.setPixel(x, y+1, (0,50,0))
 +            self.setPixel(x, y-1, (0,50,0))
 +            y = int(math.sin(0.04189*(x+i+10))*7+8)
 +            self.setPixel(x, y, (0,0,255))
 +            self.setPixel(x, y+1, (0,0,50))
 +            self.setPixel(x, y-1, (0,0,50))
 +        self.write()
 +
 +        
 +    def play(self):
 +        self.setup()
 +        if self.helper:
 +            while True:
 +                while self.helper.getButtons()!=255:
 +                    pass
 +                while self.helper.getButtons()==255:
 +                    pass
 +                if (self.helper.getButtons()^0xff) &0xf>0:
 +                    self.waitForConnection()
 +                else:
 +                    break                    
 +        else:
 +            self.waitForConnection()
 +            
 +        i=0
 +        while True:
 +            self.demo(i)
 +            i+=1
 +
 +
 +# Start with execfile("wifiserver.py")
 +
 +if __name__=="__main__":
 +    print("Start Main")
 +#    from helper import Helper  # Import der Klasse
 +#    helper = Helper()   # Erzeugen der Instanz
 +    helper = None
 +    print(helper)
 +    s = WifiServer(helper)
 +    s.play()
 +    
 +
 +</code>
 +</hidden>
 +===== Ablauf der Programmierung =====
 +**Achtung**: Wenn Putty verbunden ist, funktioniert ampy nicht (und umgekehrt).
 +  * Entwicklung des Codes im Texteditor, speichern einer Datei, z.B. ''beispiel.py''
 +  * Eventuell Datei lokal mit Python ausführen, erste Bugs werden so schon gefunden.
 +  * Datei mit ''ampy'' auf EPS laden.
 +  * Wenn die Datei ''main.py'' heisst (oder von main.py aufgerufen wird):
 +    * Reset am Tisch
 +  * Sonst:
 +    * Verbinden mit Putty (oder pico-dingsbums auf Mac), evtl. Ctrl-C um Programm zu stoppen
 +    * Programm mit ''import beispiel.py'' ausführen, Fehlermeldungen verstehen.
 +
 +===== Tools auf dem ESP =====
 +  * Dateien anschauen, löschen, umbennen, direkt auf dem ESP:
 +    * Mit Putty verbinden
 +      * ''import os''
 +      * ''help(os)'' (Zeigt Befehle an, wie Liste der Dateien, löschen, umbenennen).
 +
 +
 +
 +===== Joysticks testen =====
 +Auf der Konsole (putty oder screen)
 +<code python>
 +import helper
 +h = helper.Helper()
 +while True:
 +   print(h.getJoyStick(0))
 +
 +</code>