sync with current state
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								apps/PressStart2P-Regular.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								apps/PressStart2P-Regular.ttf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										38
									
								
								apps/backlight.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										38
									
								
								apps/backlight.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import os | ||||
| import sys | ||||
| import random  | ||||
| import time | ||||
| import math | ||||
| import numpy as np | ||||
| # Groesse des Bildschirms bestimmen | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
|  | ||||
| # Bestimme den Parameter | ||||
| time_ms = 10 | ||||
| try: | ||||
|     time_ms = int(sys.argv[3]) | ||||
| except: | ||||
|     pass | ||||
|  | ||||
| # Puffer fuer Pixel erstellen und mit 0 initialisieren | ||||
|  | ||||
| curPixel = 0 | ||||
|  | ||||
| phase = np.random.uniform(0, 2*np.pi, (Ny, Nx)) | ||||
| t = 0 | ||||
| f_min = 0.08 | ||||
| f_max = 0.10 | ||||
| f = np.random.uniform(f_min, f_max, (Ny, Nx)) | ||||
| while True: | ||||
|     t += time_ms/1000.0 | ||||
|     s = 0.80 +0.2*np.sin(phase+2*np.pi*t*f) | ||||
|     img = np.zeros([Ny, Nx, 4]) | ||||
|     img[:,:,3] = 255*s | ||||
|     # Zeige den Puffer an | ||||
|     out = img.reshape((Nx*Ny*4,)).astype(np.uint8) | ||||
|     os.write(1, out.tobytes()) | ||||
|     # warte time_ms ms | ||||
|     time.sleep(time_ms*0.001) | ||||
							
								
								
									
										
											BIN
										
									
								
								apps/bimood
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								apps/bimood
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										6
									
								
								apps/c-src/99-fbdev.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								apps/c-src/99-fbdev.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| Section "Device"   | ||||
|   Identifier "myfb" | ||||
|   Driver "fbdev" | ||||
|   Option "fbdev" "/dev/fb0" | ||||
| EndSection | ||||
|  | ||||
| @@ -6,7 +6,7 @@ | ||||
| #include <assert.h> | ||||
| #include <ctype.h> | ||||
| #include <stdio.h> | ||||
| #include <threads.h> | ||||
| #include <pthread.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| int Nx, Ny; | ||||
| @@ -156,7 +156,7 @@ int PFT_HandlePixelflutMessage(uint8_t *buffer, int size, int sock){ | ||||
|     return begin-(char*)buffer; | ||||
| } | ||||
|  | ||||
| int PFT_HandleClient(void* sock_){ | ||||
| void* PFT_HandleClient(void* sock_){ | ||||
|     int sock = (int)(size_t)sock_; | ||||
|     PFT_ClientThreadCount++; | ||||
|     uint8_t buf[1024]; | ||||
| @@ -172,7 +172,7 @@ int PFT_HandleClient(void* sock_){ | ||||
| } | ||||
|  | ||||
|  | ||||
| int PFT_RunServer(void* _){ | ||||
| void* PFT_RunServer(void* _){ | ||||
|     int client_sock; | ||||
|     socklen_t addr_len; | ||||
|     struct sockaddr_in addr; | ||||
| @@ -220,9 +220,9 @@ int PFT_RunServer(void* _){ | ||||
|     while(1){ | ||||
|         client_sock = accept(server_sock, (struct sockaddr*)&addr, &addr_len); | ||||
|         if(client_sock > 0){ | ||||
|             thrd_t thread; | ||||
|             thrd_create(&thread, PFT_HandleClient, (void*)(size_t)client_sock); | ||||
|             thrd_detach(thread); | ||||
|             pthread_t thread; | ||||
|             pthread_create(&thread, NULL, PFT_HandleClient, (void*)(size_t)client_sock); | ||||
|             pthread_detach(thread); | ||||
|         } | ||||
|     } | ||||
|     close(server_sock); | ||||
| @@ -235,8 +235,8 @@ int main(int argc, char **argv) { | ||||
|     buf = (uint8_t*)malloc(Nx*Ny*3); | ||||
|     port = atoi(argv[3]); | ||||
|     if (port == 0) port = 4444; | ||||
|     thrd_t thread; | ||||
|     thrd_create(&thread, PFT_RunServer, NULL); | ||||
|     pthread_t thread; | ||||
|     pthread_create(&thread, NULL, PFT_RunServer, NULL); | ||||
|  | ||||
|      | ||||
|  | ||||
| @@ -245,4 +245,4 @@ int main(int argc, char **argv) { | ||||
|         usleep(33*1000); | ||||
|  | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								apps/cnoise
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								apps/cnoise
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										61
									
								
								apps/convergence.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										61
									
								
								apps/convergence.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| #!/usr/bin/env python3 | ||||
| import numpy as np | ||||
| import time | ||||
| import os | ||||
| import sys | ||||
| import colorsys | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| N = max(Nx, Ny) | ||||
|  | ||||
| def CpxRandNormal(min, max, N): | ||||
|     mu = (min+max)/2 | ||||
|     sigma = (max-min)/2 | ||||
|     return np.random.normal(mu, sigma, (N, N))+1.0j*np.random.normal(mu, sigma, (N, N)) | ||||
| def CpxRand(min, max, N): | ||||
|     return np.random.uniform(min, max, (N, N))+1.0j*np.random.uniform(min, max, (N, N)) | ||||
|  | ||||
| A = CpxRandNormal(-100, 100, N) | ||||
| B = CpxRand(-1, 1, N)*0.1 | ||||
| C = CpxRand(-1, 1, N) | ||||
|  | ||||
| A_ex = np.linalg.inv(np.eye(N)-B)@C | ||||
|  | ||||
| dir = -1 | ||||
| solve = True | ||||
| t = 0 | ||||
| while True: | ||||
|     t += 0.003 | ||||
|     if solve: | ||||
|         A = 0.9*A+0.1*(B@A+C) | ||||
|     else: | ||||
|         A += CpxRandNormal(0, 0.008, N) | ||||
|     diff = A-A_ex | ||||
|     #angles = (np.angle(diff)+np.pi)/(2*np.pi | ||||
|     #diff = np.abs(diff) | ||||
|     #diff = 1-diff/(1+diff) | ||||
|     a = np.abs(np.real(diff)) | ||||
|     a = a/(a+1) | ||||
|     b = np.abs(np.imag(diff)) | ||||
|     b = b/(b+1) | ||||
|     img = np.zeros((Ny, Nx, 3)) | ||||
|     for x in range(Nx): | ||||
|         for y in range(Ny): | ||||
|             c = colorsys.hsv_to_rgb((t+0.2+a[x, y]*0.2)%1, 1, 0.5*b[x, y]+0.5) | ||||
|             img[y,x,:] = np.array(c)*255 | ||||
|     #img[:,:,0] = np.minimum(np.abs(diff*255).astype(int), 255)[:Ny,:Nx] | ||||
|     out = img.reshape((Nx*Ny*3,)).astype(np.uint8) | ||||
|     #A += np.random.uniform(-0.01, 0.01, (N, N)) | ||||
|  | ||||
|     #print(len(out)) | ||||
|     os.write(1, out.tobytes()) | ||||
|  | ||||
|     if solve and np.sum(np.abs(diff)) <= 0.001*N*N: | ||||
|         solve = False | ||||
|     elif not solve and np.sum(np.abs(diff)) >= 1*N*N: | ||||
|         solve = True | ||||
|  | ||||
|     #os.write(2, b"frame") | ||||
|     #print(angles, diff) | ||||
|  | ||||
|     time.sleep(0.01) | ||||
							
								
								
									
										110
									
								
								apps/digi_clock.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										110
									
								
								apps/digi_clock.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import os | ||||
| import numpy as np | ||||
| import pygame | ||||
| from datetime import datetime | ||||
| import math | ||||
|  | ||||
| # Displaygröße | ||||
| Nx = int(sys.argv[1])  # Breite des Displays (z.B. 80) | ||||
| Ny = int(sys.argv[2])  # Höhe des Displays (z.B. 40) | ||||
|  | ||||
| # Initialize pygame | ||||
| pygame.init() | ||||
| pygame.font.init() | ||||
|  | ||||
| # Pfad zur Pixelfont im Verzeichnis "apps" | ||||
| font_path = os.path.join('.', 'PressStart2P-Regular.ttf')  # Pfad zur Schriftart | ||||
|  | ||||
| # Schriftart mit optimierter Größe laden (z.B. 16px bis 20px) | ||||
| font_size = 16  # Geeignete Schriftgröße wählen | ||||
| font = pygame.font.Font(font_path, font_size) | ||||
|  | ||||
| clock = pygame.time.Clock() | ||||
| time_elapsed = 0  # Zeit-Tracker für den Farbverlauf | ||||
|  | ||||
| # Feste Farbe für den Rand (Türkis) | ||||
| border_color = (64, 224, 208)  # RGB-Werte für Türkis | ||||
|  | ||||
| # Funktion zur Berechnung der RGB-Farbe basierend auf der Zeit und der Position des Zeichens | ||||
| def calculate_color(time_elapsed, position, total_length): | ||||
|     """Berechnet eine RGB-Farbe basierend auf der verstrichenen Zeit und der Position des Zeichens.""" | ||||
|     frequency = 2 * math.pi / total_length  # Frequenz für den Regenbogenverlauf | ||||
|     phase_shift = position * frequency  # Verschiebung der Phase pro Zeichen | ||||
|  | ||||
|     r = int((math.sin(time_elapsed + phase_shift) + 1) * 127.5) | ||||
|     g = int((math.sin(time_elapsed + phase_shift + 2 * math.pi / 3) + 1) * 127.5) | ||||
|     b = int((math.sin(time_elapsed + phase_shift + 4 * math.pi / 3) + 1) * 127.5) | ||||
|  | ||||
|     return (r, g, b) | ||||
|  | ||||
| # Funktion zum Rendern des Rahmens | ||||
| def render_border(display_surface, Nx, Ny, border_color): | ||||
|     """Zeichnet den Rahmen mit einer festen Farbe.""" | ||||
|     # Obere Linie des Rahmens | ||||
|     for x in range(Nx): | ||||
|         display_surface.set_at((x, 0), border_color)  # Oben | ||||
|  | ||||
|     # Rechte Linie des Rahmens | ||||
|     for y in range(1, Ny - 1): | ||||
|         display_surface.set_at((Nx - 1, y), border_color)  # Rechts | ||||
|  | ||||
|     # Untere Linie des Rahmens | ||||
|     for x in range(Nx - 1, -1, -1): | ||||
|         display_surface.set_at((x, Ny - 1), border_color)  # Unten | ||||
|  | ||||
|     # Linke Linie des Rahmens | ||||
|     for y in range(Ny - 2, 0, -1): | ||||
|         display_surface.set_at((0, y), border_color)  # Links | ||||
|  | ||||
| # Funktion zum Zeichnen der Uhrzeit | ||||
| def render_time(display_surface, Nx, Ny, font, current_time, time_elapsed): | ||||
|     """Zeichnet die aktuelle Uhrzeit mittig auf das Display.""" | ||||
|     # Reduzierter Zeichenabstand (85% der Schriftgröße) | ||||
|     character_spacing = font_size * 0.95   | ||||
|     # Breite des gesamten Textes berechnen | ||||
|     text_width = len(current_time) * character_spacing   | ||||
|      | ||||
|     # Horizontale und vertikale Zentrierung | ||||
|     x_offset = (Nx - text_width) // 2   | ||||
|     y_offset = (Ny - font_size) // 2    | ||||
|  | ||||
|     # Zeichnen der Uhrzeit | ||||
|     for i, char in enumerate(current_time): | ||||
|         # Berechne die Farbe für das aktuelle Zeichen | ||||
|         text_color = calculate_color(time_elapsed, i, len(current_time)) | ||||
|         # Rendern des Zeichens | ||||
|         text = font.render(char, True, text_color) | ||||
|         text_rect = text.get_rect(topleft=(x_offset + i * character_spacing, y_offset)) | ||||
|         # Zeichen auf das Display zeichnen | ||||
|         display_surface.blit(text, text_rect) | ||||
|  | ||||
| # Hauptprogramm zur Anzeige der Uhrzeit | ||||
| while True: | ||||
|     # Zeit seit Beginn des Programms | ||||
|     time_elapsed += clock.get_time() / 1000.0  # in Sekunden | ||||
|  | ||||
|     # Aktuelle Zeit abrufen | ||||
|     now = datetime.now() | ||||
|     current_time = now.strftime("%H:%M")  # Uhrzeit im Format HH:MM | ||||
|  | ||||
|     # Ein leeres Display für die Uhrzeit erstellen | ||||
|     display_surface = pygame.Surface((Nx, Ny)) | ||||
|     display_surface.fill((0, 0, 0))  # Hintergrund schwarz | ||||
|  | ||||
|     # Rahmen zeichnen | ||||
|     render_border(display_surface, Nx, Ny, border_color) | ||||
|  | ||||
|     # Uhrzeit zeichnen (Aufruf der neuen Funktion) | ||||
|     render_time(display_surface, Nx, Ny, font, current_time, time_elapsed) | ||||
|  | ||||
|     # Sicherstellen, dass das Bild die korrekten Dimensionen hat und der Framebuffer vollständig ist | ||||
|     out = pygame.surfarray.array3d(display_surface).transpose((1, 0, 2)).astype(np.uint8).tobytes() | ||||
|  | ||||
|     # Framebuffer zum Server senden | ||||
|     os.write(1, out) | ||||
|  | ||||
|     clock.tick(30)  # 30 FPS für flüssigen Farbverlauf | ||||
|  | ||||
							
								
								
									
										101
									
								
								apps/doom_fire_psx2.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										101
									
								
								apps/doom_fire_psx2.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import os | ||||
| import numpy as np | ||||
| import pygame | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| try: | ||||
|     fps = float(sys.argv[3]) | ||||
| except (IndexError, ValueError): | ||||
|     fps = 15 | ||||
|  | ||||
| #fps = 15 | ||||
|  | ||||
| colors = np.array([ | ||||
|     0x0, 0x0, 0x0, | ||||
| #    0x07,0x07,0x07, | ||||
| #    0x1F,0x07,0x07, | ||||
| #    0x2F,0x0F,0x07, | ||||
| #    0x47,0x0F,0x07, | ||||
|     0x57,0x17,0x07, | ||||
| #    0x67,0x1F,0x07, | ||||
| #    0x77,0x1F,0x07, | ||||
| #    0x8F,0x27,0x07, | ||||
|     0x9F,0x2F,0x07, | ||||
| #    0xAF,0x3F,0x07, | ||||
| #    0xBF,0x47,0x07, | ||||
| #    0xC7,0x47,0x07, | ||||
|     0xDF,0x4F,0x07, | ||||
| #    0xDF,0x57,0x07, | ||||
| #    0xDF,0x57,0x07, | ||||
| #    0xD7,0x5F,0x07, | ||||
| #    0xD7,0x5F,0x07, | ||||
|  #   0xD7,0x67,0x0F, | ||||
|  #   0xCF,0x6F,0x0F, | ||||
|  #   0xCF,0x77,0x0F, | ||||
|     0xCF,0x7F,0x0F, | ||||
|  #   0xCF,0x87,0x17, | ||||
|  #   0xC7,0x87,0x17, | ||||
|  #   0xC7,0x8F,0x17, | ||||
|  #   0xC7,0x97,0x1F, | ||||
|  #   0xBF,0x9F,0x1F, | ||||
|  #   0xBF,0x9F,0x1F, | ||||
|  #   0xBF,0xA7,0x27, | ||||
|     0xBF,0xA7,0x27, | ||||
|  #   0xBF,0xAF,0x2F, | ||||
|  #   0xB7,0xAF,0x2F, | ||||
|  #   0xB7,0xB7,0x2F, | ||||
|  #   0xB7,0xB7,0x37, | ||||
|  #   0xCF,0xCF,0x6F, | ||||
|  #   0xDF,0xDF,0x9F, | ||||
|  #   0xEF,0xEF,0xC7, | ||||
|  #   0xFF,0xFF,0xFF | ||||
| ], dtype=np.uint8) | ||||
|  | ||||
| colors = np.reshape(colors, (colors.size//3, 3)) | ||||
|  | ||||
| grid = np.zeros((Ny,Nx), dtype=np.int) | ||||
| gridout = np.zeros((Ny,Nx), dtype=np.int) | ||||
| grid[0,:].fill(colors.shape[0]-1) | ||||
|  | ||||
| clock = pygame.time.Clock() | ||||
|  | ||||
|  | ||||
|  | ||||
| def state2red(c): | ||||
|     return colors[c, 0] | ||||
|  | ||||
| def state2green(c): | ||||
|     return colors[c, 1] | ||||
|  | ||||
| def state2blue(c): | ||||
|     return colors[c, 2] | ||||
|  | ||||
| i = 0 | ||||
|  | ||||
| while True: | ||||
|     i = i + 1 | ||||
|     rnd = np.random.randint(3, size=(Ny, Nx)) | ||||
|  | ||||
|     for px in range(Nx): | ||||
|         for py in range(1, Ny): | ||||
|             #grid[py, px] = max(grid[py-1, px] - 1, 0) # v1 | ||||
|             #grid[py, px] = max(grid[py-1, px] - (rnd[py, px] & 1), 0) # v2 | ||||
|             grid[py, (px - rnd[py, px] + 1) % Nx] = max(grid[py-1, px] - (rnd[py, px] & 1), 0) # v3 | ||||
|  | ||||
|     #if i % 100 == 0: | ||||
|     #    grid[0,:].fill(0) | ||||
|     #elif (i - (colors.shape[0] +10)) % 100 == 0: | ||||
|     #    grid[0,:].fill(colors.shape[0]-1) | ||||
|  | ||||
|     gridup = np.flipud(np.fliplr(grid)) | ||||
|     np.clip(grid + gridup, 0, colors.shape[0]-1, out=gridout) | ||||
|  | ||||
|     #out = np.dstack((state2red(gridout), state2green(gridout), state2blue(gridout), np.full((Ny, Nx), 100, dtype=np.uint8))).astype(np.uint8).tobytes() | ||||
|     out = np.dstack((state2red(gridout), state2green(gridout), state2blue(gridout))).astype(np.uint8).tobytes() | ||||
|      | ||||
|     os.write(1, out) | ||||
|     clock.tick_busy_loop(fps) | ||||
							
								
								
									
										
											BIN
										
									
								
								apps/dualmaze
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								apps/dualmaze
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										68
									
								
								apps/example2.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								apps/example2.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import os | ||||
| import sys | ||||
| import random  | ||||
| import time | ||||
|  | ||||
| # Groesse des Bildschirms bestimmen | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
|  | ||||
| # Bestimme den Parameter | ||||
| time_ms = 100 | ||||
| try: | ||||
|     time_ms = int(sys.argv[3]) | ||||
| except: | ||||
|     pass | ||||
|  | ||||
| # Puffer fuer Pixel erstellen und mit 0 initialisieren | ||||
| buffer = bytearray(b"\x00" * (4 * Nx * Ny)) | ||||
|  | ||||
| curPixel = 0 | ||||
|  | ||||
| while True: | ||||
|     # Zufaellige Pixel waeheln | ||||
|     # rot | ||||
|     x_r = random.randint(0, Nx-1) | ||||
|     y_r = random.randint(0, Ny-1) | ||||
|     i_r = 4*(x_r+Nx*y_r) | ||||
|     # gruen  | ||||
|     x_g = random.randint(0, Nx-1) | ||||
|     y_g = random.randint(0, Ny-1) | ||||
|     i_g = 4*(x_g+Nx*y_g) | ||||
|     # blau | ||||
|     x_b = random.randint(0, Nx-1) | ||||
|     y_b = random.randint(0, Ny-1) | ||||
|     i_b = 4*(x_b+Nx*y_b) | ||||
|     # weiss | ||||
|     x_w = random.randint(0, Nx-1) | ||||
|     y_w = random.randint(0, Ny-1) | ||||
|     i_w = 4*(x_w+Nx*y_w) | ||||
|  | ||||
|     # Pixel in Puffer schreiben | ||||
|     # rot | ||||
|     buffer[i_r+0] = 0xff # Rotanteil | ||||
|     buffer[i_r+1] = 0x00 # Gruenanteil | ||||
|     buffer[i_r+2] = 0x00 # Blauanteil | ||||
|     buffer[i_r+3] = 0x00 | ||||
|     # gruen | ||||
|     buffer[i_g+0] = 0x00 # Rotanteil | ||||
|     buffer[i_g+1] = 0xff # Gruenanteil | ||||
|     buffer[i_g+2] = 0x00 # Blauanteil | ||||
|     buffer[i_g+3] = 0x00 | ||||
|     # blau | ||||
|     buffer[i_b+0] = 0x00 # Rotanteil | ||||
|     buffer[i_b+1] = 0x00 # Gruenanteil | ||||
|     buffer[i_b+2] = 0xff # Blauanteil | ||||
|     buffer[i_b+3] = 0x00 | ||||
|     # weiss | ||||
|     buffer[i_w+0] = 0x00 # Rotanteil | ||||
|     buffer[i_w+1] = 0x00 # Gruenanteil | ||||
|     buffer[i_w+2] = 0x00 # Blauanteil | ||||
|     buffer[i_w+3] = 0xff | ||||
|  | ||||
|     # Zeige den Puffer an | ||||
|     os.write(1, buffer) | ||||
|     # warte time_ms ms | ||||
|     time.sleep(time_ms*0.001) | ||||
							
								
								
									
										42
									
								
								apps/fading_pixels.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										42
									
								
								apps/fading_pixels.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import os | ||||
| import numpy as np | ||||
| import pygame | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| try: | ||||
|     fps = float(sys.argv[3]) | ||||
| except (IndexError, ValueError): | ||||
|     fps = 1.0 | ||||
|  | ||||
|  | ||||
| def point2idx(x,y): | ||||
|     return 3*(x+Nx*y) | ||||
|  | ||||
| def set_pixel_max(buffer, x, y): | ||||
|     idx = point2idx(x,y) | ||||
|     for i in range(3): | ||||
|         buffer[idx+i] = max(0x00, buffer[idx+i]-1) | ||||
|  | ||||
| def set_pixel_rand(buffer, x, y): | ||||
|     idx = point2idx(x,y) | ||||
|     for i in range(3): | ||||
|         buffer[idx+i] = np.random.randint(0x00, 0xff) | ||||
|  | ||||
| clock = pygame.time.Clock() | ||||
| buffer = bytearray(b"\x00"*(3*Nx*Ny)) | ||||
|  | ||||
| i = 0 | ||||
| while True: | ||||
|     i = i + 1 | ||||
|     for px in range(Nx): | ||||
|         for py in range(Ny): | ||||
|             set_pixel_max(buffer, px, py) | ||||
|     for j in range(10): | ||||
|         set_pixel_rand(buffer, np.random.randint(0, Nx), np.random.randint(0, Ny)) | ||||
|         if i > 100: | ||||
|             os.write(1, buffer) | ||||
|             clock.tick_busy_loop(fps) | ||||
							
								
								
									
										78
									
								
								apps/fdtd.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										78
									
								
								apps/fdtd.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| #!/usr/bin/env python | ||||
| # -*- coding: utf-8 -*- | ||||
|  | ||||
| # From the Meep tutorial: plotting permittivity and fields of a bent waveguide | ||||
| from __future__ import division | ||||
|  | ||||
| import meep as mp | ||||
| #import matplotlib.pyplot as plt | ||||
| import os | ||||
| import sys | ||||
| import numpy as np | ||||
| from matplotlib import cm | ||||
| import pygame | ||||
|  | ||||
| #mp.quiet(True) | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| try: | ||||
|     fps = float(sys.argv[3]) | ||||
| except (IndexError, ValueError): | ||||
|     fps = 40 | ||||
|  | ||||
|  | ||||
|  | ||||
| cell = mp.Vector3(8,4,0) | ||||
| geometry = [mp.Block(mp.Vector3(12,1,mp.inf), | ||||
|                      center=mp.Vector3(0,0), | ||||
|                      material=mp.Medium(epsilon=24)) | ||||
|             ]#, | ||||
|             #mp.Block(mp.Vector3(1,5,mp.inf), | ||||
|             #         center=mp.Vector3(1,1), | ||||
|             #         material=mp.Medium(epsilon=12))] | ||||
| #pml_layers = [mp.PML(2.0)] | ||||
| resolution = 10 | ||||
|  | ||||
| sources = [mp.Source(mp.ContinuousSource(frequency=0.15, width=20), # wavelength=2*(11**0.5) | ||||
|                      component=mp.Ez, | ||||
|                      center=mp.Vector3(0,0), | ||||
|                      size=mp.Vector3(0,1)) | ||||
| ] | ||||
|  | ||||
| sim = mp.Simulation(cell_size=cell, | ||||
|                     geometry=geometry, | ||||
|                     sources=sources, | ||||
|                     resolution=resolution) | ||||
|  | ||||
|  | ||||
| buffer = np.empty([80,40]) | ||||
| clock = pygame.time.Clock() | ||||
|  | ||||
| def get_slice(sim): | ||||
|     val = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Ez, arr=buffer) | ||||
|     #plt.figure() | ||||
|     #plt.imshow(val, interpolation='none', cmap='RdBu') | ||||
|     #plt.axis('off') | ||||
|     #plt.show() | ||||
|     out = (val - np.amin(val)) / (np.amax(val) - np.amin(val)) | ||||
|     out = np.transpose(out) # or switch x and y | ||||
|     out = out.ravel() | ||||
|     out = 250*cm.RdBu(out) | ||||
|     out = out[:,0:3] | ||||
|     out = out.ravel() | ||||
|     out = out.astype(np.uint8).tobytes() | ||||
|     os.write(1, out) | ||||
|     clock.tick_busy_loop(fps) | ||||
|  | ||||
| def plot_dielectric(sim): | ||||
|     val = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Dielectric, arr=buffer) | ||||
|     #plt.figure() | ||||
|     #plt.imshow(val, interpolation='none', cmap='RdBu') | ||||
|     #plt.axis('off') | ||||
|     #plt.show() | ||||
|     #print() | ||||
|  | ||||
|  | ||||
| #sim.run(mp.at_beginning(plot_dielectric), mp.at_every(0.6, get_slice), until=200) | ||||
| sim.run(mp.at_every(0.00001, get_slice), until=1000) | ||||
							
								
								
									
										109
									
								
								apps/fibonacci-clock.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										109
									
								
								apps/fibonacci-clock.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| #!/usr/bin/env python3 | ||||
| import sys | ||||
| import os | ||||
| from time import strftime | ||||
| import time | ||||
| from math import ceil | ||||
|  | ||||
| #Nx = int(sys.argv[1]) | ||||
| #Ny = int(sys.argv[2]) | ||||
| #param = sys.argv[3] | ||||
| Nx = 80 | ||||
| Ny = 40 | ||||
|  | ||||
|  | ||||
| buffer = bytearray(b"\x00"*(3*Nx*Ny)) | ||||
|  | ||||
| def SetPixel(x, y, r, g, b): | ||||
|     idx = 3*(x+Nx*y) | ||||
|     buffer[idx+0] = r | ||||
|     buffer[idx+1] = g | ||||
|     buffer[idx+2] = b | ||||
|  | ||||
| def two(r,g,b): | ||||
|     for y in range (1,15): | ||||
|         for x in range (9,23): | ||||
|             SetPixel(x,y,r,g,b) | ||||
|  | ||||
| def three(r,g,b): | ||||
|     for y in range (17,39): | ||||
|         for x in range (9,31): | ||||
|             SetPixel(x,y,r,g,b) | ||||
|  | ||||
| def one(r,g,b): | ||||
|     for y in range (1,7): | ||||
|         for x in range (25,31): | ||||
|             SetPixel(x,y,r,g,b) | ||||
|  | ||||
| def one_one(r,g,b): | ||||
|     for y in range (9,15): | ||||
|         for x in range (25,31): | ||||
|             SetPixel(x,y,r,g,b) | ||||
|  | ||||
| def five(r,g,b): | ||||
|     for y in range (1,39): | ||||
|         for x in range (33,71): | ||||
|             SetPixel(x,y,r,g,b) | ||||
|  | ||||
| def and_gate(hourcol, mincol): | ||||
|     if hourcol and mincol: | ||||
|         return 'y' | ||||
|     if hourcol: | ||||
|         return 'r' | ||||
|     if mincol: | ||||
|         return 'g' | ||||
|     if not hourcol and not mincol: | ||||
|         return 'b' | ||||
|  | ||||
| def get_colsquares(hour, minute): | ||||
|     coldict = { | ||||
|         0: [0, 0, 0, 0, 0], | ||||
|         1: [0, 0, 0, 0, 1], | ||||
|         2: [0, 0, 0, 1, 1], | ||||
|         3: [0, 0, 1, 1, 0], | ||||
|         4: [0, 0, 1, 1, 1], | ||||
|         5: [0, 1, 1, 0, 0], | ||||
|         6: [0, 1, 1, 1, 0], | ||||
|         7: [0, 1, 1, 1, 1], | ||||
|         8: [1, 1, 0, 0, 0], | ||||
|         9: [1, 1, 0, 1, 0], | ||||
|         10: [1, 1, 1, 0, 0], | ||||
|         11: [1, 1, 1, 1, 0], | ||||
|         12: [1, 1, 1, 1, 1] | ||||
|     } | ||||
|  | ||||
|     i = 0 | ||||
|     result = [] | ||||
|     while i < 5: | ||||
|         result.append( and_gate(coldict[hour][i], coldict[minute][i]) ) | ||||
|         i += 1 | ||||
|     return result | ||||
|  | ||||
| def gettime(): | ||||
|     hour = int(strftime('%I')) | ||||
|     minute12 = ceil(int(strftime('%M'))/5.0) | ||||
|     minute = int(strftime('%M')) | ||||
|      | ||||
|     return hour, minute12, minute | ||||
|  | ||||
| while True: | ||||
|     rgbw = { | ||||
|         'r' : (255, 0, 0), | ||||
|         'g' : (0, 255, 0), | ||||
|         'b' : (0, 0, 255), | ||||
|         'y' : (255, 255, 0) | ||||
|         } | ||||
|  | ||||
|     hour, minute12, minute = gettime() | ||||
|     colsq = get_colsquares(hour, minute12) | ||||
|  | ||||
|  | ||||
|     five(rgbw[colsq[0]][0],rgbw[colsq[0]][1],rgbw[colsq[0]][2]) | ||||
|     three(rgbw[colsq[1]][0],rgbw[colsq[1]][1],rgbw[colsq[1]][2]) | ||||
|     two(rgbw[colsq[2]][0],rgbw[colsq[2]][1],rgbw[colsq[2]][2]) | ||||
|     one_one(rgbw[colsq[3]][0],rgbw[colsq[3]][1],rgbw[colsq[3]][2]) | ||||
|     one(rgbw[colsq[4]][0],rgbw[colsq[4]][1],rgbw[colsq[4]][2]) | ||||
|  | ||||
|     os.write(1, buffer) | ||||
|     time.sleep(1) | ||||
|     #grid() | ||||
							
								
								
									
										
											BIN
										
									
								
								apps/flicker
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								apps/flicker
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -13,7 +13,7 @@ Ny = int(sys.argv[2]) | ||||
| PixelsPerFrame = 20 | ||||
| NumLines = 7 | ||||
| LineGenerationRate = 0.2 | ||||
| time_ms = 10 | ||||
| time_ms = 20 | ||||
| try: | ||||
|     time_ms = int(sys.argv[3]) | ||||
| except: | ||||
|   | ||||
							
								
								
									
										81
									
								
								apps/pendlum.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										81
									
								
								apps/pendlum.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| #!/usr/bin/env python3 | ||||
| import numpy as np | ||||
| import sys | ||||
| import os | ||||
| import time | ||||
| import colorsys | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| N = 100 | ||||
| iterations = 2 | ||||
| try: | ||||
|     N = int(sys.argv[3]) | ||||
| except: | ||||
|     pass | ||||
|  | ||||
| def rk4(f, x, dt): | ||||
|     k1 = f(x) | ||||
|     k2 = f(x+k1*dt/2) | ||||
|     k3 = f(x+k2*dt/2) | ||||
|     k4 = f(x+k3*dt) | ||||
|     return x+dt*(k1+2*k2+2*k3+k4)/6.0 | ||||
| dt = 0.08  | ||||
| m = 1 | ||||
| l = 1 | ||||
| g = 1 | ||||
|  | ||||
| def sq(x): return x*x | ||||
|  | ||||
| def rhs(x): | ||||
|     phi1 = x[0] | ||||
|     p1 = x[1] | ||||
|     phi2 = x[2] | ||||
|     p2 = x[3] | ||||
|  | ||||
|     dphi1 = 6/(m*l*l)*(2*p1-3*np.cos(phi1-phi2)*p2)/(16-9*sq(np.cos(phi1-phi2)))  | ||||
|     dphi2 = 6/(m*l*l)*(8*p2-3*np.cos(phi1-phi2)*p1)/(16-9*sq(np.cos(phi1-phi2))) | ||||
|  | ||||
|     dp1 = -0.5*m*l*l*(dphi1*dphi2*np.sin(phi1-phi2)+3*g/l*np.sin(phi1)) | ||||
|     dp2 = -0.5*m*l*l*(-dphi1*dphi2*np.sin(phi1-phi2)+g/l*np.sin(phi2)) | ||||
|     return np.array([dphi1, dp1, dphi2, dp2]) | ||||
|  | ||||
| s = np.array([np.pi+0.1, 0, np.pi-0.1, 0]) | ||||
|  | ||||
| angles = np.linspace(np.pi, np.pi/3, N)+np.random.uniform(-np.pi/6/N, np.pi/6/N, N) | ||||
| angles = np.random.uniform(-np.pi/6, np.pi/3, N)+np.pi | ||||
| states = [np.array([np.pi, 0, a, 0]) for a in angles] | ||||
|  | ||||
| def clamp(x, min_, max_): | ||||
|     return  max(min_, min(max_, x)) | ||||
|  | ||||
| buffer = bytearray(b"\x00"*Nx*Ny*3) | ||||
|  | ||||
| def setpixel(x, y, r, g, b): | ||||
|     xi = int(Nx*(x+1.2)/2.4) | ||||
|     yi = int(Ny*(y+1.2)/2.4) | ||||
|     if xi < 0 or xi >= Nx or yi < 0 or yi >= Ny: | ||||
|         return | ||||
|     idx = xi+Nx*yi | ||||
|     buffer[3*idx+0] = r | ||||
|     buffer[3*idx+1] = g | ||||
|     buffer[3*idx+2] = b | ||||
| timestep = 0 | ||||
| timefac = 0.03 | ||||
| while True: | ||||
|     timestep += 1 | ||||
|     for s, i in zip(states, range(len(states))): | ||||
|         phi1 = s[0] | ||||
|         phi2 = s[2] | ||||
|         x1 = np.sin(phi1)*l | ||||
|         y1 = np.cos(phi1)*l | ||||
|         x2 = np.sin(phi2)*l+x1 | ||||
|         y2 = np.cos(phi2)*l+y1 | ||||
|         h = 0.2*i/N+0*timestep*timefac/iterations | ||||
|         r, g, b = colorsys.hsv_to_rgb(h%1, 1, 1) | ||||
|         setpixel(x2, y2, int(r*255), int(g*255), int(b*255)) | ||||
|         states[i] = rk4(rhs, s, dt/iterations) | ||||
|     if timestep > 10*iterations and timestep % iterations == 0: | ||||
|         #time.sleep(0.01) | ||||
|         os.write(1, buffer) | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								apps/pixelflut
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								apps/pixelflut
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										33
									
								
								apps/plane_wave.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										33
									
								
								apps/plane_wave.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import os | ||||
| import numpy as np | ||||
| import pygame | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| try: | ||||
|     frequency = float(sys.argv[3]) | ||||
| except (IndexError, ValueError): | ||||
|     frequency = 5 | ||||
|  | ||||
| fps = 30 | ||||
| amplitude = 105 | ||||
| offset = 150 | ||||
| t = 0 | ||||
|  | ||||
| x,y = np.meshgrid(np.linspace(0, 2*np.pi * min(1, Nx/Ny), Nx),  np.linspace(0, 2*np.pi * min(1, Ny/Nx), Ny)) | ||||
| kx = x + y | ||||
|  | ||||
| clock = pygame.time.Clock() | ||||
|  | ||||
| while True: | ||||
|     t = t + 1e-3 | ||||
|     R = amplitude * np.sin(kx - 2 * np.pi * frequency * t) + offset | ||||
|     G = amplitude * np.sin(kx - 2 * np.pi * frequency  * t + 2*np.pi/3) + offset | ||||
|     B = amplitude * np.sin(kx - 2 * np.pi * frequency  * t + 4*np.pi/3) + offset | ||||
|  | ||||
|     out = np.dstack((R,G,B)).astype(np.uint8).tobytes() | ||||
|     os.write(1, out) | ||||
|     clock.tick_busy_loop(fps) | ||||
							
								
								
									
										
											BIN
										
									
								
								apps/predprey
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								apps/predprey
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										82
									
								
								apps/quadratic.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										82
									
								
								apps/quadratic.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import numpy as np | ||||
| import os | ||||
| import sys | ||||
| import time | ||||
| import colorsys | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| iterations = 10 | ||||
|  | ||||
| class Slider: | ||||
|     def __init__(self, lo, hi, step, pos=0): | ||||
|         self.lo = lo | ||||
|         self.hi = hi | ||||
|         self.stepSize = step | ||||
|         self.pos = pos | ||||
|         self.dir = 1 | ||||
|      | ||||
|     def step(self): | ||||
|         if self.pos >= self.hi: | ||||
|             self.dir = -1 | ||||
|         elif self.pos <= self.lo: | ||||
|             self.dir = 1 | ||||
|          | ||||
|         self.pos += self.dir * self.stepSize | ||||
|         return self.pos | ||||
|  | ||||
| Sa = Slider(-10, 10, 0.1/iterations, np.random.uniform(-2, 2)) | ||||
| Sb = Slider(-10, 10, 0.2/iterations, np.random.uniform(-2, 2)) | ||||
| Sc = Slider(-10, 10, 0.2/iterations, np.random.uniform(-2, 2)) | ||||
| Sd = Slider(-10, 10, 0.1/iterations, np.random.uniform(-2, 2)) | ||||
| Se = Slider(-10, 10, 0.2/iterations, np.random.uniform(-2, 2)) | ||||
| Sf = Slider(0, 6, 0.05/iterations, 0) | ||||
|  | ||||
| x, y = np.meshgrid( | ||||
|     np.linspace(-4, 4, Nx), | ||||
|     np.linspace(-4, 4, Ny)) | ||||
|  | ||||
| color = 1.0 | ||||
|  | ||||
| img = np.zeros( [Ny, Nx, 3] ) | ||||
|  | ||||
| cr = 1.0 | ||||
| cg = 0.5 | ||||
| cb = 0.25 | ||||
|  | ||||
| step = 0 | ||||
| while True: | ||||
|     a = Sa.step() | ||||
|     b = Sb.step() | ||||
|     c = Sc.step() | ||||
|     d = Sd.step() | ||||
|     e = Se.step() | ||||
|     f = Sf.step() | ||||
|  | ||||
|     Sa.pos += b*0.001 | ||||
|     Sb.pos += c*0.001 | ||||
|     Sc.pos += d*0.001 | ||||
|     Sd.pos += e*0.001 | ||||
|     Se.pos += f*0.001 | ||||
|     Sf.pos += a*0.001 | ||||
|  | ||||
|     curve = (np.abs(a*x**2 + b*x*y + c*y**2 + d*x + e*y + f) <= 1.5)*1 | ||||
|  | ||||
|     cr, cg, cb = colorsys.hsv_to_rgb(color, 1, 1) | ||||
|  | ||||
|     img[:,:,0] = np.where(curve > 0, curve*cr*255, img[:,:,0]) | ||||
|     img[:,:,1] = np.where(curve > 0, curve*cg*255, img[:,:,1]) | ||||
|     img[:,:,2] = np.where(curve > 0, curve*cb*255, img[:,:,2]) | ||||
|  | ||||
|     step += 1 | ||||
|     if step % iterations == 0: | ||||
|         out = img.reshape((Nx*Ny*3,)).astype(np.uint8) | ||||
|         os.write(1, out.tobytes()) | ||||
|         time.sleep(0.01) | ||||
|  | ||||
|     color = (color+0.01/iterations ) % 1 | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										71
									
								
								apps/rps.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										71
									
								
								apps/rps.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import os | ||||
| import numpy as np | ||||
| import pygame | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| try: | ||||
|     frequency = float(sys.argv[3]) | ||||
| except (IndexError, ValueError): | ||||
|     frequency = 5 | ||||
|  | ||||
| fps = 10 | ||||
|  | ||||
| nstates = 5 | ||||
| colors = np.linspace(0, 255, nstates, dtype=np.uint8) | ||||
|  | ||||
| red = np.random.choice(colors, size=(Ny,Nx)) | ||||
| green = np.zeros((Ny, Nx)) | ||||
| blue = np.zeros((Ny, Nx)) | ||||
| grid = np.dstack((red, green, blue)).astype(np.uint8) | ||||
|  | ||||
|  | ||||
| clock = pygame.time.Clock() | ||||
|  | ||||
| def clamp(value, min, max): | ||||
|   if value > max: | ||||
|       return max | ||||
|   elif value < min: | ||||
|       return min | ||||
|   return value | ||||
|  | ||||
|  | ||||
| while True: | ||||
|  | ||||
|   for px in range(Nx): | ||||
|     for py in range(Ny): | ||||
|       statecount = np.zeros(nstates, dtype=np.uint8) | ||||
|       for ix in [-1, 0, 1]: | ||||
|         for iy in [-1, 0, 1]: | ||||
|  | ||||
|           if (px+ix) >= Nx or (px+ix) <= 0 or (py+iy) >= Ny or (py+iy) <= 0: | ||||
|             i = 0 | ||||
|           else: | ||||
|             i = int(grid[py + iy, px + ix, 0] / colors[1]) | ||||
|  | ||||
|           #i = int(grid[(px + ix) % Nx, (py + iy) % Ny, 0] / colors[1]) | ||||
|           #i = int(grid[max(min(px + ix, Nx-1), 0), max(min(py + iy, Ny-1), 0), 0] / colors[1]) | ||||
|           #print(px, py, max(min(px + ix, Nx-1), 0), max(min(py + iy, Ny-1), 0), file=sys.stderr) | ||||
|           statecount[i] = statecount[i] + 1 | ||||
|  | ||||
|       i = int(grid[py, px, 0] / colors[1]) | ||||
|       i_successor = (i+1) % colors.size | ||||
|  | ||||
|       if statecount[i_successor] >= 2: #(2-np.random.randint(0, 2)): | ||||
|         grid[py, px, 0] = colors[i_successor] | ||||
|  | ||||
| #    for i in range(Nx*Ny): | ||||
| #      c1 = clamp(i % Nx - 1, 0, Nx - 1)  | ||||
| #      c2 = clamp(int(i / Nx) - 1, 0, Ny - 1) | ||||
| #      neighbourhood = grid[c1:(c1+3), c2:(c2+3), 0] | ||||
| #      #print(neighbourhood.size, file=sys.stderr) | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|   out = grid.tobytes() | ||||
|   os.write(1, out) | ||||
|   clock.tick_busy_loop(fps) | ||||
							
								
								
									
										67
									
								
								apps/sinic.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										67
									
								
								apps/sinic.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import numpy as np | ||||
| import os | ||||
| import sys | ||||
| import time | ||||
| import colorsys | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| iterations = 2 | ||||
|  | ||||
| class Slider: | ||||
|     def __init__(self, lo, hi, step, pos=0): | ||||
|         self.lo = lo | ||||
|         self.hi = hi | ||||
|         self.stepSize = step | ||||
|         self.pos = pos | ||||
|         self.dir = 1 | ||||
|      | ||||
|     def step(self): | ||||
|         if self.pos >= self.hi: | ||||
|             self.dir = -1 | ||||
|         elif self.pos <= self.lo: | ||||
|             self.dir = 1 | ||||
|          | ||||
|         self.pos += self.dir * self.stepSize | ||||
|         return self.pos | ||||
|  | ||||
| x, y = np.meshgrid( | ||||
|     np.linspace(-2, 2, Nx), | ||||
|     np.linspace(-2, 2, Ny)) | ||||
|  | ||||
| img = np.zeros( [Ny, Nx, 3] ) | ||||
|  | ||||
| Sa = Slider(-3, 3, 0.01, np.random.uniform(-1, 1)) | ||||
| Sb = Slider(-3, 3, 0.01, np.random.uniform(-1, 1)) | ||||
| Sc = Slider(0, 1, 0.005, np.random.uniform(-1, 1)) | ||||
|  | ||||
| Scolor = Slider(0, 1, 0.001/iterations, 0) | ||||
|  | ||||
| step = 0 | ||||
| while True: | ||||
|     a = Sa.step() | ||||
|     b = Sb.step() | ||||
|     c = Sc.step() | ||||
|  | ||||
|     Sa.pos += b*0.001 | ||||
|     Sb.pos += c*0.001 | ||||
|     Sc.pos += a*0.001 | ||||
|  | ||||
|     curve = (np.clip(np.sin(c) + np.sin(np.sin(a*x) + np.cos(b*y)) - np.cos(np.sin(b*x*y) + np.cos(b*x)), 0, 1)) | ||||
|  | ||||
|     cr, cg, cb = colorsys.hsv_to_rgb(Scolor.step(), 1, 1) | ||||
|  | ||||
|     img[:,:,0] = curve*cr*255 | ||||
|     img[:,:,1] = curve*cg*255 | ||||
|     img[:,:,2] = curve*cb*255 | ||||
|  | ||||
|     step += 1 | ||||
|     if step % iterations == 0: | ||||
|         out = img.reshape((Nx*Ny*3,)).astype(np.uint8) | ||||
|         os.write(1, out.tobytes()) | ||||
|         time.sleep(0.01) | ||||
|  | ||||
|  | ||||
|  | ||||
							
								
								
									
										68
									
								
								apps/sinic2.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								apps/sinic2.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import numpy as np | ||||
| import os | ||||
| import sys | ||||
| import time | ||||
| import colorsys | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| iterations = 2 | ||||
|  | ||||
| class Slider: | ||||
|     def __init__(self, lo, hi, step, pos=0): | ||||
|         self.lo = lo | ||||
|         self.hi = hi | ||||
|         self.stepSize = step | ||||
|         self.pos = pos | ||||
|         self.dir = 1 | ||||
|      | ||||
|     def step(self): | ||||
|         if self.pos >= self.hi: | ||||
|             self.dir = -1 | ||||
|         elif self.pos <= self.lo: | ||||
|             self.dir = 1 | ||||
|          | ||||
|         self.pos += self.dir * self.stepSize | ||||
|         return self.pos | ||||
|  | ||||
| x, y = np.meshgrid( | ||||
|     np.linspace(-2, 2, Nx), | ||||
|     np.linspace(-2, 2, Ny)) | ||||
|  | ||||
| img = np.zeros( [Ny, Nx, 3] ) | ||||
|  | ||||
| Sa = Slider(-3, 3, 0.01, np.random.uniform(-1, 1)) | ||||
| Sb = Slider(-3, 3, 0.01, np.random.uniform(-1, 1)) | ||||
| Sc = Slider(0, 1, 0.005, np.random.uniform(-1, 1)) | ||||
|  | ||||
| Scolor = Slider(0, 1, 0.001/iterations, 0) | ||||
|  | ||||
|  | ||||
| step = 0 | ||||
| while True: | ||||
|     a = Sa.step() | ||||
|     b = Sb.step() | ||||
|     c = Sc.step() | ||||
|  | ||||
|     Sa.pos += b*0.001 | ||||
|     Sb.pos += c*0.001 | ||||
|     Sc.pos += a*0.001 | ||||
|  | ||||
|     curve = np.clip(c+np.sin(a*x*x-b*y*y)-np.sin(a*x+b*y)-np.cos(a*b*x*y), 0, 1) | ||||
|  | ||||
|     cr, cg, cb = colorsys.hsv_to_rgb(Scolor.step(), 1, 1) | ||||
|  | ||||
|     img[:,:,0] = curve*cr*255 | ||||
|     img[:,:,1] = curve*cg*255 | ||||
|     img[:,:,2] = curve*cb*255 | ||||
|  | ||||
|     step += 1 | ||||
|     if step % iterations == 0: | ||||
|         out = img.reshape((Nx*Ny*3,)).astype(np.uint8) | ||||
|         os.write(1, out.tobytes()) | ||||
|         time.sleep(0.01) | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -2,24 +2,33 @@ | ||||
|  | ||||
| import os | ||||
| import sys | ||||
| import time | ||||
|  | ||||
|  | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
|  | ||||
| param = 10 | ||||
|  | ||||
| p1 = 20 | ||||
| p2 = 10 | ||||
| try: | ||||
|     param = int(sys.argv[3]) | ||||
|     param = sys.argv[3] | ||||
|     p = param.split(",") | ||||
|     p1 = int(p[0]) | ||||
|     p2 = int(p[1]) | ||||
| except: | ||||
|     pass | ||||
|  | ||||
| buffera = bytearray(b"\x00" * (3 * Nx * Ny)) | ||||
| bufferb = bytearray(b"\xFF" * (3 * Nx * Ny)) | ||||
| cnt = 0 | ||||
|  | ||||
| os.write(2,b"Usage: Parameter: \"20,10\"\n   -> updates every 20*0.01s, every 10th frame is white")  | ||||
| while True: | ||||
|  | ||||
|         os.write(1, buffera) | ||||
|         time.sleep(param*0.01) | ||||
|         os.write(1, bufferb) | ||||
|         time.sleep(param*0.01) | ||||
|         time.sleep(p1*0.01) | ||||
|         if cnt == p2-1: | ||||
|             cnt = 0 | ||||
|             os.write(1, bufferb) | ||||
|             time.sleep(p1*0.01) | ||||
|         cnt += 1 | ||||
|   | ||||
							
								
								
									
										63
									
								
								apps/swifthohenberg.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										63
									
								
								apps/swifthohenberg.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| #!/usr/bin/env python3 | ||||
| import sys | ||||
| import os | ||||
| import numpy as np | ||||
| Nx = int(sys.argv[1]) | ||||
| Ny = int(sys.argv[2]) | ||||
| param = sys.argv[3] | ||||
|  | ||||
| buffer = bytearray(b" "*(3*Nx*Ny)) | ||||
|  | ||||
|  | ||||
| Lx = 32 #128 #Physikalische Laenge des Gebietes in x-Richtung | ||||
| Ly =32 #128#Physikalische Laenge des Gebietes in y-Richtung | ||||
|  | ||||
| x, y = np.meshgrid(np.arange(Nx)* Lx/Nx, np.arange(Ny)* Ly/Ny) #x-Array | ||||
| kx, ky = np.meshgrid(np.fft.fftfreq(Nx,Lx/(Nx*2.0*np.pi)), np.fft.fftfreq(Ny,Ly/(Ny*2.0*np.pi))) | ||||
| ksq = kx*kx + ky*ky | ||||
|  | ||||
| c = 0.0+(np.random.random((Ny,Nx))-0.5)*0.1 | ||||
| eps=0.3 | ||||
| delta=0.0 | ||||
| #eps = 0.1 | ||||
| #delta = 1.0 | ||||
|  | ||||
| t = 0.0 | ||||
| dt = 0.01 | ||||
| T_End = 300000  | ||||
| N_t = int(T_End / dt) | ||||
|  | ||||
| plotEveryNth = 100 | ||||
| ck = np.fft.fft2(c) #FFT(c) | ||||
| # Lineare Terme | ||||
| def rhs_lin(ksq): | ||||
|     result=eps-(1.0-ksq)**2 | ||||
|     return result | ||||
|  | ||||
| Eu=1.0/(1.0-dt*rhs_lin(ksq)) | ||||
| i = 0 | ||||
| def lerp_sat(a, t, b): | ||||
|     v = (1-t)*a+t*b | ||||
|     v = int(v) | ||||
|     if v < 0: | ||||
|         v = 0 | ||||
|     if v > 255: | ||||
|         v = 255 | ||||
|     return v | ||||
|  | ||||
| while True: | ||||
|     i+= 1 | ||||
|     ck=Eu*(ck+dt*(delta*np.fft.fft2(np.fft.ifft2(ck)**2)-np.fft.fft2(np.fft.ifft2(ck)**3))) | ||||
|     c=np.fft.ifft2(ck) | ||||
|     eps = 0.1+0.2*np.cos(i/10000) | ||||
|     delta = np.sin(i/10000) | ||||
|     if(i % plotEveryNth == 0): | ||||
|         myc = c.real | ||||
|         myc = (myc-np.min(myc))/(np.max(myc)-np.min(myc)) | ||||
|         for px in range(Nx): | ||||
|             for py in range(Ny): | ||||
|                 idx = 3*(px+Nx*py) | ||||
|                 buffer[idx+0] = lerp_sat(0xff, myc[py,px], 0x00) | ||||
|                 buffer[idx+1] = lerp_sat(0x00, myc[py,px], 0xff) | ||||
|                 buffer[idx+2] = 0 | ||||
|         os.write(1, buffer) | ||||
							
								
								
									
										111
									
								
								apps/textscroll.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										111
									
								
								apps/textscroll.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import os | ||||
| import sys | ||||
| import pygame | ||||
| import paho.mqtt.client as mqtt | ||||
| import random | ||||
|  | ||||
| class ScrollingTextDisplay: | ||||
|     def __init__(self, width: int, height: int): | ||||
|         pygame.init() | ||||
|         self.width = width | ||||
|         self.height = height | ||||
|         self.screen = pygame.Surface((width, height)) | ||||
|         self.clock = pygame.time.Clock() | ||||
|  | ||||
|         # Liste der Standardtexte | ||||
|         self.default_texts = [ | ||||
|             "Text per MQTT an: mqtt.chaospott.de Topic: test/topic ",  # Hardcodierte IP-Adresse | ||||
|             "Willkommen beim MQTT-Display!", | ||||
|             "Aktuelle Nachrichten hier empfangen.", | ||||
|             "MQTT-Server verbindet...", | ||||
|             "Textnachricht anzeigen...", | ||||
|         ] | ||||
|         self.error_text = "MQTT-Server nicht erreichbar!" | ||||
|         self.text = self.get_random_default_text()  # Zufälligen Standardtext auswählen | ||||
|         self.text_x = width | ||||
|  | ||||
|         # Schriftart 'PressStart2P-Regular' aus dem Verzeichnis 'apps' laden | ||||
|         self.font = pygame.font.Font("PressStart2P-Regular.ttf", 16)  # Schriftgröße anpassen | ||||
|  | ||||
|         # Fest codierte MQTT-Einstellungen | ||||
|         self.mqtt_broker = "mqtt.chaospott.de"  # Beispiel IP-Adresse des MQTT-Brokers | ||||
|         self.topic = "test/topic"       # Beispiel Topic | ||||
|         self.mqtt_client = mqtt.Client() | ||||
|         self.mqtt_client.on_connect = self.on_connect | ||||
|         self.mqtt_client.on_message = self.on_message | ||||
|         self.mqtt_client.on_disconnect = self.on_disconnect | ||||
|  | ||||
|         # Versuche die Verbindung aufzubauen | ||||
|         self.connect_to_mqtt() | ||||
|  | ||||
|         # Zähler für die angezeigte Nachricht | ||||
|         self.message_display_count = 0 | ||||
|  | ||||
|     def get_random_default_text(self): | ||||
|         """Wählt zufällig einen Standardtext aus der Liste aus.""" | ||||
|         return random.choice(self.default_texts) | ||||
|  | ||||
|     def connect_to_mqtt(self): | ||||
|         try: | ||||
|             self.mqtt_client.connect(self.mqtt_broker) | ||||
|             self.mqtt_client.loop_start() | ||||
|         except Exception as e: | ||||
|             print(f"Verbindungsfehler zu MQTT-Server: {e}") | ||||
|             self.text = self.error_text  # Setze Fehlertext für die Anzeige | ||||
|             self.text_x = self.width  # Text von rechts starten | ||||
|  | ||||
|     def on_connect(self, client, userdata, flags, rc): | ||||
|         if rc == 0: | ||||
|             client.subscribe(self.topic) | ||||
|             self.text = self.get_random_default_text()  # Setze einen zufälligen Standardtext | ||||
|         else: | ||||
|             print(f"Fehler beim Verbinden mit MQTT: Code {rc}") | ||||
|             self.text = self.error_text | ||||
|  | ||||
|     def on_disconnect(self, client, userdata, rc): | ||||
|         if rc != 0: | ||||
|             print("Verbindung zum MQTT-Server verloren. Erneuter Verbindungsversuch...") | ||||
|             self.text = self.error_text | ||||
|             self.text_x = self.width  # Fehlertext von rechts starten | ||||
|             # Erneut die Verbindung aufbauen | ||||
|             self.connect_to_mqtt() | ||||
|  | ||||
|     def on_message(self, client, userdata, msg): | ||||
|         self.text = msg.payload.decode("utf-8") if msg.payload.decode("utf-8") else self.get_random_default_text() | ||||
|         self.text_x = self.width  # Text von rechts starten | ||||
|         self.message_display_count = 3  # Setze den Zähler auf 3 | ||||
|  | ||||
|     def draw_text(self): | ||||
|         self.screen.fill((0, 0, 0))  # Bildschirm leeren | ||||
|         text_surface = self.font.render(self.text, True, (255, 255, 255)) | ||||
|         text_width = text_surface.get_width()  # Breite des Textes ermitteln | ||||
|         text_y = (self.height - text_surface.get_height()) // 2  # Y-Position zentrieren | ||||
|         self.screen.blit(text_surface, (self.text_x, text_y))  # Text zentriert zeichnen | ||||
|  | ||||
|     def display(self): | ||||
|         while True: | ||||
|             text_surface = self.font.render(self.text, True, (255, 255, 255)) | ||||
|             text_width = text_surface.get_width()  # Breite des Textes ermitteln | ||||
|  | ||||
|             self.text_x -= 1  # Text nach links verschieben | ||||
|             if self.text_x < -text_width:  # Wenn der Text komplett verschwunden ist | ||||
|                 self.text_x = self.width  # Text von rechts neu starten | ||||
|                 # Falls der Text leer ist, setze Standardtext oder Fehlertext | ||||
|                 if self.message_display_count > 0: | ||||
|                     self.message_display_count -= 1 | ||||
|                 else: | ||||
|                     self.text = self.get_random_default_text()  # Setze zurück auf zufälligen Standardtext | ||||
|  | ||||
|             self.draw_text() | ||||
|             os.write(1, pygame.image.tostring(self.screen, "RGB")) | ||||
|             self.clock.tick(30) | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     Nx = int(sys.argv[1])  # Breite des Displays | ||||
|     Ny = int(sys.argv[2])  # Höhe des Displays | ||||
|  | ||||
|     display = ScrollingTextDisplay(Nx, Ny) | ||||
|     display.display() | ||||
|  | ||||
							
								
								
									
										23
									
								
								apps/wget.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										23
									
								
								apps/wget.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| #!/bin/bash | ||||
| #pkill -9 wget | ||||
| if [ ! -d /tmp/video ]; then | ||||
| 	mkdir /tmp/video | ||||
| fi | ||||
| rm -f /tmp/video/* | ||||
|  | ||||
| if [[ ${3} =~ .*gif$ ]]; then | ||||
| 	wget -O "/tmp/video/$(basename ${3})" "${3}" && ffmpeg -loglevel -8 -re -ignore_loop 0 -i "/tmp/video/$(basename ${3})" -pix_fmt rgb24 -vf "scale=(iw*sar)*min(${1}/(iw*sar)\,${2}/ih):ih*min(${1}/(iw*sar)\,${2}/ih), pad=${1}:${2}:(${1}-iw*min(${1}/iw\,${2}/ih))/2:(${2}-ih*min(${1}/iw\,${2}/ih))/2" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe - | ||||
| elif [[ ${3} =~ .*(jpg|jpeg|png|bmp|tiff|webp)$ ]]; then | ||||
| 	wget -q -O "/tmp/video/$(basename ${3})" "${3}"; | ||||
| 	ffmpeg -i "/tmp/video/$(basename ${3})" -pix_fmt rgb24 -vf "scale=${1}x${2}" -vcodec rawvideo -f image2pipe - | tee /tmp/video/matrix | ||||
| 	while true; do | ||||
| 		cat /tmp/video/matrix | ||||
| 		sleep 1; | ||||
| 	done | ||||
| else | ||||
|  | ||||
|  | ||||
| 	wget -O - -q "${3}" | tee "/tmp/video/$(basename ${3})" | ffmpeg -loglevel -8 -f alsa default -re -i - -pix_fmt rgb24 -vf "scale=${1}x${2}" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe - | ||||
|        	ffmpeg -loglevel -8 -f alsa default -stream_loop -1 -re -i "/tmp/video/$(basename ${3})" -pix_fmt rgb24 -vf "scale=${1}x${2}" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe - | ||||
|  | ||||
| fi | ||||
							
								
								
									
										75
									
								
								apps/wolfram.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										75
									
								
								apps/wolfram.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import sys | ||||
| import os | ||||
| import numpy as np | ||||
| import pygame | ||||
| import time | ||||
|  | ||||
| Nx = int(sys.argv[1])  # Breite des Displays | ||||
| Ny = int(sys.argv[2])  # Höhe des Displays | ||||
| fps = 30 | ||||
|  | ||||
| # Liste der Wolfram-Regeln, die angezeigt werden sollen | ||||
| rules = [30, 90, 110, 60, 150, 126, 45, 105, 75, 214] | ||||
| pause_duration = 5  # Dauer der Pause zwischen den Mustern in Sekunden | ||||
|  | ||||
| # Umwandlung der Regelnummer in eine Binärliste | ||||
| def get_rule_bin(rule_number): | ||||
|     return np.array([int(x) for x in np.binary_repr(rule_number, width=8)]) | ||||
|  | ||||
| # Regel für die nächste Generation | ||||
| def next_gen(current_gen, rule_bin): | ||||
|     padded = np.pad(current_gen, (1,), mode='constant') | ||||
|     new_gen = np.zeros_like(current_gen) | ||||
|      | ||||
|     for i in range(1, len(padded) - 1): | ||||
|         neighborhood = padded[i-1:i+2] | ||||
|         index = 7 - (neighborhood[0] * 4 + neighborhood[1] * 2 + neighborhood[2]) | ||||
|         new_gen[i-1] = rule_bin[index] | ||||
|      | ||||
|     return new_gen | ||||
|  | ||||
| # Funktion, um eine zufällige Farbe zu erzeugen | ||||
| def random_color(): | ||||
|     return np.random.randint(0, 256, size=3) | ||||
|  | ||||
| # Haupt-Loop für die Animation | ||||
| clock = pygame.time.Clock() | ||||
|  | ||||
| while True: | ||||
|     for rule_number in rules: | ||||
|         rule_bin = get_rule_bin(rule_number) | ||||
|  | ||||
|         # Initialisiere ein leeres Display (alle Zellen sind tot) | ||||
|         cells = np.zeros((Ny, Nx), dtype=np.uint8) | ||||
|  | ||||
|         # Setze die mittlere Zelle der ersten Reihe auf 1 (Zelle ist lebendig) | ||||
|         cells[0, Nx // 2] = 1 | ||||
|  | ||||
|         # Erstelle einen Farbarray für die Zellen | ||||
|         color_map = np.zeros((Ny, Nx, 3), dtype=np.uint8) | ||||
|  | ||||
|         # Animation Schleife | ||||
|         for row in range(1, Ny): | ||||
|             cells[row] = next_gen(cells[row - 1], rule_bin) | ||||
|  | ||||
|             # Setze die Farben für die lebendigen Zellen | ||||
|             color_map[row] = np.where(cells[row][:, None], random_color(), 0)  # Zufällige Farbe für lebende Zellen | ||||
|  | ||||
|             # Erstelle das Bild aus den Zellen | ||||
|             image = np.zeros((Ny, Nx, 3), dtype=np.uint8) | ||||
|             for r in range(Ny): | ||||
|                 for c in range(Nx): | ||||
|                     if cells[r, c]: | ||||
|                         image[r, c] = color_map[r, c] | ||||
|  | ||||
|             # Schreibe das Bild in den Output-Stream | ||||
|             os.write(1, image.tobytes()) | ||||
|  | ||||
|             # Warte für die nächste Frame | ||||
|             clock.tick(fps) | ||||
|  | ||||
|         # Pause von 5 Sekunden nach jedem Muster | ||||
|         time.sleep(pause_duration) | ||||
|  | ||||
| @@ -1,6 +1,7 @@ | ||||
| #!/bin/bash | ||||
| export PATH="$PATH:/home/deckensteuerung/.config/bin" | ||||
| youtube-dl -f 'worst[abr>=96]' --no-progress --output - ${3}  | ffmpeg -f alsa default -re -i - -pix_fmt rgb24 -vf "scale=${1}x${2}" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe - | ||||
| yt-dlp --no-progress --output - ${3}  | ffmpeg -f alsa default -re -i - -pix_fmt rgb24 -vf "scale=${1}x${2}" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe - | ||||
| #youtube-dl -f 'worst[abr>=96]' --no-progress --output - ${3}  | ffmpeg -f alsa default -re -i - -pix_fmt rgb24 -vf "scale=${1}x${2}" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe - | ||||
| #youtube-dl --no-progress --output - ${3}  | ffmpeg -re -i - -pix_fmt rgb24 -vf "scale=${1}x${2}" -sws_flags bicubic -sws_dither bayer -vcodec rawvideo -f image2pipe - | ||||
|  | ||||
| exit 0 | ||||
|   | ||||
							
								
								
									
										76
									
								
								config.py
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								config.py
									
									
									
									
									
								
							| @@ -5,7 +5,7 @@ ScreenX = 80 | ||||
| #height | ||||
| ScreenY = 40 | ||||
|  | ||||
| DefaultBrightness = 1.0 | ||||
| DefaultBrightness = 0.6 | ||||
|  | ||||
| Serial = "/dev/ttyACM0" | ||||
|  | ||||
| @@ -15,6 +15,7 @@ NoDataTimeout = 40 | ||||
| LogLevel = logging.DEBUG | ||||
|  | ||||
| UseGui = True | ||||
| GuiFPS = 20 | ||||
| GuiScaleFactor = 15 | ||||
|  | ||||
| WebHost = "0.0.0.0" | ||||
| @@ -22,26 +23,53 @@ WebPort = 8000 | ||||
|  | ||||
| # first app is always running as default     | ||||
| Apps = [ | ||||
|     {"guiname": "Lines", "name": "lines", "cmd": "apps/lines.py", "persistent": False}, | ||||
|      | ||||
|  | ||||
|     {"name": "backlight", "cmd": "apps/backlight.py", "white": True}, | ||||
|  | ||||
|     {"guiname": "Lines", "name": "lines", "cmd": "./lines.py", "persistent": False, "path": "./apps/"}, | ||||
|     {"guiname": "Wolfram", "name": "wolfram", "cmd": "./wolfram.py", "persistent": False, "path": "./apps/"}, | ||||
|     {"guiname": "Digi Clock", "name": "digiclock", "cmd": "./digi_clock.py", "persistent": False, "path": "./apps/"}, | ||||
|     {"guiname": "Text Scroller MQTT", "name": "textscroll", "cmd": "./textscroll.py", "persistent": False, "path": "./apps/"}, | ||||
|     {"guiname": "Flicker", "name": "flicker", "cmd": "apps/flicker"}, | ||||
|  | ||||
|     {"guiname": "Pixelflut", "name": "pixelflut", "cmd": "apps/pixelflut", "persistent": True}, | ||||
|     {"guiname": "Pong", "name": "pong", "cmd": "apps/pong.py"}, | ||||
|     # {"guiname": "Pong", "name": "pong", "cmd": "apps/pong.py"}, | ||||
|     {"guiname": "YoutubeDL", "name": "youtubedl", "cmd": "apps/youtubedl.sh", "persistent": False}, | ||||
|     {"guiname": "Show Framebuffer", "name": "fbcp", "cmd": ["apps/fbcp", "/dev/fb0"]}, | ||||
|     # {"guiname": "Show Framebuffer", "name": "fbcp", "cmd": ["apps/fbcp", "/dev/fb0"]}, | ||||
|     {"guiname": "Strobo", "name": "strobo", "cmd": "apps/strobo.py"}, | ||||
|     {"guiname": "Beispiel", "name": "example", "cmd": "apps/example.py"}, | ||||
|     # {"guiname": "Beispiel", "name": "example", "cmd": "apps/example.py"}, | ||||
|     # {"guiname": "Beispiel2", "name": "example2", "cmd": "apps/example2.py", "white": True}, | ||||
|     {"guiname": "Fibonacci Clock", "name": "fibonacci-clock", "cmd": "apps/fibonacci-clock.py"}, | ||||
|     {"guiname": "Wget Video/Gif/Images", "name": "wget", "cmd": "apps/wget.sh", "persistent": False}, | ||||
|  | ||||
|  | ||||
|     # juergen/pixelfoo | ||||
|     {"guiname": "Colored noise", "name": "cnoise", "cmd": "apps/cnoise", "persistent": False}, | ||||
|     {"guiname": "Dual Moodlight", "name": "bimood", "cmd": "apps/bimood", "persistent": False}, | ||||
|     {"guiname": "Maze", "name": "maze", "cmd": "apps/maze", "persistent": False}, | ||||
|     {"guiname": "Dual Maze", "name": "dualmaze", "cmd": "apps/dualmaze", "persistent": False, "persistent": False}, | ||||
|     {"guiname": "Predator & Prey", "name": "predprey", "cmd": "apps/predprey", "persistent": False}, | ||||
|     {"guiname": "Congress noise", "name": "cnoise", "cmd": "pixelfoo/target/release/cnoise", "persistent": False}, | ||||
|     {"guiname": "Game of Life", "name": "life", "cmd": "pixelfoo/target/release/life", "persistent": False}, | ||||
|     {"guiname": "Matrix Code", "name": "matrix-code", "cmd": "pixelfoo/target/release/matrix-code", "persistent": False}, | ||||
|     {"guiname": "Lorenz Attractor", "name": "lorenz", "cmd": "pixelfoo/target/release/lorenz", "persistent": False}, | ||||
|     {"guiname": "Dual Moodlight", "name": "bimood", "cmd": "pixelfoo/target/release/bimood", "persistent": False}, | ||||
|     {"guiname": "Maze", "name": "maze", "cmd": "pixelfoo/target/release/maze", "persistent": False}, | ||||
|     {"guiname": "Dual Maze", "name": "dualmaze", "cmd": "pixelfoo/target/release/dualmaze", "persistent": False, "persistent": False}, | ||||
|     {"guiname": "Predator & Prey", "name": "predprey", "cmd": "pixelfoo/target/release/predprey", "persistent": False}, | ||||
|  | ||||
|     # { "guiname": "Beat Saber Ceiling", "name": "beatsaberceiling", "cmd": "./beatsaberceiling.py", "path": "apps/beatsaberceiling" }, | ||||
|  | ||||
|     # mathpixel | ||||
|     {"guiname": "Structure formation", "name": "swifthohenberg", "cmd": "apps/swifthohenberg.py", "persistent": False}, | ||||
|     {"guiname": "Quadratisch", "name": "quadratic", "cmd": "apps/quadratic.py"}, | ||||
|     {"guiname": "Pendel", "name": "pendulum", "cmd": "apps/pendlum.py"}, | ||||
|     {"guiname": "Konvergenz", "name": "convergence", "cmd": "apps/convergence.py"}, | ||||
|     {"guiname": "Sinic", "name": "sinic", "cmd": "apps/sinic.py"}, | ||||
|     {"guiname": "Sinic 2", "name": "sinic2", "cmd": "apps/sinic2.py"}, | ||||
|  | ||||
|     # pixelthud | ||||
|     {"guiname": "Fading Pixels", "name": "fadingpxls", "cmd": "apps/fading_pixels.py", "persistent": False}, | ||||
|     {"guiname": "Plane Wave", "name": "planewave", "cmd": "apps/plane_wave.py", "persistent": False}, | ||||
|     {"guiname": "Rock-paper-scissors-spock-lizard", "name": "rps", "cmd": "apps/rps.py", "persistent": False}, | ||||
|     {"guiname": "Doom Fire", "name": "doomfire", "cmd": "apps/doom_fire_psx2.py", "persistent": False}, | ||||
|     # {"guiname": "Maxwell FDTD", "name": "fdtd", "cmd": "apps/fdtd.py", "persistent": False}, | ||||
|  | ||||
|     #{"guiname": "Fibonacci Clock", "name": "fibonacci-clock", "cmd": "apps/fibonacci-clock.py"}, | ||||
|      | ||||
|     #{"guiname": "Stream", "name": "stream", "cmd": "apps/stream.sh", "persistent": False}, | ||||
|     #{"guiname": "Wget Video/Gif/Images", "name": "wget", "cmd": "apps/wget.sh", "persistent": False}, | ||||
|     #{"guiname": "Tetris", "name": "tetris", "cmd": "apps/deckentetris/deckentetris.py", "persistent": False}, | ||||
| @@ -53,14 +81,14 @@ Apps = [ | ||||
| ]    | ||||
|  | ||||
| # load additional apps from config/ | ||||
| import os | ||||
| import os.path | ||||
| configs = os.listdir("configs/") | ||||
| import importlib | ||||
| for config in configs: | ||||
|     file, ext = os.path.splitext(os.path.basename(config)) | ||||
|     if ext != ".py" or file[0] == "_": | ||||
|         continue | ||||
|     modname = "configs."+file | ||||
|     lib = importlib.import_module(modname) | ||||
|     Apps += lib.Apps | ||||
| # import os | ||||
| # import os.path | ||||
| # configs = os.listdir("configs/") | ||||
| # import importlib | ||||
| # for config in configs: | ||||
| #     file, ext = os.path.splitext(os.path.basename(config)) | ||||
| #     if ext != ".py" or file[0] == "_": | ||||
| #         continue | ||||
| #     modname = "configs."+file | ||||
| #     lib = importlib.import_module(modname) | ||||
| #     Apps += lib.Apps | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								filter/test.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								filter/test.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 2.1 KiB | 
| @@ -4,9 +4,10 @@ | ||||
|         <title>Pixelserver Interface</title> | ||||
|     </head> | ||||
|      | ||||
|     <body> | ||||
|         <h1>Andreas <i>DEBUG</i> Interface</h1> | ||||
|     <body style="display: grid; grid-template-columns: auto auto auto;"> | ||||
|         <h1 style="grid-column: 1 / 4; text-align: center;">Andreas <i>production-ready</i> Interface</h1> | ||||
|  | ||||
|         <div> | ||||
|         <h2>Kommando:</h2> | ||||
|         <form id='in' onSubmit="return request()"> | ||||
|             <select id="list"></select> | ||||
| @@ -19,17 +20,49 @@ | ||||
|             <input id="brightness" value=1.0 /><br/> | ||||
|             <button id="sendbrightness">Setzen</button> | ||||
|         </form> | ||||
|  | ||||
|     </div> | ||||
|     <div style="border-left: solid 1px; padding-left: 10px;"> | ||||
|         <h2>Gamma:</h2> | ||||
|         <form id='gammeform' onSubmit="return setgamma()"> | ||||
|             Rot: <input id="gammar" value=2.8 /><br/> | ||||
|             Grün: <input id="gammag" value=2.65 /><br/> | ||||
|             Blau: <input id="gammab" value=2.65 /><br/> | ||||
|             Weiß: <input id="gammaw" value=2.65 /><br/> | ||||
|             <button id="sendgamma">Setzen</button> | ||||
|         </form> | ||||
|  | ||||
|         <h2>Flip:</h2> | ||||
|         <form id="flipform" onSubmit="return setFlip()"> | ||||
|             <input id="flipx" type="checkbox" /> Flip X <br/> | ||||
|             <input id="flipy" type="checkbox" /> Flip Y <br/> | ||||
|             <button id="sendflip">Setzen</button> | ||||
|         </form> | ||||
|  | ||||
|         <h2>Filterimage:</h2> | ||||
|         <form id="filteform" onSubmit="return setFilter()"> | ||||
|             <input id="filtername" value="test"></intput><br/> | ||||
|             <button id="filterflip">Setzten</button> | ||||
|         </form> | ||||
|  | ||||
|         <h2>Filter expression:</h2> | ||||
|         <form id="filterexprform" onSubmit="return setFilterExpr()"> | ||||
|             <input id="filterexpr" value="0.5+0.25*sin(x/3+t)"></intput><br/> | ||||
|             <button>Setzten</button> | ||||
|         </form> | ||||
|     </div> | ||||
|     <div  style="border-left: solid 1px; padding-left: 10px; width: 600px;"> | ||||
|         <h2>Crash Log:</h2> | ||||
|         <form id="crashlogform" onSubmit="return enableCrashLog()"> | ||||
|             <button>start</button> | ||||
|         </form> | ||||
|         <textarea readonly id='crashlogs' style="width: 500px; height: 300px; display: none;"></textarea> | ||||
|  | ||||
|         <h2>Log:</h2> | ||||
|         <textarea readonly id='logs' style="width: 500px; height: 500px;"></textarea> | ||||
|         <form id="logform" onSubmit="return enableLog()"> | ||||
|             <button>start</button> | ||||
|         </form> | ||||
|         <textarea readonly id='logs' style="width: 500px; height: 300px; display: none;"></textarea> | ||||
|     </div> | ||||
|         <script> | ||||
|             function getRaw(from, callback){ | ||||
|                 var xhttp = new XMLHttpRequest(); | ||||
| @@ -105,7 +138,8 @@ | ||||
|                 let r = document.getElementById('gammar').value; | ||||
|                 let g = document.getElementById('gammag').value; | ||||
|                 let b = document.getElementById('gammab').value; | ||||
|                 let url = "/setgamma/" + r+"/"+g+"/"+b; | ||||
|                 let w = document.getElementById('gammaw').value; | ||||
|                 let url = "/setgamma/" + r+"/"+g+"/"+b+"/"+w; | ||||
|                 getRaw(url, function test(){}); | ||||
|                 return false; | ||||
|             } | ||||
| @@ -117,13 +151,61 @@ | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             function setFlip(){ | ||||
|                 let x = document.getElementById('flipx').checked; | ||||
|                 let y = document.getElementById('flipy').checked; | ||||
|                 console.log(x); | ||||
|                 console.log(y); | ||||
|                 getRaw("/filter/flipx/" + x, function test(){}); | ||||
|                 getRaw("/filter/flipy/" + y, function test(){}); | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             function setFilter(){ | ||||
|                 let i = document.getElementById('filtername').value; | ||||
|                 let url = "/filter/img/" + i; | ||||
|                 getRaw(url, function test(){}); | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|              | ||||
|  | ||||
|             function setFilterExpr(){ | ||||
|                 let expr = document.getElementById('filterexpr').value; | ||||
|                 let url = "/filter/expr/"; | ||||
|                 post(url, {"expr": expr}); | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             function updateLog(){ | ||||
|                 getRaw("/apps/log", function(text){ | ||||
|                     document.getElementById('logs').innerText = text; | ||||
|                     document.getElementById('logs').value = text; | ||||
|                 }); | ||||
|             } | ||||
|             updateLog(); | ||||
|             setInterval(updateLog, 1000); | ||||
|  | ||||
|             function updateCrashLog(){ | ||||
|                 getRaw("/apps/crashlog", function(text){ | ||||
|                     document.getElementById('crashlogs').value = text; | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             function enableCrashLog(){ | ||||
|                 document.getElementById("crashlogform").style.display = "none"; | ||||
|                 document.getElementById("crashlogs").style.display = "block"; | ||||
|                  | ||||
|                 updateCrashLog(); | ||||
|                 setInterval(updateCrashLog, 1000); | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             function enableLog(){ | ||||
|                 document.getElementById("logform").style.display = "none"; | ||||
|                 document.getElementById("logs").style.display = "block"; | ||||
|                 updateLog(); | ||||
|                 setInterval(updateLog, 1000); | ||||
|                 return false; | ||||
|             } | ||||
|              | ||||
|  | ||||
|             getJSON("/apps/list", populateForm); | ||||
|  | ||||
|   | ||||
							
								
								
									
										252
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										252
									
								
								main.py
									
									
									
									
									
								
							| @@ -12,7 +12,10 @@ import time | ||||
| import sys | ||||
| import logging | ||||
| import math | ||||
|  | ||||
| import numpy as np | ||||
| import string | ||||
| from collections import OrderedDict | ||||
| import scipy.misc | ||||
| logging.basicConfig(filename='pixelserver.log', level=config.LogLevel) | ||||
| running = True | ||||
|  | ||||
| @@ -71,6 +74,16 @@ class LogReader(threading.Thread): | ||||
|         logging.info("LogReader closed") | ||||
|     def stop(self): | ||||
|         self.running = False | ||||
|      | ||||
| class Frame: | ||||
|     def __init__(self, buffer, channels=3): | ||||
|         self.buffer = buffer | ||||
|         self.created = time.time() | ||||
|         self.channels = channels | ||||
|     def clone(self): | ||||
|         f = Frame(self.buffer+0, self.channels) | ||||
|         f.created = self.created | ||||
|         return f | ||||
|  | ||||
| ######################################################################## | ||||
| #                                  GUI                                 # | ||||
| @@ -84,6 +97,7 @@ if config.UseGui: | ||||
|             self.cv = threading.Condition() | ||||
|             self.datasource = datasource.addListener(self.cv) | ||||
|         def run(self): | ||||
|             last_frame = time.time() | ||||
|             logging.info("Starting GUI") | ||||
|             sf = config.GuiScaleFactor | ||||
|             screen = pygame.display.set_mode((sf*config.ScreenX, sf*config.ScreenY)) | ||||
| @@ -93,14 +107,26 @@ if config.UseGui: | ||||
|                     pass | ||||
|                 with self.cv: | ||||
|                     self.cv.wait() | ||||
|                     data = self.datasource.getData() | ||||
|                 screen.fill((0, 255, 0)) | ||||
|                 for x in range(config.ScreenX): | ||||
|                     for y in range(config.ScreenY): | ||||
|                         i = x+y*config.ScreenX | ||||
|                         color = (data[i*3+0], data[i*3+1], data[i*3+2]) | ||||
|                         pygame.draw.rect(screen, color, pygame.Rect(sf*x, sf*y, sf, sf)) | ||||
|                     frame = self.datasource.getData() | ||||
|                 screen.fill((0, 0, 0)) | ||||
|                 if frame.channels == 3: | ||||
|                     for x in range(config.ScreenX): | ||||
|                         for y in range(config.ScreenY): | ||||
|                             color = (frame.buffer[y, x, 0], frame.buffer[y, x, 1], frame.buffer[y, x, 2]) | ||||
|                             pygame.draw.rect(screen, color, pygame.Rect(sf*x, sf*y, sf, sf)) | ||||
|                 elif frame.channels == 4: | ||||
|                     for x in range(config.ScreenX): | ||||
|                         for y in range(config.ScreenY): | ||||
|                             w = frame.buffer[y, x, 3]//2 | ||||
|                             color = (frame.buffer[y, x, 0]//2+w, frame.buffer[y, x, 1]//2+w, frame.buffer[y, x, 2]//2+w) | ||||
|                             pygame.draw.rect(screen, color, pygame.Rect(sf*x, sf*y, sf, sf)) | ||||
|                 #logging.debug("Time to gui: "+str(time.time()-frame.created)) | ||||
|                 pygame.display.flip() | ||||
|                 if time.time() < last_frame+1/config.GuiFPS: | ||||
|                     time.sleep(time.time()-(last_frame+1/config.GuiFPS)) | ||||
|                     #time.sleep(0.01) | ||||
|                 last_frame = time.time() | ||||
|  | ||||
|             logging.info("Closing GUI") | ||||
|         def join(self): | ||||
|             with self.cv: | ||||
| @@ -128,19 +154,26 @@ class SerialWriter(threading.Thread): | ||||
|                     logging.info("Serial Opened") | ||||
|                 with self.cv: | ||||
|                     self.cv.wait(timeout = 1/30) | ||||
|                     data = self.datasource.getData() | ||||
|                     frame = self.datasource.getData() | ||||
|                     data = frame.buffer.reshape((config.ScreenX*config.ScreenY*frame.channels,)).astype(np.uint8).tobytes() | ||||
|                     if self.updateGamma: | ||||
|                         buf = bytearray(b"\x00")*3*256 | ||||
|                         buf = bytearray(b"\x00")*4*256 | ||||
|                         for i in range(256): | ||||
|                             apply = lambda x, g: max(0, min(255, int(math.pow(x/255, g)*255))) | ||||
|                             buf[i]     = apply(i, self.r) | ||||
|                             buf[i+256] = apply(i, self.g) | ||||
|                             buf[i+512] = apply(i, self.b) | ||||
|                             buf[i+512+256] = apply(i, self.w) | ||||
|                         ser.write(b"\x02") | ||||
|                         ser.write(buf) | ||||
|                         self.updateGamma = False | ||||
|                 ser.write(b"\01") | ||||
|                 ser.write(data) | ||||
|                 if frame.channels == 3: | ||||
|                     ser.write(b"\01") | ||||
|                     ser.write(data) | ||||
|                 elif frame.channels == 4: | ||||
|                     ser.write(b"\03") | ||||
|                     ser.write(data) | ||||
|                 logging.debug("Time to gui: "+str(time.time()-frame.created)) | ||||
|                 ser.flush() | ||||
|             except Exception as e: | ||||
|                 if ser != None: | ||||
| @@ -154,9 +187,9 @@ class SerialWriter(threading.Thread): | ||||
|         with self.cv: | ||||
|             self.cv.notify_all() | ||||
|         super().join() | ||||
|     def setGamma(self, r, g, b): | ||||
|     def setGamma(self, r, g, b, w): | ||||
|         with self.cv: | ||||
|             self.r, self.g, self.b = r, g, b | ||||
|             self.r, self.g, self.b,  self.w = r, g, b, w | ||||
|             self.updateGamma = True | ||||
|             self.cv.notify_all() | ||||
|  | ||||
| @@ -164,31 +197,37 @@ class SerialWriter(threading.Thread): | ||||
| #                                   App                                # | ||||
| ######################################################################## | ||||
| class App(threading.Thread): | ||||
|     def __init__(self, cmd, param, listener, is_persistent): | ||||
|     def __init__(self, cmd, param, listener, is_persistent, is_white=False, path="."): | ||||
|         super().__init__() | ||||
|         #start app | ||||
|         if type(cmd) != list: | ||||
|             cmd = [cmd,] | ||||
|         args = cmd+[str(config.ScreenX), str(config.ScreenY), param] | ||||
|         self.app = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) | ||||
|         self.app = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, cwd=path) | ||||
|         self.last_update = time.time() | ||||
|         self.cv = threading.Condition() | ||||
|         self.watchdog = WatchDog(lambda: self.isAppTimedOut(), lambda: self.terminateApp()) | ||||
|         self.watchdog.start() | ||||
|         self.logreader = LogReader(self) | ||||
|         self.logreader.start() | ||||
|         self.datasource = DataSource(b"\x00"*config.ScreenX*config.ScreenY*3) | ||||
|         self.datasource = DataSource(Frame(np.zeros((config.ScreenY, config.ScreenX, 3)))) | ||||
|         self.running = True | ||||
|         self.listener = listener | ||||
|         self.is_persistent = is_persistent | ||||
|         self.is_white = is_white | ||||
|     def run(self): | ||||
|         while running and self.running and self.alive(): | ||||
|             oshandle = self.app.stdout.fileno() | ||||
|             try: | ||||
|                 data = os.read(oshandle, config.ScreenX*config.ScreenY*3) | ||||
|                 assert len(data) == config.ScreenX*config.ScreenY*3 | ||||
|                 bytes = 4 if self.is_white else 3 | ||||
|                 data = os.read(oshandle, config.ScreenX*config.ScreenY*bytes) | ||||
|                 assert len(data) == config.ScreenX*config.ScreenY*bytes | ||||
|                 buffer = np.frombuffer(data, dtype=np.uint8, count=config.ScreenX*config.ScreenY*bytes) | ||||
|                 buffer = buffer.reshape((config.ScreenY, config.ScreenX, bytes)) | ||||
|                  | ||||
|                 frame = Frame(buffer, channels=bytes) | ||||
|                 self.last_update = time.time() | ||||
|                 self.datasource.pushData(data) | ||||
|                 self.datasource.pushData(frame) | ||||
|             except Exception as e: | ||||
|                 logging.debug("Exception in App.run") | ||||
|         with self.listener: | ||||
| @@ -197,6 +236,8 @@ class App(threading.Thread): | ||||
|         self.logreader.stop() | ||||
|         self.watchdog.join() | ||||
|         self.logreader.join() | ||||
|         self.app.wait() | ||||
|         logging.debug("App stopped") | ||||
|     def alive(self): | ||||
|         return self.app.poll() == None | ||||
|     def stop(self): | ||||
| @@ -206,6 +247,8 @@ class App(threading.Thread): | ||||
|         self.app.stderr.close() | ||||
|         self.watchdog.stop() | ||||
|         self.logreader.stop() | ||||
|         self.app.wait() | ||||
|         logging.debug("App stopped") | ||||
|     def getLog(self): | ||||
|         return self.logreader.getLog() | ||||
|     def terminateApp(self): | ||||
| @@ -220,16 +263,17 @@ class App(threading.Thread): | ||||
| class AppRunner(threading.Thread): | ||||
|     def __init__(self): | ||||
|         super().__init__() | ||||
|         self.last_crashlog = "" | ||||
|         self.currentApp = -1 | ||||
|         self.requestedApp = 0 | ||||
|         self.intensity = config.DefaultBrightness | ||||
|         self.app = None | ||||
|         self.cv = threading.Condition() | ||||
|         self.param = "" | ||||
|         self.datasource = DataSource(b"\x00"*config.ScreenX*config.ScreenY*3) | ||||
|         self.datasource = DataSource(Frame(np.zeros((config.ScreenY, config.ScreenX, 3)))) | ||||
|         self.serial = SerialWriter(self.datasource) | ||||
|         self.serial.start() | ||||
|         self.persistent_apps = {} | ||||
|         self.filters = OrderedDict() | ||||
|         #start persistent apps | ||||
|         for app, i in zip(config.Apps, range(len(config.Apps))): | ||||
|             if app["persistent"]: | ||||
| @@ -245,34 +289,41 @@ class AppRunner(threading.Thread): | ||||
|         logging.info("Requesting app: "+str(app)) | ||||
|     def startApp(self, i, param=""): | ||||
|         app = config.Apps[i] | ||||
|         newapp = App(app["cmd"], param, self.cv, is_persistent=app["persistent"]) | ||||
|         newapp = App(app["cmd"], param, self.cv, is_persistent=app["persistent"], is_white=app["white"], path=app["path"]) | ||||
|         newapp.datasource.addListener(self.cv) | ||||
|         newapp.start() | ||||
|         if app["persistent"]: | ||||
|             self.persistent_apps[self.currentApp] = newapp | ||||
|           self.persistent_apps[self.currentApp] = newapp | ||||
|         return newapp | ||||
|     def updateApp(self): | ||||
|         if self.app != None and not self.app.is_persistent: | ||||
|         try: | ||||
|           if self.app != None and not self.app.is_persistent: | ||||
|             self.app.stop() | ||||
|         self.currentApp = self.requestedApp | ||||
|         if (self.currentApp in self.persistent_apps.keys()  | ||||
|             and self.persistent_apps[self.currentApp].alive()): | ||||
|             self.app = self.persistent_apps[self.currentApp] | ||||
|         else: | ||||
|           self.currentApp = self.requestedApp | ||||
|           if (self.currentApp in self.persistent_apps.keys()  | ||||
|               and self.persistent_apps[self.currentApp].alive()): | ||||
|                 self.app = self.persistent_apps[self.currentApp] | ||||
|           else: | ||||
|             self.app = self.startApp(self.requestedApp, self.param) | ||||
|         except FileNotFoundError as e: | ||||
|           print(e) | ||||
|     def run(self): | ||||
|         logging.info("Starting Apprunner") | ||||
|         while running: | ||||
|             with self.cv: | ||||
|                 if self.app == None or not self.app.alive(): | ||||
|                     if self.app != None: | ||||
|                         self.last_crashlog = self.app.getLog() | ||||
|                     self.requestedApp = 0    | ||||
|                 if self.requestedApp != None: | ||||
|                     self.updateApp() | ||||
|                     self.requestedApp = None | ||||
|                 data = bytearray(self.app.datasource.getData()) | ||||
|                 for i in range(len(data)): | ||||
|                     data[i] = int(data[i]*self.intensity) | ||||
|                 self.datasource.pushData(data) | ||||
|                 frame = self.app.datasource.getData().clone() | ||||
|                 #logging.debug("Runner in time: "+str(time.time()-frame.created)) | ||||
|                 for _, f in self.filters.items(): | ||||
|                     frame.buffer = f(frame.buffer) | ||||
|                 #logging.debug("Runner out  time: "+str(time.time()-frame.created)) | ||||
|                 self.datasource.pushData(frame) | ||||
|                 self.cv.wait() | ||||
|         self.serial.join() | ||||
|         if config.UseGui: | ||||
| @@ -282,8 +333,77 @@ class AppRunner(threading.Thread): | ||||
|         if self.app == None: | ||||
|             return "" | ||||
|         return self.app.getLog() | ||||
|     def setGamma(self, r, g, b): | ||||
|         self.serial.setGamma(r, g, b) | ||||
|     def setGamma(self, r, g, b, w): | ||||
|         self.serial.setGamma(r, g, b, w) | ||||
|     def setFilter(self, name, filter): | ||||
|         self.filters[name] = filter | ||||
|     def removeFilter(self, name): | ||||
|         if name in self.filters.keys(): | ||||
|             del self.filters[name] | ||||
|  | ||||
| ######################################################################## | ||||
| #                           Filter Api                                 # | ||||
| ######################################################################## | ||||
| def MakeBrightnessFilter(intensity): | ||||
|     def filter(img): | ||||
|         return (img*intensity).astype(np.uint8) | ||||
|     return filter | ||||
|  | ||||
| def FlipXFilter(intensity): | ||||
|     return intensity[:,::-1,:] | ||||
|  | ||||
| def FlipYFilter(intensity): | ||||
|     return intensity[::-1,:,:] | ||||
|  | ||||
| def MakeBrightnessImageFilter(name): | ||||
|     img = scipy.misc.imread("filter/"+name+".png", flatten=True)/255 | ||||
|     #img = np.transpose(img) | ||||
|     def filter(intensity): | ||||
|         intensity = intensity.astype(float) | ||||
|         for i in range(intensity.shape[2]): | ||||
|             intensity[:,:,i] *= img | ||||
|         return intensity.astype(np.uint8) | ||||
|     return filter | ||||
|  | ||||
| def strings(str): | ||||
|     allowed_chars = string.ascii_letters+string.digits+"+-*/()." | ||||
|     i = 0 | ||||
|     outlist = [] | ||||
|     while i != len(str): | ||||
|         if str[i] not in allowed_chars: | ||||
|             raise Exception("Unexpected char "+str[i]) | ||||
|         if str[i] not in string.ascii_letters: | ||||
|             i+=1 | ||||
|             continue | ||||
|         out = "" | ||||
|         while i != len(str) and str[i] in string.ascii_letters+string.digits: | ||||
|             out += str[i] | ||||
|             i+=1 | ||||
|         outlist.append(out) | ||||
|     return outlist | ||||
|  | ||||
| def eval_safer(expr, x, y, t): | ||||
|     symbols = {"x": x, "y": y, "t": t,  | ||||
|                "sin": np.sin, "cos": np.cos, "exp": np.exp, "tan": np.tan} | ||||
|     strs = strings(expr) | ||||
|     for s in strs: | ||||
|         if s not in symbols.keys(): | ||||
|             raise Exception("unexpected symbol: "+s) | ||||
|     return eval(expr, {}, symbols) | ||||
|      | ||||
| def MakeBrightnessExprFilter(expr): | ||||
|     t0 = time.time() | ||||
|     x, y = np.meshgrid(np.arange(config.ScreenX), np.arange(config.ScreenY)) | ||||
|     eval_safer(expr, 0, 0, 0) | ||||
|     def filter(intensity): | ||||
|         t = time.time()-t0 | ||||
|         intensity = intensity.astype(float) | ||||
|         filter = 0*x+eval_safer(expr, x, y, t) | ||||
|         filter = np.clip(np.nan_to_num(filter), 0, 1) | ||||
|         for i in range(intensity.shape[2]): | ||||
|             intensity[:,:,i] *= filter | ||||
|         return intensity.astype(np.uint8) | ||||
|     return filter | ||||
|  | ||||
| ######################################################################## | ||||
| #                              Web Api                                 # | ||||
| @@ -336,6 +456,10 @@ def apps_start(name, param): | ||||
| def apps_log(): | ||||
|     return runner.getLog() | ||||
|  | ||||
| @route("/apps/crashlog") | ||||
| def apps_log(): | ||||
|     return runner.last_crashlog | ||||
|  | ||||
| @route("/apps/running")  | ||||
| def  apps_running(): | ||||
|     return config.Apps[runner.currentApp]["name"] | ||||
| @@ -344,22 +468,56 @@ def  apps_running(): | ||||
| def index(): | ||||
|     return bottle.static_file("index.html", root='html') | ||||
|  | ||||
| @route("/setgamma/<r>/<g>/<b>") | ||||
| def setGamma(r, g, b): | ||||
| @route("/setgamma/<r>/<g>/<b>/<w>") | ||||
| def setGamma(r, g, b, w): | ||||
|     r = float(r) | ||||
|     g = float(g) | ||||
|     b = float(b) | ||||
|     runner.setGamma(r, g, b) | ||||
|     w = float(w) | ||||
|     runner.setGamma(r, g, b, w) | ||||
|     return "ok" | ||||
|  | ||||
| @route("/setbrightness/<i>") | ||||
| def setGamma(i): | ||||
| def setIntensity(i): | ||||
|     i = float(i) | ||||
|     if i < 0 or i > 1: | ||||
|         return "bad_value" | ||||
|     runner.intensity = i | ||||
|     runner.setFilter("0_intensity", MakeBrightnessFilter(i)) | ||||
|     return "ok" | ||||
|  | ||||
| @route("/filter/flipx/<do>") | ||||
| def flipx(do): | ||||
|     if do == "true": | ||||
|         runner.setFilter("1_flipx", FlipXFilter) | ||||
|     else: | ||||
|         runner.removeFilter("1_flipx") | ||||
|     return "ok" | ||||
|  | ||||
| @route("/filter/flipy/<do>") | ||||
| def flipy(do): | ||||
|     if do == "true": | ||||
|         runner.setFilter("1_flipy", FlipYFilter) | ||||
|     else: | ||||
|         runner.removeFilter("1_flipy") | ||||
|     return "ok" | ||||
|  | ||||
| @route("/filter/img/<name>") | ||||
| def setfilter(name): | ||||
|     if name == "none": | ||||
|         runner.removeFilter("3_imgfilter") | ||||
|     else: | ||||
|         runner.setFilter("3_imgfilter", MakeBrightnessImageFilter(name)) | ||||
|     return "ok" | ||||
| @post("/filter/expr/") | ||||
| def filter_expr(): | ||||
|     expr = request.forms.get('expr') | ||||
|     if expr == "" or expr == "none": | ||||
|         runner.removeFilter("5_brightnessfunction") | ||||
|     else: | ||||
|         runner.setFilter("5_brightnessfunction", MakeBrightnessExprFilter(expr)) | ||||
|     return "ok" | ||||
|      | ||||
|  | ||||
| ######################################################################## | ||||
| #                              Startup                                 # | ||||
| ######################################################################## | ||||
| @@ -369,15 +527,21 @@ for app in config.Apps: | ||||
|         app["persistent"] = False | ||||
|     if "guiname" not in app.keys(): | ||||
|         app["guiname"] = app["name"] | ||||
|     if "white" not in app.keys(): | ||||
|         app["white"] = False | ||||
|     if "path" not in app.keys(): | ||||
|         app["path"] = "." | ||||
|     cmd = app["cmd"] | ||||
|     #remove non existing apps | ||||
|     if type(cmd) == str and not os.path.isfile(cmd): | ||||
|         config.Apps.remove(app) | ||||
|         logging.warning("Removed app "+app["name"]) | ||||
|     #if type(cmd) == str and not os.path.isfile(cmd): | ||||
|         #config.Apps.remove(app) | ||||
|         #logging.warning("Removed app "+app["name"]) | ||||
|  | ||||
|  | ||||
| runner = AppRunner() | ||||
| runner.start() | ||||
|  | ||||
| #runner.setFilter("5_crazy", MakeBrightnessExprFilter("0.5+0.25*sin(x/3)/x")) | ||||
| run(host=config.WebHost, port=config.WebPort) | ||||
|  | ||||
| ######################################################################## | ||||
|   | ||||
| @@ -39,17 +39,17 @@ if hash cargo 2>/dev/null; then | ||||
|     cp -f external/pixelfoo/target/release/dualmaze apps/ | ||||
| fi | ||||
|  | ||||
| echo "Getting mathpixel" | ||||
| mkdir -p external | ||||
| pushd external | ||||
| if [ ! -d "mathpixel" ]; then | ||||
|     git clone https://git.chaospott.de/andreas/mathpixel.git | ||||
| fi | ||||
| pushd mathpixel | ||||
| git pull | ||||
| bash setup.sh | ||||
| popd | ||||
| popd | ||||
| #echo "Getting mathpixel" | ||||
| #mkdir -p external | ||||
| #pushd external | ||||
| #if [ ! -d "mathpixel" ]; then | ||||
| #    git clone https://git.chaospott.de/andreas/mathpixel.git | ||||
| #fi | ||||
| #pushd mathpixel | ||||
| #git pull | ||||
| #bash setup.sh | ||||
| #popd | ||||
| #popd | ||||
|  | ||||
| echo "Getting pixelthud" | ||||
| mkdir -p external | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 T
					T