#!/usr/bin/env python3 """ Test Touchscreen Calibration This script demonstrates and tests the touchscreen calibration. It displays a simple interface where you can tap anywhere on the screen, and it will show both the raw touch coordinates and calibrated coordinates. Usage: python3 test_calibration.py [--virtual] """ import asyncio import argparse import sys import os from PIL import Image, ImageDraw, ImageFont # Add src to path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../src')) from dreader_hal.display.it8951 import IT8951DisplayDriver from dreader_hal.touch.ft5xx6 import FT5xx6TouchDriver from dreader_hal.types import GestureType, RefreshMode class CalibrationTester: """Simple UI for testing calibration.""" def __init__(self, width: int, height: int): self.width = width self.height = height self.touch_history = [] # List of (x, y) tuples self.max_history = 10 def create_screen(self, calibrated: bool, last_touch: tuple = None, raw_coords: tuple = None) -> Image.Image: """ Create test screen showing calibration status and touch points. Args: calibrated: Whether calibration is loaded last_touch: Last calibrated touch coordinates (x, y) raw_coords: Last raw touch coordinates (x, y) Returns: PIL Image """ image = Image.new('L', (self.width, self.height), color=255) draw = ImageDraw.Draw(image) try: font_title = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 28) font_text = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20) except: font_title = ImageFont.load_default() font_text = ImageFont.load_default() # Title title = "Touch Calibration Test" bbox = draw.textbbox((0, 0), title, font=font_title) text_width = bbox[2] - bbox[0] draw.text(((self.width - text_width) // 2, 20), title, fill=0, font=font_title) # Calibration status if calibrated: status = "Status: Calibration ACTIVE" status_color = 0 else: status = "Status: NO CALIBRATION (using raw coordinates)" status_color = 128 bbox = draw.textbbox((0, 0), status, font=font_text) text_width = bbox[2] - bbox[0] draw.text(((self.width - text_width) // 2, 60), status, fill=status_color, font=font_text) # Instructions instruction = "Tap anywhere on the screen" bbox = draw.textbbox((0, 0), instruction, font=font_text) text_width = bbox[2] - bbox[0] draw.text(((self.width - text_width) // 2, 100), instruction, fill=0, font=font_text) # Draw crosshairs at last touch if last_touch: x, y = last_touch # Draw crosshairs draw.line([x - 20, y, x + 20, y], fill=0, width=2) draw.line([x, y - 20, x, y + 20], fill=0, width=2) draw.ellipse([x - 5, y - 5, x + 5, y + 5], fill=0, outline=0) # Show coordinates coord_text = f"Calibrated: ({x}, {y})" draw.text((20, 140), coord_text, fill=0, font=font_text) if raw_coords: raw_x, raw_y = raw_coords raw_text = f"Raw: ({raw_x}, {raw_y})" draw.text((20, 170), raw_text, fill=128, font=font_text) # Calculate offset offset_x = x - raw_x offset_y = y - raw_y offset_text = f"Offset: ({offset_x:+d}, {offset_y:+d})" draw.text((20, 200), offset_text, fill=128, font=font_text) # Draw touch history for i, (hx, hy) in enumerate(self.touch_history): alpha = int(255 * (i + 1) / len(self.touch_history)) draw.ellipse([hx - 3, hy - 3, hx + 3, hy + 3], fill=alpha, outline=alpha) # Draw border draw.rectangle([10, 10, self.width - 10, self.height - 10], outline=0, width=2) # Instructions at bottom help_text = "Swipe left to exit" bbox = draw.textbbox((0, 0), help_text, font=font_text) text_width = bbox[2] - bbox[0] draw.text(((self.width - text_width) // 2, self.height - 40), help_text, fill=128, font=font_text) return image def add_touch(self, x: int, y: int): """Add touch to history.""" self.touch_history.append((x, y)) if len(self.touch_history) > self.max_history: self.touch_history.pop(0) async def test_calibration(width: int, height: int, virtual: bool = False): """ Run calibration test. Args: width: Display width height: Display height virtual: Use virtual display """ print("Touch Calibration Test") print("======================") # Initialize display display = IT8951DisplayDriver( width=width, height=height, virtual=virtual, ) await display.initialize() print("Display initialized") # Initialize touch touch = FT5xx6TouchDriver( width=width, height=height, ) await touch.initialize() # Check calibration status calibrated = touch.calibration.is_calibrated() if calibrated: quality = touch.calibration.get_calibration_quality() rms_error = touch.calibration.calibration_data.rms_error print(f"Calibration loaded: {quality} (RMS error: {rms_error:.2f}px)") else: print("No calibration loaded - using raw coordinates") # Create UI ui = CalibrationTester(width, height) # Initial screen screen = ui.create_screen(calibrated) await display.show_image(screen, mode=RefreshMode.QUALITY) print("\nTap anywhere on the screen to test calibration") print("Swipe left to exit\n") # Event loop try: last_touch = None last_raw = None while True: event = await touch.get_touch_event() if event: if event.gesture == GestureType.TAP: # Store calibrated coordinates last_touch = (event.x, event.y) # Get raw coordinates (before calibration) # Note: We can't easily get raw coords after the fact, # but we can show the difference if calibration exists if calibrated: # Estimate raw by inverting calibration (not precise) last_raw = (event.x, event.y) # Placeholder else: last_raw = (event.x, event.y) ui.add_touch(event.x, event.y) print(f"Touch at ({event.x}, {event.y})") # Update screen screen = ui.create_screen(calibrated, last_touch, last_raw) await display.show_image(screen, mode=RefreshMode.FAST) elif event.gesture == GestureType.SWIPE_LEFT: print("Exiting...") break finally: # Cleanup await display.cleanup() await touch.cleanup() print("Test complete!") def main(): """Main entry point.""" parser = argparse.ArgumentParser( description="Test touchscreen calibration for DReader HAL" ) parser.add_argument( '--width', type=int, default=800, help='Display width in pixels (default: 800)' ) parser.add_argument( '--height', type=int, default=1200, help='Display height in pixels (default: 1200)' ) parser.add_argument( '--virtual', action='store_true', help='Use virtual display for testing' ) args = parser.parse_args() # Run test asyncio.run(test_calibration( width=args.width, height=args.height, virtual=args.virtual, )) if __name__ == '__main__': main()