# Sauna Driver Developer Guide

This guide provides detailed technical information for developers who want to understand, modify, or extend the Sauna OpenVR driver. It covers the code structure, OpenVR integration, IMU data processing, and tips for extending and debugging the driver.

## Code Structure

The Sauna driver is organized into several key components:

### Directory Structure

```
drivers/sauna/
├── build.bat                    # Build script for Windows
├── driver_sauna.cpp             # Main driver entry point
├── driver.vrdrivermanifest      # Driver manifest for OpenVR
├── imu_data_provider.cpp        # IMU data provider implementation
├── imu_data_provider.h          # IMU data provider interface
├── lighthouse_driver_wrapper.cpp # Lighthouse driver wrapper implementation
├── lighthouse_driver_wrapper.h  # Lighthouse driver wrapper interface
├── sauna_device_driver.cpp      # Custom device driver implementation
├── sauna_device_driver.h        # Custom device driver interface
├── docs/                        # Documentation
└── tests/                       # Testing framework
    ├── integration_test.cpp     # Integration tests
    ├── performance_test.cpp     # Performance tests
    ├── test_imu_data_provider.cpp # Unit tests for IMU data provider
    ├── test_lighthouse_driver_wrapper.cpp # Unit tests for lighthouse wrapper
    ├── test_sauna_device_driver.cpp # Unit tests for device driver
    ├── test_utils.cpp           # Test utilities implementation
    ├── test_utils.h             # Test utilities interface
    ├── validation_test.cpp      # Validation tests
    ├── run_integration_tests.bat # Script to run integration tests
    ├── run_performance_tests.bat # Script to run performance tests
    ├── run_unit_tests.bat       # Script to run unit tests
    ├── run_validation_tests.bat # Script to run validation tests
    └── README.md                # Testing framework documentation
```

### Class Hierarchy

The driver consists of the following main classes:

1. **SaunaDeviceProvider** (in `driver_sauna.cpp`)
   - Implements `IServerTrackedDeviceProvider`
   - Main entry point for the driver
   - Manages the lifecycle of the driver components

2. **LighthouseDriverWrapper** (in `lighthouse_driver_wrapper.h/cpp`)
   - Wraps the existing lighthouse driver
   - Loads the lighthouse driver dynamically
   - Forwards calls to the lighthouse driver

3. **IMUDataProvider** (in `imu_data_provider.h/cpp`)
   - Manages IMU data for tracked devices
   - Provides methods to access IMU data

4. **SaunaDeviceDriver** (in `sauna_device_driver.h/cpp`)
   - Implements `ITrackedDeviceServerDriver` and `IVRIMUComponent`
   - Wraps existing device drivers
   - Provides IMU data access and fallback tracking

5. **IVRIMUComponent** (in `sauna_device_driver.h`)
   - Custom interface for accessing IMU data
   - Implemented by `SaunaDeviceDriver`

### Component Relationships

The components interact as follows:

- `SaunaDeviceProvider` creates and manages instances of `LighthouseDriverWrapper` and `IMUDataProvider`
- `SaunaDeviceProvider` creates instances of `SaunaDeviceDriver` for each tracked device
- `SaunaDeviceDriver` wraps the original device driver and adds IMU functionality
- `SaunaDeviceDriver` uses `IMUDataProvider` to access IMU data
- Applications interact with `IVRIMUComponent` to access IMU data

## OpenVR Integration

### Driver Initialization

The driver initialization process follows these steps:

1. OpenVR loads the driver DLL and calls `HmdDriverFactory` with the interface name
2. `HmdDriverFactory` creates a new `SaunaDeviceProvider` instance
3. OpenVR calls `SaunaDeviceProvider::Init` with the driver context
4. `SaunaDeviceProvider::Init` initializes the lighthouse driver wrapper and IMU data provider
5. The lighthouse driver wrapper loads the original lighthouse driver
6. The driver is now ready to handle tracked devices

### Driver Lifecycle

The driver lifecycle is managed by OpenVR through the following methods:

- `Init`: Called when the driver is loaded
- `Cleanup`: Called when the driver is unloaded
- `RunFrame`: Called each frame to update the driver state
- `ShouldBlockStandbyMode`: Called to check if the driver should prevent the system from entering standby mode
- `EnterStandby`: Called when the system enters standby mode
- `LeaveStandby`: Called when the system leaves standby mode

### Device Tracking

Device tracking is handled as follows:

1. OpenVR calls `SaunaDeviceProvider::RunFrame` each frame
2. `SaunaDeviceProvider::RunFrame` forwards the call to the lighthouse driver
3. OpenVR calls `SaunaDeviceDriver::GetPose` to get the device pose
4. `SaunaDeviceDriver::GetPose` gets the pose from the wrapped driver
5. If optical tracking is lost, `SaunaDeviceDriver::GetPose` uses IMU data to update the pose
6. The updated pose is returned to OpenVR

## IMU Data Processing

### IMU Data Collection

IMU data is collected from the tracked devices as follows:

1. The IMU data provider registers devices when they are activated
2. IMU data samples are added to the provider through the `AddIMUSample` method
3. The samples are stored in a queue for each device
4. The queue has a maximum size to prevent memory issues

### IMU Data Integration

When optical tracking is lost, IMU data is integrated to update the device pose:

1. `SaunaDeviceDriver::GetPose` detects that optical tracking is lost
2. It gets the latest IMU sample from the IMU data provider
3. It calls `IntegrateIMUData` to update the pose using the IMU data
4. `IntegrateIMUData` performs the following steps:
   - Updates the angular velocity from the gyroscope data
   - Updates the acceleration from the accelerometer data
   - Integrates the gyroscope data to update the orientation
   - Integrates the accelerometer data to update the velocity and position
   - Applies a velocity decay to prevent drift

### Fallback Tracking

The fallback tracking mechanism works as follows:

1. `SaunaDeviceDriver::GetPose` checks the tracking result from the wrapped driver
2. If the result indicates that optical tracking is lost, it switches to IMU-based tracking
3. It uses the last known good pose as a starting point
4. It updates the pose using IMU data integration
5. It returns the updated pose to OpenVR

## Extending the Driver

### Adding New Features

To add new features to the driver:

1. Identify the component that needs to be modified
2. Make the necessary changes to the component
3. Update the tests to cover the new functionality
4. Build and test the driver

### Supporting Additional Devices

To support additional devices:

1. Modify `SaunaDeviceProvider` to handle the new device type
2. Create a new device driver class if needed
3. Update the IMU data provider to handle the new device
4. Add tests for the new device support

### Best Practices

When modifying the driver, follow these best practices:

1. Maintain backward compatibility with existing applications
2. Keep the driver lightweight to minimize performance impact
3. Add comprehensive tests for new functionality
4. Document all changes and new features
5. Follow the existing code style and conventions

## Build Instructions

### Prerequisites

To build the driver, you need:

- Visual Studio with C++ development tools
- OpenVR SDK
- CMake (optional, for cross-platform builds)

### Building on Windows

To build the driver on Windows:

1. Open a command prompt in the `drivers\sauna` directory
2. Run `build.bat`
3. The built driver will be in the `bin\win64` directory

### Building on Other Platforms

To build the driver on other platforms:

1. Create a build script similar to `build.bat` for your platform
2. Ensure the OpenVR include path is set correctly
3. Compile the source files and create a shared library
4. Copy the driver manifest to the output directory

### Debugging Setup

To set up debugging:

1. Build the driver with debug symbols
2. Configure Visual Studio to attach to the SteamVR process
3. Set breakpoints in the driver code
4. Launch SteamVR and attach the debugger

## Debugging Tips

### Common Issues

Common issues when developing the driver include:

1. Driver not loading
   - Check that the driver manifest is correct
   - Verify that the DLL is in the correct location
   - Check SteamVR logs for error messages

2. IMU data not available
   - Verify that the device is registered with the IMU data provider
   - Check that IMU samples are being added to the provider
   - Ensure the device supports IMU data

3. Fallback tracking not working
   - Verify that the driver correctly detects when optical tracking is lost
   - Check that IMU data integration is working correctly
   - Ensure the last known good pose is being stored

### Logging and Diagnostics

The driver uses the OpenVR logging system for diagnostics:

```cpp
VRDriverLog()->Log("Log message");
```

To enable verbose logging, add the following to the driver manifest:

```json
{
  "alwaysActivate": true,
  "name": "sauna",
  "directory": "",
  "resourceOnly": false,
  "hmd_presence": ["*.*"],
  "enable_verbose_logging": true
}
```

### Performance Optimization

To optimize the driver's performance:

1. Minimize work done in the `RunFrame` method
2. Use efficient data structures for storing IMU samples
3. Implement a simple velocity decay to prevent drift
4. Limit the queue size for IMU samples
5. Use a complementary filter for sensor fusion