ruida 0.1.1

Fast Rust Library and CLI to control Ruida Laser DSP Machines, with Python bindings
Documentation
# Ruida Architecture & Design Guidelines

This document describes the software architecture, design principles, and module structure of the Ruida Rust project. It serves as a technical guide for contributors and as an overview of how the system is organized.

## High-Level Architecture

Ruida is designed in a modular way with clear separation of concerns. The core idea is to isolate the low-level Ruida protocol handling from the user-facing interfaces. This allows multiple interfaces (CLI, Python, GUI, etc.) to reuse the same core logic.

**Layers and Components:**

1. **Transport Layer** – Handles communication with the hardware (UDP network sockets or USB serial). This layer knows how to send raw bytes and receive responses.
2. **Protocol Layer** – Implements Ruida-specific protocol encoding/decoding on top of the transport. This includes packet construction, checksum calculation, byte swizzling, and interpreting responses (like ACKs or status messages).
3. **Controller API Layer** – Provides high-level operations (methods) that correspond to actions a user wants (e.g., send_file, move_head, read_status). This layer orchestrates the protocol commands to achieve a function. For example, `send_file()` will use the Protocol layer to send chunks and handle acks, rather than the interface layer doing that.
4. **Interface Layer** – User-facing. This includes:
   - CLI: Parsing command-line arguments, invoking the Controller API, and formatting output for terminal.
   - Python bindings: Wrapping the Controller API functions/classes.

Each layer is mostly independent. The Interface Layer should not need to know details about checksums or UDP ports; it relies on the Controller API. The Protocol Layer doesn’t print or log user-facing messages – it returns errors or data up to the higher layers which decide how to present them.

This separation makes the code easier to maintain and extend. For instance, if Ruida releases a new communication method, we add a new Transport implementation. If we add a new UI (say a Node.js binding), we just wrap the Controller API differently, but the core logic stays the same.

## Module Structure

The project is organized into multiple crates for clarity:

- **ruida_core (library crate):** Contains the Transport, Protocol, and Controller API layers.
- **ruida_cli (binary crate):** The CLI application.
- **ruida_py (library crate):** Python bindings (likely using PyO3 to expose `ruida_core` functionality).

We use a Cargo workspace so that these crates share the same repository, and we can have inter-crate dependencies (e.g., CLI depends on ruida_core, Python and WASM crates also depend on ruida_core).

**Inside ruida_core:**

```rust
ruida_core/src/
├── lib.rs             // lib entry, defines public API of ruida_core
├── transport.rs       // Transport trait and implementations
├── protocol.rs        // Low-level protocol functions (checksum, swizzle, etc.)
├── controller.rs      // Main struct e.g., RuidaController and impl with high-level methods
├── commands.rs        // Definitions of command codes, param addresses, etc.
├── error.rs           // Error type definitions (using thiserror for convenience)
└── utils.rs           // Any utility functions (e.g., conversion between units, etc.)