Skip to content

tompatulpan/vail-adapter-lib

Repository files navigation

Vail Adapter Library

A Python library for interfacing with XIAO SAMD21 CW paddle adapters, supporting both Vail firmware (hardware keyer) and custom firmware (software keyer).

Features

  • Dual firmware support: Works with both Vail adapter firmware and custom firmware
  • Auto-detection: Automatically detects which firmware is installed
  • MIDI configuration: Control Vail firmware settings (keyer mode, speed, sidetone)
  • Backend abstraction: Clean API for different keyer implementations
  • Async/sync compatible: Works in both asyncio and synchronous contexts
  • USB HID reading: Generic HID device interface for paddle input

Installation

As Git Submodule (Recommended)

cd your-project
git submodule add https://github.com/tompatulpan/vail-adapter-lib
git submodule update --init --recursive

Add to Python path in your code:

import sys
sys.path.insert(0, 'vail-adapter-lib')
from vail_adapter_lib import PaddleManager

As Python Package

cd vail-adapter-lib
pip install -e .

Quick Start

Basic Usage

from vail_adapter_lib import PaddleManager

# Configuration
config = {
    'usb_hid': {
        'vendor_id': 0x2886,
        'product_id': 0x802f,
        'keyer_mode': 'straight'  # or 'iambic_a', 'iambic_b'
    },
    'vail_adapter': {
        'enabled': True,
        'keyer_mode': 8,  # Iambic B
        'speed_wpm': 25,
        'sidetone_note': 73,  # ~600 Hz
        'output_mode': 'keyboard'
    }
}

# Initialize paddle manager
paddle = PaddleManager(config)
if paddle.initialize():
    print(f"Detected firmware: {paddle.get_firmware_type()}")
    
    # Read paddle state
    left_pressed, right_pressed = paddle.read_paddles()
    print(f"Left: {left_pressed}, Right: {right_pressed}")
    
    # Check if Python keyer logic needed
    if paddle.needs_python_keyer():
        print("Using software iambic keyer")
    else:
        print("Using hardware keyer in firmware")
    
    paddle.close()

With Async Code

import asyncio
from vail_adapter_lib import PaddleManager

async def main():
    paddle = PaddleManager(config)
    paddle.initialize()
    
    while True:
        left, right = paddle.read_paddles()
        if left or right:
            print(f"Paddles: L={left} R={right}")
        await asyncio.sleep(0.001)  # 1ms polling

asyncio.run(main())

Firmware Types

Vail Adapter Firmware (Hardware Keyer)

Features:

  • 9 keyer modes (passthrough, straight, bug, Ultimatic, Iambic A/B, keyahead)
  • Hardware-precise timing (no jitter)
  • MIDI configuration
  • EEPROM settings storage
  • USB HID keyboard output (Left/Right Ctrl)

Download: Vail Adapter Releases

Firmware file: xiao_basic_pcb_v2.uf2 (for PCB v2 with switched TRRS jack)

Configuration:

config = {
    'vail_adapter': {
        'enabled': True,
        'keyer_mode': 8,        # 0-9 (see modes below)
        'speed_wpm': 25,        # 5-60 WPM
        'sidetone_note': 73,    # MIDI note (0-127)
        'output_mode': 'keyboard'
    }
}

Keyer Modes:

  • 0: Passthrough (no keyer)
  • 1: Straight key (either paddle = key down)
  • 2: Bug (auto dits on one side, manual dah on other)
  • 3: Ultimatic
  • 4: Iambic A
  • 5: Iambic A (reversed paddles)
  • 6: Iambic B
  • 7: Iambic B (reversed paddles)
  • 8: Iambic B (Vail style) ← Recommended
  • 9: Keyahead

Custom Firmware (Software Keyer)

Features:

  • Simple USB HID output (dit/dah buttons)
  • Python handles iambic keyer logic
  • Lower latency (no firmware processing)
  • More control over timing

Source: Your custom Arduino firmware

Configuration:

config = {
    'usb_hid': {
        'vendor_id': 0x2886,
        'product_id': 0x802f,
        'keyer_mode': 'iambic_b'  # or 'straight', 'iambic_a'
    },
    'vail_adapter': {
        'enabled': False  # Disable Vail firmware features
    }
}

API Reference

PaddleManager

High-level manager that auto-detects firmware and provides unified interface.

Methods:

  • __init__(config: dict) - Create manager with configuration
  • initialize() -> bool - Initialize and detect firmware, returns success
  • read_paddles() -> Tuple[bool, bool] - Get (left, right) paddle state
  • needs_python_keyer() -> bool - Check if software keyer needed
  • get_firmware_type() -> str - Get "vail" or "custom"
  • close() - Clean up resources

KeyerBackend (Abstract Base Class)

Methods:

  • initialize(config: dict) -> bool - Setup backend
  • read_paddles() -> Tuple[bool, bool] - Read paddle state
  • needs_python_keyer() -> bool - Whether Python keyer needed
  • close() - Cleanup

Implementations:

  • VailFirmwareBackend - For Vail adapter firmware
  • CustomFirmwareBackend - For custom firmware

VailMIDIConfig

MIDI configuration for Vail adapter firmware.

Methods:

  • find_vail_adapter() -> Optional[str] - Find MIDI device name
  • open() -> bool - Open MIDI port
  • set_keyer_mode(mode: int) - Set keyer mode (0-9)
  • set_speed(wpm: int) - Set speed (5-60 WPM)
  • set_sidetone_note(note: int) - Set sidetone MIDI note (0-127)
  • set_output_mode(mode: str) - Set "keyboard" or "midi" output
  • configure_adapter(config: dict) - Apply all settings
  • close() - Close MIDI port

Helper Functions:

  • frequency_to_midi_note(freq: float) -> int - Convert Hz to MIDI note
  • midi_note_to_frequency(note: int) -> float - Convert MIDI note to Hz

IambicKeyer

Software iambic keyer for custom firmware.

Methods:

  • __init__(wpm: int, mode: str, on_element: callable, on_spacing: callable)
  • process_paddles(dit: bool, dah: bool) - Process paddle input
  • set_speed(wpm: int) - Change speed

Modes:

  • "iambic_a" - Iambic mode A
  • "iambic_b" - Iambic mode B (with memory)

HIDReader

Generic USB HID device reader.

Methods:

  • __init__(vendor_id: int, product_id: int, device_path: str)
  • find_device() -> bool - Search for device
  • open() -> bool - Open device
  • read(timeout_ms: int) -> Optional[bytes] - Read data
  • close() - Close device

Examples

See examples/ directory:

  • basic_usage.py - Simple paddle reading
  • async_usage.py - Asyncio integration
  • midi_config.py - Configure Vail firmware
  • software_keyer.py - Using IambicKeyer

Dependencies

Required:

  • Python 3.9+

Optional:

  • mido>=1.3.0 - MIDI support (for Vail firmware configuration)
  • python-rtmidi>=1.5.0 - MIDI backend (recommended)

Install optional dependencies:

pip install mido python-rtmidi

Without MIDI support, the library still works but cannot configure Vail firmware settings (uses EEPROM defaults).

License

MIT License - See LICENSE file

Credits

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages