rusty-tip 0.0.2

Rust library for Nanonis SPM system control via TCP
Documentation
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with the `rusty-tip` library.

## Build and Development Commands

```bash
# Build the library
cargo build

# Run examples
cargo run --example boundary_monitor_demo
cargo run --example real_time_boundary_monitor
cargo run --example machine_test
cargo run --example get_signals
cargo run --example signal_monitor_test
cargo run --example signal_timing_benchmark
cargo run --example signal_timing_oscilloscope
cargo run --example two_osci_instances_test
cargo run --example oscilloscope_comparison
cargo run --example two_osci2t_instances_test
cargo run --example simple_dual_client_test
cargo run --example osci_continuity_analysis  # Comprehensive analysis of oscilloscope data continuity
cargo run --example scan_heatmap_plotter    # Creates heatmap visualization from scan data
cargo run --example egui_scan_reader        # Interactive GUI for reading and visualizing scan data
cargo run --example tcplog_demo             # TCP Logger configuration and control demo

# Run tests
cargo test

# Run specific test modules
cargo test classifier
cargo test controller
cargo test policy

# Check for compilation errors without building
cargo check
```

## Logging Configuration

The library uses the `log` crate with configurable logging levels. Set the `RUST_LOG` environment variable to control verbosity:

```bash
# Maximum verbosity - shows all internal operations
RUST_LOG=trace cargo run --example boundary_monitor_demo

# Debug level - shows detailed operational info
RUST_LOG=debug cargo run --example boundary_monitor_demo

# Info level (default) - shows normal operation messages
RUST_LOG=info cargo run --example boundary_monitor_demo

# Warning level - shows only warnings and errors
RUST_LOG=warn cargo run --example boundary_monitor_demo

# Error level - shows only errors
RUST_LOG=error cargo run --example boundary_monitor_demo
```

**Log Levels Used:**
- **`trace`**: Very detailed internal state (buffer contents, signal values)
- **`debug`**: Detailed operational info (good signals, stability tracking, pulse operations)
- **`info`**: Normal operation messages (control loop start/stop, major actions, stable signals)
- **`warn`**: Warnings (bad signals, recovery actions)
- **`error`**: Errors (connection failures, protocol errors)

## Architecture Overview

This is a Rust library for interfacing with Nanonis SPM (Scanning Probe Microscopy) systems via TCP protocol. The architecture has evolved to use a **separated, modular design** with clear data flow and responsibilities.

### Key Architectural Changes

The library now uses **`MachineState`** as the central data structure, replacing the previous `TipState`. This represents a significant architectural shift toward a more structured approach:

- **Raw Signals****StateClassifier****Enriched MachineState****PolicyEngine****Actions**
- State classification is now **in-place** on `MachineState` objects
- Fresh signal sampling with configurable buffer sizes
- Enhanced debugging and monitoring capabilities

### Core Components

#### **Types Layer** (`src/types.rs`)
- **`NanonisValue`**: Enum for all Nanonis protocol data types with comprehensive conversion traits
- **`BiasVoltage`**, **`Position`**: Type-safe wrappers for common values
- **`MachineState`**: **Central state representation** containing:
  - Current signal readings (`primary_signal`, `all_signals`)
  - Spatial context (`position`, `z_position`) 
  - Temporal context (`timestamp`, `signal_history`)
  - System state (`approach_count`, `last_action`, `system_parameters`)
  - **Classification result** (`classification: TipState`)
  - ML expansion fields (commented for future use)

#### **Error Handling** (`src/error.rs`)
- **`NanonisError`**: Comprehensive error types with detailed context
- Covers IO, protocol, type, and command errors using `thiserror`

#### **Protocol Layer** (`src/protocol.rs`)
- Low-level TCP protocol implementation for Nanonis communication
- Big-endian serialization/deserialization of `NanonisValue` types
- Message headers, validation, and protocol constants
- Supports integers, floats, arrays, strings

#### **Client Layer** (`src/client.rs`)
- **`NanonisClient`** with builder pattern for flexible configuration
- **Comprehensive Nanonis command support**:
  - **Signals**: `ValsGet`, `NamesGet`, `CalibrGet`, `RangeGet`
  - **Control**: `Bias.Set/Get`, `FolMe.XYPosSet/Get`, `ZCtrl.Withdraw`
  - **Automation**: `AutoApproach.*`, `Motor.*` commands
- Connection management with configurable timeouts and retry logic
- Type-safe method interfaces

#### **State Classification** (`src/classifier.rs`)
- **`StateClassifier`** trait: Converts raw signals into interpreted machine states
- **`BoundaryClassifier`**: Advanced boundary-based classification with:
  - **Fresh sampling integration**: Uses `signal_history` from `MachineState`
  - **Drop-front buffering**: Configurable buffer size and drop count
  - **Stability tracking**: Consecutive good readings for stable classification  
  - **In-place classification**: Updates `MachineState.classification` directly
- **`TipState`**: Simple enum (`Bad`, `Good`, `Stable`) with `Default` trait

#### **Policy Engine** (`src/policy.rs`)
- **`PolicyEngine`** trait: Makes decisions based on `MachineState`
- **`RuleBasedPolicy`**: Simple mapping from classification to decision
- **`PolicyDecision`**: Good/Bad/Stable decision types
- **Extensible design** for future ML/transformer-based policies with learning traits

#### **Controller** (`src/controller.rs`)
- **High-level orchestration** integrating all components
- **Fresh sampling strategy**: Collects multiple samples per monitoring cycle
- **State-driven actions**: Complex action sequences based on policy decisions
- **Rich context tracking**: Position history, action history, approach counts
- **ML-ready architecture**: Placeholder methods for future expansion

### Data Flow Architecture

```
1. Controller collects fresh samples → MachineState.signal_history
2. StateClassifier.classify(machine_state) → Updates classification in-place  
3. Controller enriches MachineState with position, signal names, etc.
4. PolicyEngine.decide(machine_state) → PolicyDecision
5. Controller executes actions based on decision
```

### Nanonis Protocol Integration

**Signal Operations:**
- `Signals.ValsGet` - Read multiple signal values with wait-for-newest option
- `Signals.NamesGet` - Get available signal names  
- `Signals.CalibrGet` - Get signal calibration and offset
- `Signals.RangeGet` - Get signal range limits

**Control Operations:**
- `Bias.Set` / `Bias.Get` - Control bias voltage
- `FolMe.XYPosSet` / `FolMe.XYPosGet` - Position control with type-safe Position struct
- `ZCtrl.Withdraw` - Tip withdrawal with timeout control

**TCP Logger Operations:**
- `TCPLog.Start` / `TCPLog.Stop` - Control data logging acquisition
- `TCPLog.ChsSet` - Configure channels to record (0-23 signal slots)
- `TCPLog.OversamplSet` - Set oversampling rate (0-1000)
- `TCPLog.StatusGet` - Monitor logger status (idle, running, overflow, etc.)

**Automation:**
- `AutoApproach.Open` / `AutoApproach.OnOffSet` / `AutoApproach.OnOffGet` - Auto-approach control
- `Motor.StartMove` / `Motor.StartClosedLoop` / `Motor.StopMove` - Coarse positioning
- `Motor.PosGet` / `Motor.StepCounterGet` / `Motor.FreqAmpGet/Set` - Motor status and control

### Current Usage Pattern

The separated architecture is demonstrated in `boundary_monitor_demo.rs`:

```rust
// Create client
let client = NanonisClient::new("127.0.0.1:6501")?;

// Create classifier for signal interpretation
let classifier = BoundaryClassifier::new(
    "Bias Boundary Classifier".to_string(),
    24,  // Signal index (bias voltage)
    0.0, // min bound (V)
    2.0, // max bound (V)
)
.with_buffer_config(10, 2)    // 10 samples, drop first 2
.with_stability_config(3);    // 3 consecutive good for stable

// Create policy for decision making
let policy = RuleBasedPolicy::new("Simple Rule Policy".to_string());

// Integrate with controller
let mut controller = Controller::with_client(
    client, 
    Box::new(classifier), 
    Box::new(policy)
);

// Run automated control loop
controller.run_control_loop(2.0, Duration::from_secs(30))?;
```

## Development Notes

### Architecture Principles
- **Separated concerns**: Raw signals → classification → policy → actions
- **Type safety**: Extensive use of type-safe wrappers and conversion traits
- **Fresh sampling**: Controller actively collects fresh samples for classification
- **In-place updates**: `MachineState` is modified in-place by classifiers
- **ML readiness**: Architecture designed for future transformer/ML policy engines

### Technical Details
- **Protocol**: Big-endian byte order for all data types
- **Signal indices**: Typically 0-127, with bias voltage commonly at index 24
- **Buffering**: Classifiers use configurable buffering with drop-front analysis
- **Error handling**: Comprehensive error types with detailed context
- **Testing**: Unit tests for all core components with mocking support

### Key Behavioral Changes
- `StateClassifier.classify()` now takes `&mut MachineState` instead of returning `TipState`
- `PolicyEngine.decide()` now takes `&MachineState` instead of `&TipState`  
- Controller performs fresh sampling (10 samples per cycle) instead of single reads
- `MachineState` replaces `TipState` as the central data structure
- Classification and enrichment happen in-place on the state object

### Future Expansion Points
- **Advanced Classifiers**: Statistical, multi-signal, frequency-domain analysis
- **ML Policy Engines**: Neural networks, transformers, reinforcement learning
- **Data Management**: Logging, real-time plotting, configuration management
- **Robustness**: Enhanced error recovery, simulation modes, benchmarking