FW_LED_System_Monitor/drawing.py

216 lines
6.5 KiB
Python
Raw Normal View History

2024-08-17 20:49:21 +00:00
# Built In Dependencies
import time
import math
import threading
# Internal Dependencies
from commands import Commands, send_command
# External Dependencies
import numpy as np
import serial # pyserial
from serial.tools import list_ports
# This table represents the 3x3 grid of LEDs to be drawn for each fill ratio
lookup_table = np.array(
[
[
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
],
[
[0, 0, 0],
[0, 1, 0],
[0, 0, 0]
],
[
[0, 1, 0],
[0, 1, 0],
[0, 0, 0]
],
[
[0, 1, 1],
[0, 1, 0],
[0, 0, 0]
],
[
[0, 1, 1],
[0, 1, 1],
[0, 0, 0]
],
[
[0, 1, 1],
[0, 1, 1],
[0, 0, 1]
],
[
[0, 1, 1],
[0, 1, 1],
[0, 1, 1]
],
[
[0, 1, 1],
[0, 1, 1],
[1, 1, 1]
],
[
[0, 1, 1],
[1, 1, 1],
[1, 1, 1]
],
[
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]
]
]
)
lightning_bolt = np.array( [[0,0,0,0,0,0,0], # 0
[0,0,0,0,0,1,0], # 1
[0,0,0,0,1,1,0], # 2
[0,0,0,1,1,0,0], # 3
[0,0,1,1,1,0,0], # 4
[0,1,1,1,0,0,0], # 5
[0,1,1,1,1,1,0], # 6
[0,0,0,1,1,1,0], # 7
[0,0,1,1,1,0,0], # 8
[0,0,1,1,0,0,0], # 9
[0,1,1,0,0,0,0], #10
[0,1,0,0,0,0,0], #11
[0,0,0,0,0,0,0]],#12
dtype=bool).T
# Correct table orientation for visual orientation when drawn
for i in range(lookup_table.shape[0]):
lookup_table[i] = lookup_table[i].T
def spiral_index(fill_ratio):
return int(round(fill_ratio * 9.999999 - 0.5))
# Takes up 15 rows, 7 columns, starting at 1,1
def draw_cpu(grid, cpu_values, fill_value):
for i, v in enumerate(cpu_values):
column_number = i % 2
row_number = i // 2
fill_grid = lookup_table[spiral_index(v)]
grid[1+column_number*4:4+column_number*4, 1+row_number*4:4+row_number*4] = fill_grid * fill_value
# Takes up 2 rows, 7 columns, starting at 17,1
def draw_memory(grid, memory_ratio, fill_value):
lit_pixels = 7 * 2 * memory_ratio
pixels_bottom = int(round(lit_pixels / 2))
pixels_top = int(round((lit_pixels - 0.49) / 2))
grid[1:1+pixels_top,17] = fill_value
grid[1:1+pixels_bottom,18] = fill_value
# Takes up 13 rows, 7 columns, starting at 21,1
def draw_battery(grid, battery_ratio, battery_plugged, fill_value, battery_low_thresh = 0.07, battery_low_flash_time = 2, charging_pulse_time = 3):
lit_pixels = int(round(13 * 7 * battery_ratio))
pixels_base = lit_pixels // 7
remainder = lit_pixels % 7
if battery_ratio <= battery_low_thresh and not battery_plugged:
if time.time() % battery_low_flash_time * 2 < battery_low_flash_time: # This will flash the battery indicator if too low
return
for i in range(7):
pixels_col = pixels_base
if i < remainder:
pixels_col += 1
grid[i+1,33-pixels_col:33] = fill_value
if battery_plugged:
pulse_amount = math.sin(time.time() / charging_pulse_time)
grid[1:8,20:33][lightning_bolt] -= np.rint(fill_value + 10 * pulse_amount).astype(int)
indices = grid[1:8,20:33] < 0
grid[1:8,20:33][indices] = -grid[1:8,20:33][indices]
def draw_borders_left(grid, border_value):
# Fill in the borders
# Cpu vertical partitions
grid[4, :16] = border_value
# Cpu horizontal partitions
grid[:, 4] = border_value
grid[:, 8] = border_value
grid[:, 12] = border_value
grid[:, 16] = border_value
# Memory bottom partition
grid[:, 19] = border_value
# Outer Edge borders
grid[:, 0] = border_value # Top
grid[0, :] = border_value # Left
grid[8, :] = border_value # Right
grid[:, 33] = border_value # Bottom
def draw_borders_right(grid, border_value):
# Fill in the borders
# Middle Partition borders
grid[:, 16] = border_value
grid[4, :] = border_value
# Outer Edge borders
grid[:, 0] = border_value # Top
grid[0, :] = border_value # Left
grid[8, :] = border_value # Right
grid[:, 33] = border_value # Bottom
def draw_bar(grid, bar_ratio, bar_value, bar_x_offset = 1,draw_at_bottom = True):
bar_width = 3
bar_height = 16
lit_pixels = int(round(bar_height * bar_width * bar_ratio))
pixels_base = lit_pixels // bar_width
remainder = lit_pixels % bar_width
for i in range(bar_width):
pixels_col = pixels_base
if i < remainder:
pixels_col += 1
if draw_at_bottom:
grid[bar_x_offset+i,33-pixels_col:33] = bar_value
else:
grid[bar_x_offset+i,1:1+pixels_col] = bar_value
def draw_to_LEDs(s, grid):
for i in range(grid.shape[0]):
params = bytearray([i]) + bytearray(grid[i, :].tolist())
send_command(s, Commands.StageCol, parameters=params)
send_command(s, Commands.FlushCols)
def init_device(location = "1-4.2"):
try:
# VID = 1234
# PID = 5678
device_list = list_ports.comports()
for device in device_list:
if device.location and device.location.startswith(location):
s = serial.Serial(device.device, 115200)
return s
except Exception as e:
print(e)
class DrawingThread(threading.Thread):
def __init__(self, port_location, input_queue):
2024-08-17 20:49:21 +00:00
super().__init__()
self.daemon = True
self.port_location = port_location
self.serial_port = init_device(self.port_location)
2024-08-17 20:49:21 +00:00
self.input_queue = input_queue
def run(self):
while True:
try:
grid = self.input_queue.get()
draw_to_LEDs(self.serial_port, grid)
except Exception as e:
print(f"Error in DrawingThread: {e}")
del self.serial_port
time.sleep(1.0)
self.serial_port = init_device(self.port_location)
2024-08-17 20:49:21 +00:00