253 lines
7.9 KiB
Python
Executable File
253 lines
7.9 KiB
Python
Executable File
#!/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()
|