Browse Source

fix tetris. image resize aspect ratio. cheap chinese gamepad support.

Thomas Buck 11 months ago
parent
commit
ea9b0d94ff
11 changed files with 407 additions and 202 deletions
  1. 48
    48
      camp_pico.py
  2. 53
    52
      camp_small.py
  3. 61
    29
      gamepad.py
  4. 14
    5
      image.py
  5. 4
    4
      mapper.py
  6. 1
    1
      pi.py
  7. 100
    24
      pico_ota.py
  8. 26
    13
      snake.py
  9. 1
    1
      solid.py
  10. 87
    23
      tetris.py
  11. 12
    2
      util.py

+ 48
- 48
camp_pico.py View File

14
 from qr_tmp import qr_data
14
 from qr_tmp import qr_data
15
 from img_tmp import img_data
15
 from img_tmp import img_data
16
 
16
 
17
-if True:#__name__ == "__main__":
18
-    from solid import Solid
19
-    from life import GameOfLife
20
-    from net import CheckHTTP
21
-    from qr import QRScreen
22
-    from scroll import ScrollText
23
-    from splash import SplashScreen
24
-    from manager import Manager
25
-    from pico import PicoBatt
17
+from solid import Solid
18
+from life import GameOfLife
19
+from net import CheckHTTP
20
+from qr import QRScreen
21
+from scroll import ScrollText
22
+from splash import SplashScreen
23
+from manager import Manager
24
+from pico import PicoBatt
26
 
25
 
27
-    url = "http://ubabot.frubar.net"
26
+#url = "http://ubabot.frubar.net"
27
+url = "http://www.xythobuz.de"
28
 
28
 
29
-    import util
30
-    t = util.getTarget()
29
+import util
30
+t = util.getTarget()
31
 
31
 
32
-    # Loading fonts and graphics takes a while.
33
-    # So show a splash screen while the user waits.
34
-    splash = SplashScreen(t)
35
-    t.loop_start()
36
-    splash.draw()
37
-    t.loop_end()
32
+# Loading fonts and graphics takes a while.
33
+# So show a splash screen while the user waits.
34
+splash = SplashScreen(t)
35
+t.loop_start()
36
+splash.draw()
37
+t.loop_end()
38
 
38
 
39
-    # UbaBot is online
40
-    success = Manager(t)
41
-    success.add(ScrollText(t, "Visit UbaBot Cocktail machine at FruBar village for drinks!", "bitmap8", 1, 10, camp_green))
42
-    success.add(Solid(t, 1.0))
43
-    success.add(QRScreen(t, qr_data, 30.0, "Drinks", "bitmap6", camp_pink, (0, 0, 0)))
44
-    success.add(Solid(t, 1.0))
39
+# UbaBot is online
40
+success = Manager(t)
41
+success.add(ScrollText(t, "Visit UbaBot Cocktail machine at FruBar village for drinks!", "bitmap8", 1, 10, camp_green))
42
+success.add(Solid(t, 1.0))
43
+success.add(QRScreen(t, qr_data, 30.0, "Drinks", "bitmap6", camp_pink, (0, 0, 0)))
44
+success.add(Solid(t, 1.0))
45
 
45
 
46
-    # UbaBot is offline
47
-    fail = Manager(t)
48
-    fail.add(ScrollText(t, "#CCCAMP23", "bitmap8", 1, 10, camp_green))
49
-    fail.add(Solid(t, 1.0))
50
-    fail.add(ScrollText(t, "The UbaBot Cocktail machine is closed. Please come back later!", "bitmap8", 1, 10, camp_green))
51
-    fail.add(Solid(t, 1.0))
52
-    fail.add(GameOfLife(t, 20, (0, 255, 0), (0, 0, 0), None, 2.0))
53
-    fail.add(Solid(t, 1.0))
54
-    fail.add(ScrollText(t, "Your advertisement could appear here. Open a Pull Request on git.xythobuz.de/thomas/rgb-matrix-visualizer or send an e-mail to thomas@xythobuz.de", "bitmap8", 1, 10, camp_green))
55
-    fail.add(Solid(t, 1.0))
46
+# UbaBot is offline
47
+fail = Manager(t)
48
+fail.add(ScrollText(t, "#CCCAMP23", "bitmap8", 1, 10, camp_green))
49
+fail.add(Solid(t, 1.0))
50
+fail.add(ScrollText(t, "The UbaBot Cocktail machine is closed. Please come back later!", "bitmap8", 1, 10, camp_green))
51
+fail.add(Solid(t, 1.0))
52
+fail.add(GameOfLife(t, 20, (0, 255, 0), (0, 0, 0), None, 2.0))
53
+fail.add(Solid(t, 1.0))
54
+fail.add(ScrollText(t, "Your advertisement could appear here. Open a Pull Request on git.xythobuz.de/thomas/rgb-matrix-visualizer or send an e-mail to thomas@xythobuz.de", "bitmap8", 1, 10, camp_green))
55
+fail.add(Solid(t, 1.0))
56
 
56
 
57
-    # UbaBot status checker
58
-    d = CheckHTTP(url)
59
-    d.success(success)
60
-    d.fail(fail)
57
+# UbaBot status checker
58
+d = CheckHTTP(url)
59
+d.success(success)
60
+d.fail(fail)
61
 
61
 
62
-    # Main "Menu"
63
-    m = Manager(t)
64
-    m.add(QRScreen(t, img_data, 15.0))
65
-    m.add(Solid(t, 1.0))
66
-    m.add(d) # HTTP Check, either "success" or "fail"
67
-    m.add(Solid(t, 1.0))
68
-    m.add(PicoBatt(t, 5.0, 5.0))
69
-    m.add(Solid(t, 1.0))
62
+# Main "Menu"
63
+m = Manager(t)
64
+m.add(QRScreen(t, img_data, 15.0))
65
+m.add(Solid(t, 1.0))
66
+m.add(d) # HTTP Check, either "success" or "fail"
67
+m.add(Solid(t, 1.0))
68
+m.add(PicoBatt(t, 5.0, 5.0))
69
+m.add(Solid(t, 1.0))
70
 
70
 
71
-    m.restart()
72
-    t.loop(m.draw)
71
+m.restart()
72
+t.loop(m.draw)

+ 53
- 52
camp_small.py View File

10
 camp_pink = (251, 72, 196)
10
 camp_pink = (251, 72, 196)
11
 camp_green = (63, 255, 33)
11
 camp_green = (63, 255, 33)
12
 
12
 
13
-if __name__ == "__main__":
14
-    from splash import SplashScreen
15
-    from scroll import ScrollText
16
-    from solid import Solid
17
-    from life import GameOfLife
18
-    from net import CheckHTTP
19
-    from image import ImageScreen
20
-    from qr import QRScreen
21
-    from snake import Snake
22
-    from gamepad import InputWrapper
23
-    from manager import Manager
13
+from splash import SplashScreen
14
+from scroll import ScrollText
15
+from solid import Solid
16
+from life import GameOfLife
17
+from net import CheckHTTP
18
+from image import ImageScreen
19
+from qr import QRScreen
20
+from snake import Snake
21
+from gamepad import InputWrapper
22
+from manager import Manager
23
+import util
24
 
24
 
25
-    url = "http://ubabot.frubar.net"
25
+url = "http://ubabot.frubar.net"
26
 
26
 
27
-    import util
28
-    t = util.getTarget()
29
-    i = InputWrapper()
27
+# Need to import InputWrapper before initializing RGB Matrix on Pi
28
+i = InputWrapper()
30
 
29
 
31
-    # Loading fonts and graphics takes a while.
32
-    # So show a splash screen while the user waits.
33
-    splash = SplashScreen(t)
34
-    t.loop_start()
35
-    splash.draw()
36
-    t.loop_end()
30
+t = util.getTarget()
37
 
31
 
38
-    # UbaBot is online
39
-    success = Manager(t)
40
-    success.add(ImageScreen(t, "drinka.gif", 0.2, 2, 20.0))
41
-    success.add(Solid(t, 1.0))
42
-    success.add(QRScreen(t, url, 30.0, "Drinks:", "tom-thumb", (255, 255, 255), (0, 0, 0)))
43
-    success.add(Solid(t, 1.0))
32
+# Loading fonts and graphics takes a while.
33
+# So show a splash screen while the user waits.
34
+splash = SplashScreen(t)
35
+t.loop_start()
36
+splash.draw()
37
+t.loop_end()
44
 
38
 
45
-    # UbaBot is offline
46
-    fail = Manager(t)
47
-    fail.add(ImageScreen(t, "attention.gif", 0.2, 2, 20.0, (0, 0, 0)))
48
-    fail.add(ScrollText(t, "The UbaBot Cocktail machine is currently closed. Please come back later for more drinks!", "lemon", 2, 75, camp_pink))
49
-    fail.add(Solid(t, 1.0))
50
-    fail.add(GameOfLife(t, 20, (0, 255, 0), (0, 0, 0), None, 2.0))
51
-    fail.add(Solid(t, 1.0))
39
+# UbaBot is online
40
+success = Manager(t)
41
+success.add(ImageScreen(t, "drinka.gif", 0.2, 2, 20.0))
42
+success.add(Solid(t, 1.0))
43
+success.add(QRScreen(t, url, 30.0, "Drinks:", "tom-thumb", (255, 255, 255), (0, 0, 0)))
44
+success.add(Solid(t, 1.0))
52
 
45
 
53
-    # UbaBot status checker
54
-    d = CheckHTTP(url)
55
-    d.success(success)
56
-    d.fail(fail)
46
+# UbaBot is offline
47
+fail = Manager(t)
48
+fail.add(ImageScreen(t, "attention.gif", 0.2, 2, 20.0, (0, 0, 0)))
49
+fail.add(ScrollText(t, "The UbaBot Cocktail machine is currently closed. Please come back later for more drinks!", "lemon", 2, 75, camp_pink))
50
+fail.add(Solid(t, 1.0))
51
+fail.add(GameOfLife(t, 20, (0, 255, 0), (0, 0, 0), None, 2.0))
52
+fail.add(Solid(t, 1.0))
57
 
53
 
58
-    # Main "Menu"
59
-    m = Manager(t)
60
-    m.add(ScrollText(t, "#CCCAMP23", "lemon", 1, 75, camp_green))
61
-    m.add(Solid(t, 1.0))
62
-    m.add(ImageScreen(t, "Favicon.png", 0, 1, 10.0))
63
-    m.add(Solid(t, 1.0))
64
-    m.add(d) # HTTP Check, either "success" or "fail"
65
-    m.add(Solid(t, 1.0))
66
-    m.add(Snake(t, i, camp_pink, camp_green))
67
-    m.add(Solid(t, 1.0))
68
-    m.add(ScrollText(t, "Your advertisement could appear here. Open a Pull Request on git.xythobuz.de/thomas/rgb-matrix-visualizer or send an e-mail to thomas@xythobuz.de", "iv18x16u", 2, 70, camp_green))
69
-    m.add(Solid(t, 1.0))
54
+# UbaBot status checker
55
+d = CheckHTTP(url)
56
+d.success(success)
57
+d.fail(fail)
70
 
58
 
71
-    m.restart()
72
-    t.loop(m.draw)
59
+# Main "Menu"
60
+m = Manager(t)
61
+m.add(ScrollText(t, "#CCCAMP23", "lemon", 1, 75, camp_green))
62
+m.add(Solid(t, 1.0))
63
+m.add(ImageScreen(t, "Favicon.png", 0, 1, 10.0))
64
+m.add(Solid(t, 1.0))
65
+m.add(d) # HTTP Check, either "success" or "fail"
66
+m.add(Solid(t, 1.0))
67
+m.add(Snake(t, i, camp_pink, camp_green))
68
+m.add(Solid(t, 1.0))
69
+m.add(ScrollText(t, "Your advertisement could appear here. Open a Pull Request on git.xythobuz.de/thomas/rgb-matrix-visualizer or send an e-mail to thomas@xythobuz.de", "iv18x16u", 2, 70, camp_green))
70
+m.add(Solid(t, 1.0))
71
+
72
+m.restart()
73
+t.loop(m.draw)

+ 61
- 29
gamepad.py View File

26
             "b": False,
26
             "b": False,
27
             "x": False,
27
             "x": False,
28
             "y": False,
28
             "y": False,
29
+            "l": False,
30
+            "r": False,
31
+            "start": False,
32
+            "select": False,
29
         }
33
         }
30
 
34
 
31
         devices = [InputDevice(path) for path in list_devices()]
35
         devices = [InputDevice(path) for path in list_devices()]
32
         for device in devices:
36
         for device in devices:
33
-            c = device.capabilities()
37
+            c = device.capabilities(absinfo=False)
34
             keep = False
38
             keep = False
35
 
39
 
36
-            # check for key events
37
-            if ecodes.EV_KEY in c:
40
+            # check for axis events
41
+            if ecodes.EV_ABS in c:
38
                 # check for gamepad
42
                 # check for gamepad
39
-                if ecodes.BTN_A in c[ecodes.EV_KEY]:
43
+                if ecodes.ABS_X in c[ecodes.EV_ABS]:
40
                     print("Gamepad detected: ", device.name)
44
                     print("Gamepad detected: ", device.name)
41
                     keep = True
45
                     keep = True
42
 
46
 
47
+            # check for key events
48
+            if ecodes.EV_KEY in c:
43
                 # check for arrow keys
49
                 # check for arrow keys
44
-                elif ecodes.KEY_LEFT in c[ecodes.EV_KEY]:
50
+                if ecodes.KEY_LEFT in c[ecodes.EV_KEY]:
45
                     print("Keyboard detected:", device.name)
51
                     print("Keyboard detected:", device.name)
46
                     keep = True
52
                     keep = True
47
 
53
 
56
         for key, mask in self.selector.select(0):
62
         for key, mask in self.selector.select(0):
57
             device = key.fileobj
63
             device = key.fileobj
58
             for event in device.read():
64
             for event in device.read():
59
-                if event.type != ecodes.EV_KEY:
60
-                    continue
61
-
62
-                v = False
63
-                if event.value != 0:
64
-                    v = True
65
+                if event.type == ecodes.EV_KEY:
66
+                    v = False
67
+                    if event.value != 0:
68
+                        v = True
65
 
69
 
66
-                if (event.code == ecodes.KEY_LEFT) or (event.code == ecodes.BTN_WEST):
67
-                    self.keys["left"] = v
68
-                elif (event.code == ecodes.KEY_RIGHT) or (event.code == ecodes.BTN_EAST):
69
-                    self.keys["right"] = v
70
-                elif (event.code == ecodes.KEY_UP) or (event.code == ecodes.BTN_NORTH):
71
-                    self.keys["up"] = v
72
-                elif (event.code == ecodes.KEY_DOWN) or (event.code == ecodes.BTN_SOUTH):
73
-                    self.keys["down"] = v
74
-                elif (event.code == ecodes.KEY_SPACE) or (event.code == ecodes.BTN_A):
75
-                    self.keys["a"] = v
76
-                elif (event.code == ecodes.KEY_LEFTCTRL) or (event.code == ecodes.BTN_B):
77
-                    self.keys["b"] = v
78
-                elif (event.code == ecodes.KEY_LEFTALT) or (event.code == ecodes.BTN_X):
79
-                    self.keys["x"] = v
80
-                elif (event.code == ecodes.KEY_ENTER) or (event.code == ecodes.BTN_Y):
81
-                    self.keys["y"] = v
82
-                else:
83
-                    return self.keys
70
+                    if (event.code == ecodes.KEY_LEFT) or (event.code == ecodes.BTN_WEST):
71
+                        self.keys["left"] = v
72
+                    elif (event.code == ecodes.KEY_RIGHT) or (event.code == ecodes.BTN_EAST):
73
+                        self.keys["right"] = v
74
+                    elif (event.code == ecodes.KEY_UP) or (event.code == ecodes.BTN_NORTH):
75
+                        self.keys["up"] = v
76
+                    elif (event.code == ecodes.KEY_DOWN) or (event.code == ecodes.BTN_SOUTH):
77
+                        self.keys["down"] = v
78
+                    elif (event.code == ecodes.KEY_SPACE) or (event.code == ecodes.BTN_A) or (event.code == ecodes.BTN_THUMB):
79
+                        self.keys["a"] = v
80
+                    elif (event.code == ecodes.KEY_LEFTCTRL) or (event.code == ecodes.BTN_B) or (event.code == ecodes.BTN_THUMB2):
81
+                        self.keys["b"] = v
82
+                    elif (event.code == ecodes.KEY_LEFTALT) or (event.code == ecodes.BTN_X) or (event.code == ecodes.BTN_JOYSTICK) or (event.code == ecodes.BTN_TRIGGER):
83
+                        self.keys["x"] = v
84
+                    elif (event.code == ecodes.KEY_ENTER) or (event.code == ecodes.BTN_Y) or (event.code == ecodes.BTN_TOP):
85
+                        self.keys["y"] = v
86
+                    elif event.code == ecodes.BTN_PINKIE:
87
+                        self.keys["r"] = v
88
+                    elif event.code == ecodes.BTN_TOP2:
89
+                        self.keys["l"] = v
90
+                    elif event.code == ecodes.BTN_BASE4:
91
+                        self.keys["start"] = v
92
+                    elif event.code == ecodes.BTN_BASE3:
93
+                        self.keys["select"] = v
94
+                elif event.type == ecodes.EV_ABS:
95
+                    # TODO 8bit hardcoded
96
+                    if event.code == ecodes.ABS_X:
97
+                        if event.value > 200:
98
+                            self.keys["right"] = True
99
+                            self.keys["left"] = False
100
+                        elif event.value < 100:
101
+                            self.keys["right"] = False
102
+                            self.keys["left"] = True
103
+                        else:
104
+                            self.keys["right"] = False
105
+                            self.keys["left"] = False
106
+                    elif event.code == ecodes.ABS_Y:
107
+                        if event.value > 200:
108
+                            self.keys["down"] = True
109
+                            self.keys["up"] = False
110
+                        elif event.value < 100:
111
+                            self.keys["down"] = False
112
+                            self.keys["up"] = True
113
+                        else:
114
+                            self.keys["down"] = False
115
+                            self.keys["up"] = False
84
 
116
 
85
                 if verbose:
117
                 if verbose:
86
                     print(categorize(event), event)
118
                     print(categorize(event), event)

+ 14
- 5
image.py View File

34
 
34
 
35
         # automatically crop and scale large images
35
         # automatically crop and scale large images
36
         if not self.image.is_animated and ((self.image.width > self.gui.width) or (self.image.height > self.gui.height)):
36
         if not self.image.is_animated and ((self.image.width > self.gui.width) or (self.image.height > self.gui.height)):
37
+            # crop to visible area
37
             self.image = self.image.crop(self.image.getbbox())
38
             self.image = self.image.crop(self.image.getbbox())
38
 
39
 
39
-            if util.isPi():
40
-                # TODO PIL version is too old on Pi
41
-                self.image = self.image.resize((self.gui.width, self.gui.height))
40
+            # keep the aspect ratio and fit within visible area
41
+            ratio = self.image.width / self.image.height
42
+            width = self.gui.width
43
+            height = self.gui.height
44
+            if width < height:
45
+                width = self.gui.width
46
+                height = int(width / ratio)
42
             else:
47
             else:
43
-                self.image = self.image.resize((self.gui.width, self.gui.height),
44
-                                            Image.Resampling.NEAREST)
48
+                height = self.gui.height
49
+                width = int(ratio * height)
50
+
51
+            # resize
52
+            self.image = self.image.resize((width, height),
53
+                                           Image.Resampling.NEAREST)
45
 
54
 
46
             # new image object is also missing these
55
             # new image object is also missing these
47
             self.image.is_animated = False
56
             self.image.is_animated = False

+ 4
- 4
mapper.py View File

52
 # on hard-corded coordinate ranges.
52
 # on hard-corded coordinate ranges.
53
 class MapperColorAdjust(MapperNull):
53
 class MapperColorAdjust(MapperNull):
54
     def set_pixel(self, x, y, color):
54
     def set_pixel(self, x, y, color):
55
-        # third panel from the left, with 64 <= x < 96,
55
+        # second panel from the left, with 32 <= x,
56
         # is "old" type with brighter LEDs.
56
         # is "old" type with brighter LEDs.
57
-        # rest of panels to the left and right are less bright.
58
-        # so adjust brightness of inner panel rg channels down.
59
-        if (x >= (self.gui.panelW * 2)) and (x < (self.gui.panelW * 3)):
57
+        # rest of panels to the left are less bright.
58
+        # so adjust brightness of other panel rg channels down.
59
+        if x >= self.gui.panelW:
60
             color = (int(color[0] * 0.75), int(color[1] * 0.75), color[2])
60
             color = (int(color[0] * 0.75), int(color[1] * 0.75), color[2])
61
 
61
 
62
         self.gui.set_pixel(x, y, color)
62
         self.gui.set_pixel(x, y, color)

+ 1
- 1
pi.py View File

32
 from PIL import Image
32
 from PIL import Image
33
 
33
 
34
 class PiMatrix:
34
 class PiMatrix:
35
-    def __init__(self, w = 32 * 4, h = 32, panelW = 32, panelH = 32):
35
+    def __init__(self, w = 32 * 2, h = 32, panelW = 32, panelH = 32):
36
         self.width = w # x-axis
36
         self.width = w # x-axis
37
         self.height = h # y-axis
37
         self.height = h # y-axis
38
 
38
 

+ 100
- 24
pico_ota.py View File

19
 # to check if we're actually running on MicroPython
19
 # to check if we're actually running on MicroPython
20
 on_pico = False
20
 on_pico = False
21
 try:
21
 try:
22
-    import uos
22
+    import machine
23
     on_pico = True
23
     on_pico = True
24
 except Exception as e:
24
 except Exception as e:
25
     print()
25
     print()
37
 
37
 
38
         self.get = None
38
         self.get = None
39
         self.update_path = "."
39
         self.update_path = "."
40
+        self.exe_path = ""
41
+        self.version_file = "ota_version"
40
         self.blacklist = []
42
         self.blacklist = []
41
 
43
 
42
     def path(self, p):
44
     def path(self, p):
43
         self.update_path = p
45
         self.update_path = p
44
 
46
 
47
+    def exe(self, e):
48
+        self.exe_path = e
49
+
45
     def ignore(self, path):
50
     def ignore(self, path):
46
         if not path in self.blacklist:
51
         if not path in self.blacklist:
47
             self.blacklist.append(path)
52
             self.blacklist.append(path)
67
             print()
72
             print()
68
             return None
73
             return None
69
 
74
 
75
+    def get_stored_commit(self):
76
+        current = "unknown"
77
+        try:
78
+            f = open(os.path.join(self.update_path, self.version_file), "r")
79
+            current = f.readline().strip()
80
+            f.close()
81
+        except Exception as e:
82
+            print()
83
+            if hasattr(sys, "print_exception"):
84
+                sys.print_exception(e)
85
+            else:
86
+                print(e)
87
+            print()
88
+        return current
89
+
90
+    def get_previous_commit(self, commit):
91
+        r = self.fetch(self.host + "/" + self.repo + "/commit/" + commit).text
92
+        for line in r.splitlines():
93
+            if not (self.repo + "/commit/") in line:
94
+                continue
95
+
96
+            line = line[line.find("/commit/") : ][8 : ][ : 40]
97
+            if line != commit:
98
+                return line
99
+        return "unknown"
100
+
70
     def check(self, verbose = False):
101
     def check(self, verbose = False):
71
         if self.branch == None:
102
         if self.branch == None:
72
             # get default branch
103
             # get default branch
83
         if verbose:
114
         if verbose:
84
             print("Latest commit is " + commit)
115
             print("Latest commit is " + commit)
85
 
116
 
86
-        current = ""
87
-        try:
88
-            f = open(os.path.join(self.update_path, "ota_version"), "r")
89
-            current = f.readline().strip()
90
-            f.close()
91
-        except Exception as e:
92
-            print()
93
-            if hasattr(sys, "print_exception"):
94
-                sys.print_exception(e)
95
-            else:
96
-                print(e)
97
-            print()
117
+        current = self.get_stored_commit()
98
 
118
 
99
         if verbose:
119
         if verbose:
100
             if current != commit:
120
             if current != commit:
132
                 print("Writing " + f["path"] + " to " + self.update_path)
152
                 print("Writing " + f["path"] + " to " + self.update_path)
133
 
153
 
134
             # overwrite existing file
154
             # overwrite existing file
135
-            f = open(os.path.join(self.update_path, f["path"]), "w")
136
-            f.write(r)
137
-            f.close()
155
+            fo = open(os.path.join(self.update_path, f["path"]), "w")
156
+            fo.write(r)
157
+            fo.close()
158
+
159
+            if f["path"] == self.exe_path:
160
+                if verbose:
161
+                    print("Writing " + f["path"] + " to main.py")
162
+
163
+                fo = open(os.path.join(self.update_path, "main.py"), "w")
164
+                fo.write(r)
165
+                fo.close()
138
 
166
 
139
         # Write new commit id to local file
167
         # Write new commit id to local file
140
-        f = open(os.path.join(self.update_path, "ota_version"), "w")
168
+        f = open(os.path.join(self.update_path, self.version_file), "w")
141
         f.write(commit + os.linesep)
169
         f.write(commit + os.linesep)
142
         f.close()
170
         f.close()
143
 
171
 
172
+def non_pico_ota_test(ota):
173
+    if not os.path.exists("tmp"):
174
+        os.makedirs("tmp")
175
+    ota.path("tmp")
176
+
177
+    print("Checking for updates")
178
+    newer, commit = ota.check(True)
179
+    print()
180
+
181
+    # Just for testing
182
+    previous = ota.get_previous_commit(commit)
183
+    print("Previous commit (-1):", previous)
184
+    previous = ota.get_previous_commit(previous)
185
+    print("Previous commit (-2):", previous)
186
+    print()
187
+
188
+    if newer:
189
+        print("Updating")
190
+        ota.update_to_commit(commit, True)
191
+    else:
192
+        print("No update required")
193
+
194
+def pico_ota_run(ota):
195
+    newer, commit = ota.check(True)
196
+
197
+    if newer:
198
+        ota.update_to_commit(commit, True)
199
+        machine.soft_reset()
200
+
201
+    fallback = False
202
+
203
+    try:
204
+        import camp_pico
205
+    except Exception as e:
206
+        fallback = True
207
+        print()
208
+        if hasattr(sys, "print_exception"):
209
+            sys.print_exception(e)
210
+        else:
211
+            print(e)
212
+        print()
213
+
214
+    # TODO this would immediately cause another update on reboot
215
+    # TODO set a flag to prevent updates after fallbacks?
216
+    # TODO or better, blacklist failed commit_id!
217
+    #if fallback:
218
+    #    previous = ota.get_previous_commit(commit, True)
219
+    #    ota.update_to_commit(previous, True)
220
+    #    machine.soft_reset()
221
+
144
 if __name__ == "__main__":
222
 if __name__ == "__main__":
145
     ota = PicoOTA("https://git.xythobuz.de", "thomas/rgb-matrix-visualizer")
223
     ota = PicoOTA("https://git.xythobuz.de", "thomas/rgb-matrix-visualizer")
146
 
224
 
157
     ota.ignore("pi.py")
235
     ota.ignore("pi.py")
158
     ota.ignore("test.py")
236
     ota.ignore("test.py")
159
 
237
 
160
-    if not on_pico:
161
-        if not os.path.exists("tmp"):
162
-            os.makedirs("tmp")
163
-        ota.path("tmp")
238
+    ota.exe("camp_pico.py")
164
 
239
 
165
-    newer, commit = ota.check(True)
166
-    if newer:
167
-        ota.update_to_commit(commit, True)
240
+    if not on_pico:
241
+        non_pico_ota_test(ota)
242
+    else:
243
+        pico_ota_run(ota)

+ 26
- 13
snake.py View File

41
         self.player = [ (int(self.gui.width / 2), int(self.gui.height / 2)) ]
41
         self.player = [ (int(self.gui.width / 2), int(self.gui.height / 2)) ]
42
         self.data[self.player[0][0]][self.player[0][1]] = 1
42
         self.data[self.player[0][0]][self.player[0][1]] = 1
43
 
43
 
44
+        self.old_keys = {
45
+            "left": False,
46
+            "right": False,
47
+            "up": False,
48
+            "down": False,
49
+        }
50
+
44
         self.placeDot()
51
         self.placeDot()
45
 
52
 
46
     def finished(self):
53
     def finished(self):
63
 
70
 
64
     def buttons(self):
71
     def buttons(self):
65
         keys = self.input.get()
72
         keys = self.input.get()
66
-        if keys["left"]:
73
+
74
+        if keys["left"] and (not self.old_keys["left"]):
67
             self.directionTmp = "l"
75
             self.directionTmp = "l"
68
-        elif keys["right"]:
76
+        elif keys["right"] and (not self.old_keys["right"]):
69
             self.directionTmp = "r"
77
             self.directionTmp = "r"
70
-        elif keys["up"]:
78
+        elif keys["up"] and (not self.old_keys["up"]):
71
             self.directionTmp = "u"
79
             self.directionTmp = "u"
72
-        elif keys["down"]:
80
+        elif keys["down"] and (not self.old_keys["down"]):
73
             self.directionTmp = "d"
81
             self.directionTmp = "d"
82
+        elif (keys["select"] and keys["start"] and (not self.old_keys["start"])) or (keys["start"] and keys["select"] and (not self.old_keys["select"])):
83
+            self.restart()
84
+
85
+        self.old_keys = keys.copy()
74
 
86
 
75
     def step(self):
87
     def step(self):
76
         player = self.player[len(self.player) - 1]
88
         player = self.player[len(self.player) - 1]
122
         self.scoreText.draw()
134
         self.scoreText.draw()
123
 
135
 
124
     def draw(self):
136
     def draw(self):
137
+        if self.input != None:
138
+            self.buttons()
139
+        else:
140
+            # TODO "AI"
141
+            pass
142
+
125
         if self.direction == "":
143
         if self.direction == "":
126
             if self.finishedEndScreen():
144
             if self.finishedEndScreen():
127
                 self.drawScoreScreen()
145
                 self.drawScoreScreen()
130
                 self.scoreText.restart()
148
                 self.scoreText.restart()
131
             return
149
             return
132
 
150
 
133
-        if self.input != None:
134
-            self.buttons()
135
-        else:
136
-            # TODO "AI"
137
-            pass
138
-
139
         now = time.time()
151
         now = time.time()
140
         if (now - self.last) >= self.timestep:
152
         if (now - self.last) >= self.timestep:
141
             self.last = now
153
             self.last = now
158
                 self.gui.set_pixel(x, y, self.colors[self.data[x][y]])
170
                 self.gui.set_pixel(x, y, self.colors[self.data[x][y]])
159
 
171
 
160
 if __name__ == "__main__":
172
 if __name__ == "__main__":
161
-    import util
162
-    t = util.getTarget()
163
-
173
+    # Need to import InputWrapper before initializing RGB Matrix on Pi
164
     from gamepad import InputWrapper
174
     from gamepad import InputWrapper
165
     i = InputWrapper()
175
     i = InputWrapper()
166
 
176
 
177
+    import util
178
+    t = util.getTarget()
179
+
167
     d = Snake(t, i)
180
     d = Snake(t, i)
168
     t.loop(d.draw)
181
     t.loop(d.draw)

+ 1
- 1
solid.py View File

57
         global s, colors, ci, n, c
57
         global s, colors, ci, n, c
58
 
58
 
59
         now = time.time()
59
         now = time.time()
60
-        if ((now - s) >= 0.1) or (now < s):
60
+        if ((now - s) >= 0.5) or (now < s):
61
             s = now
61
             s = now
62
             n += 1
62
             n += 1
63
             if n >= 15:
63
             if n >= 15:

+ 87
- 23
tetris.py View File

12
 import random
12
 import random
13
 
13
 
14
 class Tetris:
14
 class Tetris:
15
-    def __init__(self, g, i, ts = 0.5, to = 60.0):
15
+    def __init__(self, g, i, ts = 0.5, to = 60.0, w = 10, h = 22):
16
         self.gui = g
16
         self.gui = g
17
         self.input = i
17
         self.input = i
18
         self.timestep = ts
18
         self.timestep = ts
19
         self.timeout = to
19
         self.timeout = to
20
+        self.width = min(w, self.gui.width)
21
+        self.height = min(h, self.gui.height)
22
+
23
+        self.x_off = int((self.gui.panelW - self.width - 2) / 2)
24
+        self.y_off = int((self.gui.panelH - self.height - 2) / 2)
20
 
25
 
21
         self.endText = ScrollText(self.gui, "Game Over!", "uushi",
26
         self.endText = ScrollText(self.gui, "Game Over!", "uushi",
22
                                    2, 75, (251, 72, 196))
27
                                    2, 75, (251, 72, 196))
94
         self.button = None
99
         self.button = None
95
         self.score = 0
100
         self.score = 0
96
         self.done = False
101
         self.done = False
97
-        self.data = [[self.bg for y in range(self.gui.height)] for x in range(self.gui.width)]
102
+        self.data = [[self.bg for y in range(self.height)] for x in range(self.width)]
98
         self.piece = None
103
         self.piece = None
104
+        self.old_keys = {
105
+            "left": False,
106
+            "right": False,
107
+            "up": False,
108
+            "down": False,
109
+        }
99
 
110
 
100
     def finished(self):
111
     def finished(self):
101
         if self.input == None:
112
         if self.input == None:
109
 
120
 
110
         return False
121
         return False
111
 
122
 
112
-    # TODO collision detection is broken
113
-    # TODO not working for pixels outside of vertical center line???
114
-    # TODO something like that...
115
     def collision(self):
123
     def collision(self):
116
         # check for collision of piece with data
124
         # check for collision of piece with data
117
         pos = (self.piece[2], self.piece[3])
125
         pos = (self.piece[2], self.piece[3])
122
                     continue
130
                     continue
123
 
131
 
124
                 # check for collision with bottom wall
132
                 # check for collision with bottom wall
125
-                if (y + pos[1]) >= self.gui.height:
133
+                if (y + pos[1]) >= self.height:
134
+                    return True
135
+
136
+                # check for collision with right wall
137
+                if (x + pos[0]) >= self.width:
126
                     return True
138
                     return True
127
 
139
 
128
                 # check for collision with previous pieces
140
                 # check for collision with previous pieces
142
 
154
 
143
         for y in range(0, len(piece)):
155
         for y in range(0, len(piece)):
144
             for x in range(0, len(piece[y])):
156
             for x in range(0, len(piece[y])):
145
-                remove = False
157
+                # only set or clear where piece actually is
146
                 if piece[y][x] == 0:
158
                 if piece[y][x] == 0:
147
-                    remove = True
159
+                    continue
148
 
160
 
149
-                if clear or remove:
161
+                if clear:
150
                     self.data[x + position[0]][y + position[1]] = self.bg
162
                     self.data[x + position[0]][y + position[1]] = self.bg
151
                 else:
163
                 else:
152
                     self.data[x + position[0]][y + position[1]] = self.piece[1]
164
                     self.data[x + position[0]][y + position[1]] = self.piece[1]
153
 
165
 
166
+    def checkWin(self):
167
+        had_data = False
168
+        for y in range(0, self.height):
169
+            line_full = True
170
+            for x in range(0, self.width):
171
+                if self.data[x][y] == self.bg:
172
+                    line_full = False
173
+                else:
174
+                    had_data = True
175
+
176
+            if had_data and line_full:
177
+                self.score += 1
178
+
179
+                # move stuff above into this line
180
+                for y2 in reversed(range(1, y + 1)):
181
+                    for x in range(0, self.width):
182
+                        self.data[x][y2] = self.data[x][y2 - 1]
183
+
184
+                # clear out top line
185
+                for x in range(0, self.width):
186
+                    self.data[x][0] = self.bg
187
+
188
+        # check for complete win
189
+        board_clear = (self.piece == None)
190
+        for y in range(0, self.height):
191
+            for x in range(0, self.width):
192
+                if self.data[x][y] != self.bg:
193
+                    board_clear = False
194
+                if board_clear == False:
195
+                    break
196
+            if board_clear == False:
197
+                break
198
+        return board_clear
199
+
154
     def step(self):
200
     def step(self):
155
         if self.piece == None:
201
         if self.piece == None:
156
             justPlaced = True
202
             justPlaced = True
164
             ]
210
             ]
165
 
211
 
166
             # center the piece on top of the playing board
212
             # center the piece on top of the playing board
167
-            self.piece[2] = int((self.gui.width - len(self.piece[0][0])) / 2)
213
+            self.piece[2] = int((self.width - len(self.piece[0][0])) / 2)
168
 
214
 
169
             if self.collision():
215
             if self.collision():
170
                 # new piece immediately collided. game over!
216
                 # new piece immediately collided. game over!
188
             if self.piece[2] > 0:
234
             if self.piece[2] > 0:
189
                 self.piece[2] -= 1
235
                 self.piece[2] -= 1
190
         elif self.button == "r":
236
         elif self.button == "r":
191
-            if self.piece[2] < (self.gui.width - 1):
237
+            if self.piece[2] < (self.width - 1):
192
                 self.piece[2] += 1
238
                 self.piece[2] += 1
193
         else:
239
         else:
194
             # one pixel down
240
             # one pixel down
205
             self.piece[2] = oldPosition[0]
251
             self.piece[2] = oldPosition[0]
206
             self.piece[3] = oldPosition[1]
252
             self.piece[3] = oldPosition[1]
207
 
253
 
208
-            if (self.button != "l") and (self.button != "r"):
254
+            if (self.button != "l") and (self.button != "r") and (self.button != "u"):
209
                 # but only stop playing it if it was moving down
255
                 # but only stop playing it if it was moving down
210
                 self.piece = None
256
                 self.piece = None
257
+
258
+                # check for cleared line
259
+                if self.checkWin():
260
+                    return False
211
         else:
261
         else:
212
             # copy piece at new location into buffer
262
             # copy piece at new location into buffer
213
             self.put(False)
263
             self.put(False)
219
 
269
 
220
     def buttons(self):
270
     def buttons(self):
221
         keys = self.input.get()
271
         keys = self.input.get()
222
-        if keys["left"]:
272
+
273
+        if keys["left"] and (not self.old_keys["left"]):
223
             self.button = "l"
274
             self.button = "l"
224
-        elif keys["right"]:
275
+        elif keys["right"] and (not self.old_keys["right"]):
225
             self.button = "r"
276
             self.button = "r"
226
-        elif keys["up"]:
277
+        elif keys["up"] and (not self.old_keys["up"]):
227
             self.button = "u"
278
             self.button = "u"
228
         elif keys["down"]:
279
         elif keys["down"]:
229
             self.button = "d"
280
             self.button = "d"
281
+        elif (keys["select"] and keys["start"] and (not self.old_keys["start"])) or (keys["start"] and keys["select"] and (not self.old_keys["select"])):
282
+            self.restart()
283
+
284
+        self.old_keys = keys.copy()
230
 
285
 
231
     def draw(self):
286
     def draw(self):
232
         if self.done:
287
         if self.done:
245
 
300
 
246
         now = time.time()
301
         now = time.time()
247
         if (self.button != None) or ((now - self.last) >= self.timestep) or (now < self.last):
302
         if (self.button != None) or ((now - self.last) >= self.timestep) or (now < self.last):
248
-            self.last = now
303
+            # don't let user stop falling pieces by moving/rotating endlessly
304
+            if (self.button != "l") and (self.button != "r") and (self.button != "u"):
305
+                self.last = now
306
+
249
             cont = self.step()
307
             cont = self.step()
250
             if cont == False:
308
             if cont == False:
251
                 self.done = True
309
                 self.done = True
252
                 self.scoreText.setText("Score: " + str(self.score), "uushi")
310
                 self.scoreText.setText("Score: " + str(self.score), "uushi")
253
                 self.endText.restart()
311
                 self.endText.restart()
254
 
312
 
255
-        for x in range(0, self.gui.width):
256
-            for y in range(0, self.gui.height):
257
-                self.gui.set_pixel(x, y, self.data[x][y])
313
+        # TODO placement of play area
314
+        for x in range(-1, self.width + 1):
315
+            for y in range(-1, self.height + 1):
316
+                c = (255, 255, 255)
317
+                if (x >= 0) and (y >= 0) and (x < self.width) and (y < self.height):
318
+                    c = self.data[x][y]
258
 
319
 
259
-if __name__ == "__main__":
260
-    import util
261
-    t = util.getTarget()
320
+                self.gui.set_pixel(x + 1 + self.x_off, y + 1 + self.y_off, c)
262
 
321
 
322
+if __name__ == "__main__":
323
+    # Need to import InputWrapper before initializing RGB Matrix on Pi
263
     from gamepad import InputWrapper
324
     from gamepad import InputWrapper
264
     i = InputWrapper()
325
     i = InputWrapper()
265
 
326
 
266
-    d = Tetris(t, i, 0.1)
327
+    import util
328
+    t = util.getTarget()
329
+
330
+    d = Tetris(t, i)
267
     t.loop(d.draw)
331
     t.loop(d.draw)

+ 12
- 2
util.py View File

9
 
9
 
10
 import sys
10
 import sys
11
 
11
 
12
+cachedTarget = None
12
 targetPlatform = None
13
 targetPlatform = None
13
 wifiConnected = False
14
 wifiConnected = False
14
 
15
 
29
     return targetPlatform == "pico"
30
     return targetPlatform == "pico"
30
 
31
 
31
 def getTarget():
32
 def getTarget():
32
-    global targetPlatform
33
+    global targetPlatform, cachedTarget
34
+
35
+    if cachedTarget != None:
36
+        return cachedTarget
33
 
37
 
34
     target = None
38
     target = None
35
     try:
39
     try:
40
         # TODO hard-coded adjustments
44
         # TODO hard-coded adjustments
41
         from mapper import MapperColorAdjust, MapperStripToRect
45
         from mapper import MapperColorAdjust, MapperStripToRect
42
         col = MapperColorAdjust(pi)
46
         col = MapperColorAdjust(pi)
43
-        target = MapperStripToRect(col)
47
+        #target = MapperStripToRect(col)
48
+        target = col
44
 
49
 
45
         if targetPlatform == None:
50
         if targetPlatform == None:
46
             # only print once
51
             # only print once
47
             print("Raspberry Pi Adafruit RGB LED Matrix detected")
52
             print("Raspberry Pi Adafruit RGB LED Matrix detected")
48
         targetPlatform = "pi"
53
         targetPlatform = "pi"
49
     except Exception as e:
54
     except Exception as e:
55
+        target = None
56
+
50
         print()
57
         print()
51
         if hasattr(sys, "print_exception"):
58
         if hasattr(sys, "print_exception"):
52
             sys.print_exception(e)
59
             sys.print_exception(e)
68
                 print("Raspberry Pi Pico Interstate75 RGB LED Matrix detected")
75
                 print("Raspberry Pi Pico Interstate75 RGB LED Matrix detected")
69
             targetPlatform = "pico"
76
             targetPlatform = "pico"
70
         except Exception as e:
77
         except Exception as e:
78
+            target = None
79
+
71
             print()
80
             print()
72
             if hasattr(sys, "print_exception"):
81
             if hasattr(sys, "print_exception"):
73
                 sys.print_exception(e)
82
                 sys.print_exception(e)
84
                 print("Falling back to GUI debug interface")
93
                 print("Falling back to GUI debug interface")
85
             targetPlatform = "tk"
94
             targetPlatform = "tk"
86
 
95
 
96
+    cachedTarget = target
87
     return target
97
     return target
88
 
98
 
89
 # https://github.com/raspberrypi/pico-examples/blob/master/pico_w/wifi/python_test_tcp/micropython_test_tcp_client.py
99
 # https://github.com/raspberrypi/pico-examples/blob/master/pico_w/wifi/python_test_tcp/micropython_test_tcp_client.py

Loading…
Cancel
Save