#!/usr/bin/env python3
"""
UART Core Usage Examples
========================
Shows how to use the new UART core.
"""

import time
from uart_core import *


# =============================================================================
# Example 1: Request-Response (Command Port)
# =============================================================================

def example_command_port():
    """UART command port - send command, get response."""
    print("\n" + "="*60)
    print("Example 1: Command Port (Request-Response)")
    print("="*60)
    
    # Configure for terminator-based stop (newline)
    config = UARTConfig(
        device="/dev/ttyUSB0",
        baudrate=115200,
        buffer_size=4096,
        stop_mode=StopConditionMode.TERMINATOR,
        stop_terminator=0x0A,  # '\n'
        stop_timeout_ms=1000,  # Fallback timeout
        polling_mode=False  # No grace period
    )
    
    # Create and open
    status, port = uart_create(config)
    status = uart_open(port)
    status = uart_start_reader(port)
    
    # Send command and wait for response
    status, packet = uart_send_and_receive(port, b"GET_STATUS\n")
    
    if status == Status.OK:
        print(f"Packet #{packet.packet_id}")
        print(f"Start: {packet.start_timestamp:.6f}s")
        print(f"Stop:  {packet.stop_timestamp:.6f}s")
        print(f"Duration: {(packet.stop_timestamp - packet.start_timestamp)*1000:.2f}ms")
        print(f"Data: {packet.data}")
        print(f"Reason: {packet.stop_reason}")
    
    # Cleanup
    uart_stop_reader(port)
    uart_close(port)


# =============================================================================
# Example 2: Polling (Debug Port)
# =============================================================================

def example_debug_port():
    """UART debug port - continuous polling."""
    print("\n" + "="*60)
    print("Example 2: Debug Port (Polling)")
    print("="*60)
    
    # Configure for timeout-based stop with grace period
    config = UARTConfig(
        device="/dev/ttyUSB1",
        baudrate=115200,
        buffer_size=8192,
        stop_mode=StopConditionMode.TIMEOUT,
        stop_timeout_ms=150,  # 150ms silence
        grace_timeout_ms=150,  # Wait up to 150ms for first byte
        polling_mode=True  # Enable grace period
    )
    
    status, port = uart_create(config)
    uart_open(port)
    uart_start_reader(port)
    
    # Poll for packets continuously
    for i in range(5):
        status, packet = uart_poll_packet(port)
        
        if status == Status.OK:
            print(f"\nPacket #{packet.packet_id}")
            print(f"  Data: {packet.data[:50]}...")  # First 50 bytes
            print(f"  Length: {len(packet.data)} bytes")
            print(f"  Duration: {(packet.stop_timestamp - packet.start_timestamp)*1000:.2f}ms")
        elif status == Status.TIMEOUT_NO_DATA:
            print(f"\nNo data (timeout)")
        
        time.sleep(0.1)
    
    uart_stop_reader(port)
    uart_close(port)


# =============================================================================
# Example 3: vzug-e-hinge Setup (Two Ports)
# =============================================================================

def example_vzug_e_hinge():
    """Full vzug-e-hinge setup with command and debug ports."""
    print("\n" + "="*60)
    print("Example 3: vzug-e-hinge (Command + Debug)")
    print("="*60)
    
    # Command port config
    cmd_config = UARTConfig(
        device="/dev/ttyUSB0",
        baudrate=115200,
        stop_mode=StopConditionMode.TERMINATOR,
        stop_terminator=0x0A,
        polling_mode=False
    )
    
    # Debug port config
    debug_config = UARTConfig(
        device="/dev/ttyUSB1",
        baudrate=115200,
        stop_mode=StopConditionMode.TIMEOUT,
        stop_timeout_ms=150,
        grace_timeout_ms=150,
        polling_mode=True
    )
    
    # Create both ports
    status, uart_cmd = uart_create(cmd_config)
    status, uart_debug = uart_create(debug_config)
    
    # Open and start readers
    uart_open(uart_cmd)
    uart_open(uart_debug)
    uart_start_reader(uart_cmd)
    uart_start_reader(uart_debug)
    
    # Command example
    print("\n--- Sending Command ---")
    status, packet = uart_send_and_receive(uart_cmd, b"GET_ANGLE\n")
    if status == Status.OK:
        print(f"Response: {packet.data}")
    
    # Poll debug data
    print("\n--- Polling Debug ---")
    status, packet = uart_poll_packet(uart_debug)
    if status == Status.OK:
        print(f"Debug data: {packet.data[:100]}")
    
    # Check status
    cmd_status = uart_get_status(uart_cmd)
    debug_status = uart_get_status(uart_debug)
    
    print(f"\n--- Port Status ---")
    print(f"Command: {cmd_status.total_packets} packets, "
          f"{cmd_status.total_bytes_received} bytes, "
          f"buffer {cmd_status.buffer_fill_percent}%")
    print(f"Debug:   {debug_status.total_packets} packets, "
          f"{debug_status.total_bytes_received} bytes, "
          f"buffer {debug_status.buffer_fill_percent}%")
    
    # Cleanup
    uart_stop_reader(uart_cmd)
    uart_stop_reader(uart_debug)
    uart_close(uart_cmd)
    uart_close(uart_debug)


# =============================================================================
# Example 4: Custom Timestamp Source
# =============================================================================

def example_custom_timestamp():
    """Use custom timestamp source (for syncing with I2C)."""
    print("\n" + "="*60)
    print("Example 4: Custom Timestamp Source")
    print("="*60)
    
    # Global time reference (shared with I2C, etc.)
    class GlobalClock:
        def __init__(self):
            self.offset = time.perf_counter()
        
        def now(self):
            return time.perf_counter() - self.offset
    
    clock = GlobalClock()
    
    # Configure UART with custom clock
    config = UARTConfig(
        device="/dev/ttyUSB0",
        baudrate=115200,
        stop_mode=StopConditionMode.TERMINATOR,
        stop_terminator=0x0A,
        timestamp_source=clock.now  # ← Custom time function
    )
    
    status, port = uart_create(config)
    uart_open(port)
    uart_start_reader(port)
    
    # All timestamps now use clock.now()
    status, packet = uart_send_and_receive(port, b"TEST\n")
    
    if status == Status.OK:
        print(f"Timestamp: {packet.start_timestamp:.6f}s (from global clock)")
        print(f"I2C can use same clock.now() for sync!")
    
    uart_stop_reader(port)
    uart_close(port)


# =============================================================================
# Example 5: Error Handling
# =============================================================================

def example_error_handling():
    """Handle disconnections and errors."""
    print("\n" + "="*60)
    print("Example 5: Error Handling")
    print("="*60)
    
    config = UARTConfig(
        device="/dev/ttyUSB0",
        baudrate=115200,
        stop_mode=StopConditionMode.TIMEOUT,
        stop_timeout_ms=500
    )
    
    status, port = uart_create(config)
    
    # Check creation status
    if status != Status.OK:
        print(f"Failed to create: {status}")
        return
    
    # Try to open
    status = uart_open(port)
    if status != Status.OK:
        print(f"Failed to open: {status}")
        return
    
    uart_start_reader(port)
    
    # Try to send
    status, written = uart_write(port, b"TEST\n")
    if status != Status.OK:
        print(f"Write failed: {status}")
        uart_close(port)
        return
    
    # Poll for response
    status, packet = uart_poll_packet(port)
    
    if status == Status.TIMEOUT_NO_DATA:
        print("No response received (timeout)")
    elif status == Status.OK:
        print(f"Received: {packet.data}")
    else:
        print(f"Error: {status}")
    
    # Check buffer status
    port_status = uart_get_status(port)
    if port_status.buffer_overflows > 0:
        print(f"WARNING: {port_status.buffer_overflows} buffer overflows!")
    
    uart_stop_reader(port)
    uart_close(port)


# =============================================================================
# Main
# =============================================================================

if __name__ == "__main__":
    print("\nUART Core v2.0 Examples")
    print("=======================")
    
    # Run examples (comment out as needed)
    try:
        example_command_port()
    except Exception as e:
        print(f"Example 1 error: {e}")
    
    try:
        example_debug_port()
    except Exception as e:
        print(f"Example 2 error: {e}")
    
    try:
        example_vzug_e_hinge()
    except Exception as e:
        print(f"Example 3 error: {e}")
    
    try:
        example_custom_timestamp()
    except Exception as e:
        print(f"Example 4 error: {e}")
    
    try:
        example_error_handling()
    except Exception as e:
        print(f"Example 5 error: {e}")
    
    print("\n" + "="*60)
    print("Done!")
    print("="*60)
