Implement notetaking app, ST7796 display with touch support, audio beep navigation, and video streaming

This commit is contained in:
Adolfo Reyna
2026-06-08 15:04:36 -04:00
parent 070390355e
commit 3356e5d4a2
30 changed files with 3983 additions and 71 deletions
+60 -4
View File
@@ -5,13 +5,14 @@ import time
class MCPServer:
"""A lightweight JSON-RPC HTTP server implementing Model Context Protocol (MCP) endpoints."""
def __init__(self, display, led, battery, sensor, rtc, ble):
def __init__(self, display, led, battery, sensor, rtc, ble, vstream=None):
self.display = display
self.led = led
self.battery = battery
self.sensor = sensor
self.rtc = rtc
self.ble = ble
self.vstream = vstream
self.sock = None
self.active_led_mode = "off" # static, breath, rainbow, off
@@ -128,7 +129,7 @@ class MCPServer:
"tools": [
{
"name": "clear_screen",
"description": "Clear the 400x300 screen to white (0) or black (1).",
"description": "Clear the 480x320 screen to white (0) or black (1).",
"inputSchema": {
"type": "object",
"properties": {
@@ -144,8 +145,8 @@ class MCPServer:
"type": "object",
"properties": {
"text": {"type": "string", "description": "The message to display"},
"x": {"type": "integer", "description": "X coordinate (0-390)"},
"y": {"type": "integer", "description": "Y coordinate (0-290)"},
"x": {"type": "integer", "description": "X coordinate (0-470)"},
"y": {"type": "integer", "description": "Y coordinate (0-310)"},
"size": {"type": "integer", "enum": [1, 2], "description": "Text scale (1=normal, 2=large)"}
},
"required": ["text", "x", "y"]
@@ -297,6 +298,21 @@ class MCPServer:
},
"required": ["url", "filename"]
}
},
{
"name": "get_video_streaming_instructions",
"description": "Get detailed instructions and sample Python code to stream video directly into the RLCD screen using TCP or UDP.",
"inputSchema": {
"type": "object",
"properties": {
"protocol": {"type": "string", "enum": ["tcp", "udp", "both"], "description": "The streaming protocol to query (default 'both')"}
}
}
},
{
"name": "get_stream_stats",
"description": "Get real-time device-side performance and frame-rate statistics for the TCP/UDP video stream.",
"inputSchema": {"type": "object", "properties": {}}
}
]
},
@@ -568,5 +584,45 @@ class MCPServer:
else:
raise RuntimeError(f"Failed to download file from '{url}'.")
elif name == "get_video_streaming_instructions":
protocol = str(args.get("protocol", "both")).lower()
instructions = [
"### RP2350 TFT Video Streaming Instructions",
"Dimensions: 400x300 (decoded and centered automatically on the 480x320 screen), 1-bit monochrome (Floyd-Steinberg dithered).",
"Frame Buffer Size: 15,000 bytes. The host must convert and map standard pixels into the specific RLCD hardware buffer layout before sending.",
"Mapping logic (Python):",
" def map_to_rlcd(pil_img):",
" img_1bit = pil_img.convert('1', dither=1)",
" px = img_1bit.load()",
" buf = bytearray(15000)",
" for y in range(300):",
" for x in range(400):",
" if px[x, y]:",
" inv_y = 299 - y",
" bx = x // 2",
" by = inv_y // 4",
" idx = bx * 75 + by",
" lx, ly = x % 2, inv_y % 4",
" bit = 7 - (ly * 2 + lx)",
" buf[idx] |= (1 << bit)",
" return buf"
]
if protocol in ("tcp", "both"):
instructions.append("\n**TCP Streaming (Port 8081):**")
instructions.append("Open a TCP connection to the device's IP on port 8081 and send consecutive 15,000-byte frame blocks.")
if protocol in ("udp", "both"):
instructions.append("\n**UDP Streaming / Broadcast (Port 8082):**")
instructions.append("Split the 15,000-byte frame into 15 chunks of 1,000 bytes each. Send each chunk as a 1002-byte packet: byte 0 = frame_id (0-255), byte 1 = chunk_idx (0-14), bytes 2..1001 = chunk payload. Send to port 8082 (unicast or broadcast).")
return "\n".join(instructions)
elif name == "get_stream_stats":
if self.vstream is None:
return json.dumps({"error": "Video stream server not initialized."})
return json.dumps(self.vstream.get_stats())
else:
raise ValueError(f"Unknown tool: {name}")