brlapi 0.4.1

Safe Rust bindings for the BrlAPI library
// SPDX-License-Identifier: LGPL-2.1

//! Basic BrlAPI tutorial example
//!
//! This example demonstrates the basic BrlAPI workflow:
//! 1. Connect to BrlAPI server
//! 2. Get display information  
//! 3. Enter TTY mode
//! 4. Write text to the display
//! 5. Clean up
//!
//! Based on the tutorial at:
//! https://brltty.app/doc/Manual-BrlAPI/English/BrlAPI-5.html

use std::error::Error;

use brlapi::{BrlApiError, Connection, TtyMode, text};

fn main() -> Result<(), Box<dyn Error>> {
    println!("BrlAPI Rust Tutorial Example");
    println!("============================");

    // Step 1: Connect to BrlAPI server
    println!("Connecting to BrlAPI server...");
    let connection = match Connection::open() {
        Ok(conn) => {
            println!("Connected successfully!");
            conn
        }
        Err(BrlApiError::ConnectionRefused) => {
            eprintln!("Connection refused - is brltty/xbrlapi running?");

            return Err("BrlAPI connection failed".into());
        }
        Err(e) => {
            eprintln!("Connection failed: {e}");
            return Err(e.into());
        }
    };

    let fd = connection.file_descriptor();
    println!("File descriptor: {fd}");

    // Step 2: Get display and driver information
    println!("\nGetting display information...");
    let (width, height) = connection.display_size()?;
    println!("Display size: {width} columns x {height} rows");

    let driver_name = connection
        .display_driver()
        .unwrap_or_else(|_| "unknown".to_string());
    println!("Driver: {driver_name}");

    let model = connection
        .display_model()
        .unwrap_or_else(|_| "unknown".to_string());
    println!("Model: {model}");

    if width == 0 || height == 0 {
        eprintln!("Warning: Display reports zero size - this might be a dummy display");
        eprintln!("Text writing may not work properly with driver: {driver_name}");
    }

    // Step 3: Enter TTY mode to take control (using RAII)
    println!("\nEntering TTY mode...");
    let (tty_mode, tty_num) = TtyMode::enter_auto(&connection, None)?;
    println!("TTY mode entered for virtual console {tty_num}");

    // Step 4: Write text to the display (skip for NoBraille driver)
    if driver_name == "NoBraille" {
        println!(
            "\nSkipping text write operations for NoBraille driver (testing/development mode)"
        );
        println!("In real usage, this would write to your braille display");
    } else {
        println!("\nWriting text to braille display...");
        let writer = tty_mode.writer();
        match writer.write_contracted_en_us_g2(
            "Hello from Rust! Press any key to continue...",
            text::CursorPosition::Off,
        ) {
            Ok(()) => println!("Contracted text written to display"),
            Err(_) => {
                writer.write_text("Hello from Rust! Press any key to continue...")?;
                println!("Text written to display (uncontracted fallback)");
            }
        }

        // Step 5: Wait for user acknowledgment
        println!("\nText should now be visible on the braille display.");
        println!("Press Enter to continue...");
        let mut input = String::new();
        std::io::stdin().read_line(&mut input)?;

        // Step 6: Write another message
        println!("Writing second message...");
        match writer
            .write_contracted_en_us_g2("BrlAPI + Rust = Perfect match!", text::CursorPosition::Off)
        {
            Ok(()) => {} // Success, no need to print
            Err(_) => {
                let _ = writer.write_text("BrlAPI + Rust = Perfect match!");
            }
        }
        println!("Second message written");
    }

    println!("\nPress Enter to exit...");
    let mut input = String::new();
    std::io::stdin().read_line(&mut input)?;

    // Step 7: TTY mode cleanup happens automatically when tty_mode drops
    println!("TTY mode and connection will be cleaned up automatically");

    println!("\nTutorial completed successfully!");
    Ok(())
}