# framecpp - Core Frame File I/O Library

## Overview
FrameCPP is the core C++ library for gravitational wave frame file I/O operations. It implements the LIGO/Virgo frame specification for storing and retrieving detector data, providing both C++ and C interfaces for maximum compatibility.

## Architecture

### Multi-Layer Design
```
framecpp/
├── Common/          # Shared functionality and containers
├── Universal/       # Version-agnostic frame objects
│   └── VersionRegistry/  # Consolidated version specs (v3-v9)
│       ├── Version3/     # v3 spec registration
│       ├── Version4/     # v4 spec registration
│       ├── Version5/     # v5 spec registration
│       ├── Version6/     # v6 spec registration
│       ├── Version7/     # v7 spec registration
│       ├── Version8/     # v8 spec registration
│       ├── Version9/     # v9 spec registration (current)
│       └── VersionRegistry.{cc,hh}  # Central initialization
├── OOInterface/     # C++ object-oriented interface
├── CInterface/      # C bindings for compatibility
└── Utilities/       # Command-line tools
```

### Universal Namespace Migration
**Status**: ✅ Completed - All frame objects moved to Universal namespace

**Purpose**:
- Decouple frame objects from specific frame specification versions
- Provide stable API across versions
- Enable seamless version upgrades

**Implementation**:
```cpp
namespace FrameCPP {
    using Universal::FrAdcData;
    using Universal::FrameH;
    using Universal::FrVect;
    // Version 9 is current default
}
```

### Version Consolidation (2025-12)
**Status**: ✅ Completed - All version-specific code consolidated into VersionRegistry

**Architecture Change**:

**Before Consolidation**:
- 7 separate version-specific libraries: `libframecpp3` → `libframecpp4` → ... → `libframecpp9`
- Complex dependency chain
- Redundant code across versions
- 38 files spread across 7 directories

**After Consolidation**:
- Single unified library: `libframecppu` contains all v3-v9 specifications
- Centralized version registration in `Universal/VersionRegistry/`
- Simplified build system
- All version code in one location

**Key Benefits**:
- **Simpler Build**: 1 library instead of 7
- **Faster Compilation**: No redundant library builds
- **Easier Maintenance**: All version code consolidated
- **Full Backward Compatibility**: Legacy include paths still work

**Backward Compatibility Strategy**:

Headers physically located in `Universal/VersionRegistry/VersionN/` but symlinked to backward-compatible paths:
- `#include "framecpp/Version9/FrameSpec.hh"` ✅ Still works
- `#include "framecpp/Version9/FrameStream.hh"` ✅ Still works
- `#include "framecpp/Version9/FrameStreamPlan.hh"` ✅ Still works

Version namespaces preserved:
```cpp
// Legacy code continues to work unchanged
FrameCPP::Version_9::IFrameStream stream;
FrameCPP::Version_9::IFrameStreamAuto autoStream;
```

**New Unified API**:
```cpp
// Initialize all version specs (v3-v9)
FrameCPP::Initialize();  // Calls Universal::VersionRegistry::init_all_versions()

// Or directly:
#include "framecpp/Universal/VersionRegistry.hh"
FrameCPP::Universal::VersionRegistry::init_all_versions();
```

## Core Data Structures

### Primary Frame Objects
- **FrameH** - Frame header with metadata and GPS time
- **FrVect** - Vector data for time series and arrays
- **FrAdcData** - ADC (analog-to-digital converter) data
- **FrProcData** - Post-processed data with calibration
- **FrSimData** - Simulated data for testing
- **FrRawData** - Raw detector data
- **FrSerData** - Serial data streams
- **FrEvent** - Event data structures
- **FrDetector** - Detector configuration
- **FrTOC** - Table of contents for frame files
- **FrStatData** - Static detector data
- **FrSummary** - Summary and trend data
- **FrTable** - Tabular data structure

### Container Architecture
```cpp
// Core container template
template<typename T>
class Container {
    std::vector<boost::shared_ptr<T>> data;
    // Smart pointer-based ownership
    // SWIG-friendly design
};

// Common type aliases
typedef Container<FrVect> FrVectContainer;
typedef Container<FrAdcData> FrAdcDataContainer;
```

## I/O Operations

### Stream Classes
```cpp
// Reading frames
IFrameFStream stream("file.gwf");
auto frame = stream.ReadFrame(frameNumber);
auto adcData = stream.ReadFrAdcData(frameNumber, "channelName");

// Writing frames
OFrameStream output("output.gwf");
output.WriteFrame(frame);
```

### Key I/O Patterns
- **Lazy Loading**: Data read on demand
- **Buffered I/O**: Efficient memory usage
- **Compression Support**: gzip, zstd, differential
- **Checksum Validation**: Data integrity verification

## API Interfaces

### C++ Interface (Primary)
- **Exception Handling**: C++ exceptions for errors
- **Smart Pointers**: boost::shared_ptr for memory management
- **STL Containers**: Standard library integration
- **Template Support**: Type-safe operations

### C Interface (Compatibility)
- **Error Codes**: C-style error handling
- **Manual Memory**: Explicit allocation/deallocation
- **C Linkage**: Compatible with C-only applications
- **Stable ABI**: Version-independent binary interface

## Build System

### CMake Configuration
```cmake
# Requirements
cmake_minimum_required(VERSION 3.12)
set(CMAKE_CXX_STANDARD 17)

# Dependencies
find_package(Boost 1.67 REQUIRED)
find_package(ldastoolsal REQUIRED)
```

### Library Architecture

**Core Libraries** (after consolidation):
1. **libframecppcmn** - Common utilities and containers
2. **libframecppu** - Universal frame objects + all version specs (v3-v9)
3. **libframecpp** - OOInterface (main C++ API)
4. **libframecppc** - C interface for compatibility

**Dependency Chain**:
```
Applications
    ↓
libframecpp (OOInterface)
    ↓
libframecppu (Universal + VersionRegistry)
    ↓
libframecppcmn (Common)
    ↓
ldastoolsal (LDAS Tools Abstraction Layer)
```

**Version-Specific Libraries** (eliminated):
- `libframecpp3-9` ❌ No longer built
- All version specs now contained in single `libframecppu`

### Key Build Options
- **Frame Specification**: Version 9 (current default)
- **Version Support**: All versions 3-9 in unified library
- **Compression**: Optional zlib/zstd support
- **Testing**: Boost Test framework
- **Documentation**: Doxygen generation

### pkg-config Files
```bash
# Core libraries
framecpp.pc          # Main OOInterface library
framecppu.pc         # Universal library (with all versions)
framecppc.pc         # C interface
framecpp_common.pc   # Common utilities

# Version-specific .pc files eliminated
# (framecpp3.pc through framecpp9.pc no longer generated)
```

## Data Types and GPS Time

### Type System
```cpp
// GPS time handling
class GPSTime {
    INT_4U seconds;
    INT_4U nanoseconds;
    // Leap second support
};

// Dimension objects
class Dimension {
    REAL_8 start, deltaX;
    STRING name, unit;
};
```

### Key Type Patterns
- **Consistent Naming**: `*_type` suffix for types
- **GPS Time**: Absolute time reference
- **Multi-dimensional**: Support for arrays and matrices
- **Unit Awareness**: Physical units in metadata

## Testing Framework

### Test Structure
```
test/
├── FrAdcData_test.cc         # Unit tests for ADC data
├── FrProcData_test.cc        # Process data tests
├── IOStream_test.cc          # I/O operation tests
├── Compression_test.cc       # Compression tests
├── CInterface_test.c         # C interface tests
└── Integration_test.cc       # End-to-end tests
```

### Test Categories
- **Unit Tests**: Individual class functionality
- **Integration Tests**: Complete I/O workflows
- **Compression Tests**: Data integrity with compression
- **C Interface Tests**: C API compatibility
- **Performance Tests**: I/O benchmarks

## SWIG Integration

### SWIG-Friendly Design
```cpp
#ifndef SWIGIMPORTED
// C++ specific code
#endif

// Container wrapping support
#ifdef SWIG
%template(FrVectContainer) Container<FrVect>;
#endif
```

### Key SWIG Patterns
- **Conditional Compilation**: `SWIGIMPORTED` guards
- **Template Instantiation**: Explicit %template declarations
- **Container Wrapping**: STL compatibility
- **Exception Translation**: C++ to Python exceptions

## Development Guidelines

### Code Formatting and Style
- **C/C++ Formatting**: All C/C++ files must be formatted using clang-format
- **Configuration**: clang-format configuration file is located in the parent directory
- **Trailing Spaces**: All files must have trailing whitespace removed
- **Standards**: Follow established code style conventions consistently

### When Working with Frame Data
1. **Use Universal Namespace**: All new code should use `FrameCPP::Universal::`
2. **Smart Pointers**: Always use boost::shared_ptr for frame objects
3. **Container Access**: Use iterators for container traversal
4. **Memory Management**: RAII pattern, automatic cleanup

### Performance Considerations
- **Lazy Loading**: Read data only when needed
- **Compression**: Enable for large datasets
- **Buffering**: Use buffered I/O for multiple operations
- **GPS Time**: Cache GPS time calculations

### Error Handling
```cpp
try {
    auto frame = stream.ReadFrame(frameNumber);
    // Process frame
} catch (const FrameCPP::Exception& e) {
    // Handle frame-specific errors
}
```

## Integration Points

### Upstream Dependencies
- **ldastoolsal** - LDAS tools abstraction layer
- **Boost** - Smart pointers, test framework
- **zlib/zstd** - Compression support

### Downstream Users
- **framecpp-swig** - Python bindings (currently broken)
- **frameutils** - Higher-level utilities
- **LIGO/Virgo** - Detector data analysis tools

## Recent Major Improvements

### ✅ GetDescription() Interface Refactoring (2025-01-06)
- **Enhanced Description Class**: Added iterator support and pretty printing capabilities
- **framecpp_dump_descriptions Utility**: New command-line tool with multiple output formats (pretty, compact, CSV)
- **Comprehensive Object Support**: Dynamic casting pattern supports all frame object types
- **Boost Integration**: Added program_options and format libraries for robust CLI interface

### ✅ DRY Code Refactoring (2025-01-06)
- **Eliminated Code Duplication**: FrTOC ClassicIO methods now use C++17 fold expressions
- **Template Metaprogramming**: Single source of truth for base class ordering using std::tuple
- **Protected Method Access**: Helper functions moved inside ClassicIO class for proper inheritance access
- **Load Method Standardization**: Unified signatures across all 9 FrTOC ClassicIO implementations

### ✅ Comprehensive Debugging Framework (2025-08-06)
- **FrTOC Debugging**: Complete debugging framework for all 9 FrTOC components (Data, AdcData, ProcData, SimData, SerData, Event, SimEvent, StatData, Summary)
- **FrEndOfFile Debugging**: Comprehensive debugging for Bytes(), Load(), and Write() methods with version-specific logic
- **Hierarchical Logging**: Channel-based logging system with debug levels (10, 20, 30, 40, 50)
- **Checksum Validation**: Detailed checksum verification logging with dual decimal/hex format
- **DRY Formatting**: Template-based lazy formatting for checksum values using `pretty_print_checksum()`

### ✅ IFrameStreamPlan Unification (2025-12-23)
- **Architectural Simplification**: Eliminated redundant version-specific IFrameStreamPlan classes (Version_5-9)
- **Unified Implementation**: Created single `FrameCPP::IFrameStreamPlan` type in OOInterface that handles all frame versions (v3-v9)
- **Version Auto-Detection**: Proved version template parameter doesn't affect reading capability - file version auto-detected from stream
- **Backward Compatibility**: All version-specific namespaces now provide type aliases to unified class
- **Enhanced TOC Sharing**: Unified type enables TOC sharing across all readers, removing previous template version limitation
- **Cross-Version Reading Test**: Comprehensive test validates Version_N readers can read any version file

### ✅ Version Consolidation (2025-12-27/28)
- **Complete Library Consolidation**: Eliminated 7 version-specific libraries (`libframecpp3-9`), unified into single `libframecppu`
- **Centralized VersionRegistry**: All version specifications (v3-v9) consolidated in `src/Universal/VersionRegistry/`
- **Build System Simplification**: Reduced from 7 libraries with complex dependency chain to single unified library
- **Preserved Git History**: Used `git mv` to move FrameSpec, FrameStream, and FrameStreamPlan files maintaining complete history
- **Full Backward Compatibility**: Legacy include paths (`framecpp/Version9/FrameSpec.hh`) and namespaces (`Version_9::*`) continue to work
- **Clean Build Verification**: All tests pass (100%) on clean build with only 4 core libraries
- **Header Strategy**: Physical files in `VersionRegistry/VersionN/` symlinked to backward-compatible `framecpp/VersionN/` paths
- **Eliminated Files**: Removed 38 redundant files (Types.hh, dummy.cc, TypeInstantiation.tcc, CMakeLists.txt per version)
- **pkg-config Cleanup**: Version-specific .pc files eliminated, only core library .pc files generated

## Known Issues and Solutions

### ✅ FIXED: Duplicate Debug Output in Logging System (2025-08-07)
**Issue**: Multiple identical debug lines appeared for each log message when using framecpp debug channels.

**Root Cause**: Each SimpleLogger constructor was adding a new sink to the global Boost.Log core. When multiple loggers were created (even for different channels), each added its own sink, and all sinks would output every message, resulting in duplicate lines.

**Pattern Observed**:
- 2 lines for FrHeader (default logger + FrHeader logger = 2 sinks)
- 3 lines for FrEndOfFile (+ FrEndOfFile logger = 3 sinks)
- 4 lines for FrTOCData (+ FrTOCData logger = 4 sinks)
- etc.

**Solution Implemented**: Modified SimpleLogger in ldastoolsal to ensure only one console sink is added to the global Boost.Log core, regardless of how many SimpleLogger instances are created.

**Files Modified**:
- `ldastoolsal/src/SimpleLogger.hh` - Added static flag and mutex for global sink management
- `ldastoolsal/src/SimpleLogger.cc` - Modified constructor to check if global sink already exists before adding

## Technical Implementation Details

### GetDescription() System Architecture
```cpp
// Enhanced Description class with iterator support
class Description {
    using container_type = std::vector<FrameSpec>;
    container_type m_specs;
    
public:
    // Iterator support for range-based loops
    auto begin() const { return m_specs.begin(); }
    auto end() const { return m_specs.end(); }
    
    // Pretty printing with boost::format
    void prettyPrint(std::ostream& os, unsigned int indent = 0) const;
};

// Object type mapping for string-based queries
static std::unordered_map<std::string, Common::FrameSpec::Info::frame_spec_id_type> object_type_map = {
    {"FrAdcData", Common::FrameSpec::Info::FSI_FR_ADC_DATA},
    {"FrProcData", Common::FrameSpec::Info::FSI_FR_PROC_DATA},
    {"FrVect", Common::FrameSpec::Info::FSI_FR_VECT},
    // ... complete mapping
};
```

### DRY Refactoring with C++17 Fold Expressions
```cpp
// Single source of truth for base class ordering
using FrTOCBaseClasses = std::tuple<
    FrTOCDataClassicIO,
    FrTOCStatDataClassicIO,
    FrTOCAdcDataClassicIO,
    FrTOCProcDataClassicIO,
    FrTOCSimDataClassicIO,
    FrTOCSerDataClassicIO,
    FrTOCSummaryClassicIO,
    FrTOCEventClassicIO,
    FrTOCSimEventClassicIO
>;

// Automated method calling using fold expressions
template<std::size_t... Is>
void call_all_load_impl(istream_type& stream, INT_4U& nframe, std::index_sequence<Is...>) const {
    (mutable_this->std::tuple_element_t<Is, FrTOCBaseClasses>::Load(stream, nframe), ...);
}
```

### Load Method Signature Standardization
All Load methods now use unified signature: `void Load(istream_type& Stream, INT_4U& nframe)`
- **FrTOCDataClassicIO**: Reads nframe from stream and sets reference parameter
- **Other ClassicIO**: Receive nframe value, can use or ignore as needed
- **Pass-by-reference**: Enables data flow between Load methods in sequence

## Current Status

### ✅ Completed
- Universal namespace migration
- Frame specification version 9 support
- CMake build system modernization
- C++17 standard compliance
- **GetDescription() interface modernization**
- **DRY refactoring with C++17 metaprogramming**
- **Load method signature standardization**
- **framecpp_dump_descriptions utility implementation**
- **IFrameStreamPlan unification** - Single version-agnostic reader type
- **Version Consolidation** - All version specs (v3-v9) in unified library

### ✅ Architecture Status
- **Single Unified Library**: `libframecppu` contains all version specifications
- **Centralized Version Management**: `Universal/VersionRegistry/` for all v3-v9 code
- **Full Backward Compatibility**: Legacy includes and namespaces preserved
- **Simplified Build**: 4 core libraries instead of 11
- **Clean Repository**: No redundant version-specific code

### ⚠️ Known Issues
- **SWIG Bindings**: framecpp-swig template instantiation problems
- **Container Templates**: Complex SWIG integration requires careful management

### 🔄 Active Development
- Performance optimizations
- Extended compression support
- Enhanced error reporting
- Memory usage improvements
- **Testing of new GetDescription() system**
- **Implementation of test data generation utilities**
- **DebugLevelManager utility for comprehensive debug output control**

## Build Commands

### Standard Build
```bash
cd framecpp
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build
```

### Development Build
```bash
cmake -B build -DCMAKE_BUILD_TYPE=Debug -DENABLE_SANITIZERS=ON
cmake --build build
```

## Key Files to Monitor

### Core Headers
- `src/Common/Container.hh` - Container template definitions
- `src/Universal/FrameH.hh` - Frame header structure
- `src/Universal/FrVect.hh` - Vector data structure
- `src/OOInterface/` - Primary C++ API

### Recent Modifications (2025-01-06)

#### GetDescription() System
- `src/Common/Description.hh` - Enhanced with iterator support and pretty printing
- `src/Utilities/framecpp_dump_descriptions.cc` - New CLI utility implementation

#### DRY Refactoring Files
- `src/Universal/impl/FrTOCClassicIO.hh` - C++17 fold expression helpers
- `src/Universal/FrTOC.cc` - Updated template specializations using DRY helpers

#### Load Method Standardization
- `src/Universal/impl/FrTOCDataClassicIO.hh` - Primary Load signature
- `src/Universal/impl/FrTOC*ClassicIO.hh` - All ClassicIO headers updated
- `src/Universal/FrTOCData.cc` - Load implementation with nframe handling
- `src/Universal/FrTOCProcData.cc` - Updated signature and parameter usage
- `src/Universal/FrTOCSimData.cc` - Updated signature and parameter usage
- `src/Universal/FrTOCSerData.cc` - Updated signature and parameter usage
- `src/Universal/FrTOCSummary.cc` - Updated signature and parameter usage
- `src/Universal/FrTOCEvent.cc` - Updated signature (nframe unused)
- `src/Universal/FrTOCStatData.cc` - Updated signature (nframe unused)
- `src/Universal/FrTOCSimEvent.cc` - Updated signature (nframe unused)

### Build Configuration
- `CMakeLists.txt` - Main build configuration
- `src/CMakeLists.txt` - Library build rules (simplified after consolidation)
- `test/CMakeLists.txt` - Test configuration with Boost dependencies

### Version Consolidation (2025-12)

#### VersionRegistry Structure
- `src/Universal/VersionRegistry/VersionRegistry.{cc,hh}` - Central initialization for all versions
- `src/Universal/VersionRegistry/CMakeLists.txt` - Build and header installation
- `src/Universal/VersionRegistry/Version3/FrameSpec.{cc,hh}` - v3 spec registration
- `src/Universal/VersionRegistry/Version4/FrameSpec.{cc,hh}` - v4 spec registration
- `src/Universal/VersionRegistry/Version5/` - v5 spec + FrameStream + FrameStreamPlan
- `src/Universal/VersionRegistry/Version6/` - v6 spec + FrameStream + FrameStreamPlan
- `src/Universal/VersionRegistry/Version7/` - v7 spec + FrameStream + FrameStreamPlan
- `src/Universal/VersionRegistry/Version8/` - v8 spec + FrameStream + FrameStreamPlan + impl
- `src/Universal/VersionRegistry/Version9/` - v9 spec + FrameStream + FrameStreamPlan + impl

#### Updated for Consolidation
- `src/OOInterface/FrameCPP.cc` - Simplified initialization using VersionRegistry
- `src/OOInterface/Types.hh` - Removed version-specific conditional includes
- `src/OOInterface/CMakeLists.txt` - Dependencies simplified to framecppu only
- `src/Universal/CMakeLists.txt` - Added VersionRegistry subdirectory
- `src/Utilities/CMakeLists.txt` - Removed version-specific library dependencies

### SWIG Integration
- Headers with `#ifndef SWIGIMPORTED` guards
- Container template instantiation points
- Exception handling for Python bindings

## Comprehensive Debugging Framework (2025-08-06)

### Overview
FrameCPP implements a comprehensive debugging system that provides detailed tracking of frame I/O operations, table of contents processing, and file-level operations. The system uses hierarchical logging with flexible debug levels and includes a reusable DebugLevelManager for utility applications.

### Debug Level System
- **Flexible levels**: Any integer from 0-100 (not restricted to multiples of 10)
- **Hierarchical channels**: `framecpp.frtoc.{component}` and `framecpp.frendoffile`
- **Typical level conventions**:
  - 0 = No debug output (default)
  - 10 = Entry/exit of major functions
  - 20 = Important values and field information
  - 30 = Detailed operational information
  - 40 = Very verbose output
  - 50 = Extremely detailed debugging
  - Custom levels (11, 25, 33) can be inserted between automated levels for manual debugging

### FrTOC Debugging Components

#### Supported Components
All 9 FrTOC components have dedicated logging channels:
- `framecpp.frtoc.data` - Core FrTOCData operations
- `framecpp.frtoc.adc` - FrTOCAdcData processing
- `framecpp.frtoc.proc` - FrTOCProcData operations
- `framecpp.frtoc.sim` - FrTOCSimData handling
- `framecpp.frtoc.ser` - FrTOCSerData processing
- `framecpp.frtoc.event` - FrTOCEvent operations
- `framecpp.frtoc.simevent` - FrTOCSimEvent handling
- `framecpp.frtoc.stat` - FrTOCStatData processing
- `framecpp.frtoc.summary` - FrTOCSummary operations

#### Key Operations Tracked
- **Bytes()** calculations with field-by-field breakdown
- **Load()** operations with data structure population details
- **write()** operations with stream output tracking
- **Version-specific processing** (v3-v9) with compatibility logic
- **Checksum validation** with dual format display (decimal and hex)

### FrEndOfFile Debugging

#### Channel Configuration
- `framecpp.frendoffile` - All FrEndOfFile operations

#### Detailed Tracking
- **Bytes() method**: Field size calculations for different frame versions
- **Load() method**: Stream reading with checksum verification
- **Write() method**: Stream output with TOC and header checksum tracking
- **Version handling**: v3-v9 compatibility with legacy format processing
- **Error detection**: Comprehensive checksum validation and reporting

### DebugLevelManager Utility System

#### Architecture
- **Inheritance-based Design**: `FrameCPPDebugManager` extends `ldastoolsal::DebugLevelManager`
- **frameCPP-specific Configuration**: Provides frameCPP environment variables and channel examples
- **Clean Interface**: All base class functionality inherited automatically (no delegation boilerplate)

#### Features
- **Command-line integration**: Standard debug options for all utilities via boost::program_options
- **Pattern matching**: Wildcard support for channel specification (e.g., `framecpp.frtoc.*`)
- **Environment variables**: `FRAMECPP_DEBUG_LEVEL`, `FRAMECPP_DEBUG_CHANNELS`
- **Configuration files**: Support for complex debug configurations
- **Cross-project compatibility**: Common interface shared with other LDAS Tools projects

#### Usage Examples

##### Command-Line Usage
```bash
# Set global debug level
framecpp_dump_toc --debug-level 20 file.gwf

# Set channel-specific levels
framecpp_dump_toc --debug-channels "framecpp.frtoc.*:30,framecpp.frendoffile:15" file.gwf

# Use environment variables
export FRAMECPP_DEBUG_LEVEL=25
export FRAMECPP_DEBUG_CHANNELS="framecpp.frtoc.data:30"
framecpp_dump_toc file.gwf

# Show current configuration
framecpp_dump_toc --debug-show file.gwf
```

##### Integration in Applications
```cpp
#include "framecpp/FrameCPPDebugManager.hh"

int main(int argc, char* argv[]) {
    // Initialize frameCPP debug system (uses ldastoolsal core)
    if (!FrameCPP::Utilities::FrameCPPDebugManager::initialize(argc, argv, "framecpp_utility")) {
        return 0; // Help was shown
    }
    
    // Set programmatic levels (inherited from ldastoolsal DebugLevelManager)
    FrameCPP::Utilities::FrameCPPDebugManager::set_global_level(30);
    FrameCPP::Utilities::FrameCPPDebugManager::set_channel_level("framecpp.frtoc.*", 20);
    
    // Library code uses standard logging (unchanged)
    logger_log_debug(logger(), 25, "Debug message at custom level 25");
    
    return 0;
}
```

### Implementation Details

#### Logger Architecture
- **Static logger functions** with lazy initialization (C++11 thread-safe)
- **Channel hierarchy** supporting pattern matching
- **Inheritance-based sharing** between ClassicIO and SerialIO implementations

#### Checksum Formatting
- **DRY principle**: Template-based `ChecksumFormatter` for dual format display
- **Lazy evaluation**: Formatting deferred until stream insertion
- **Consistent output**: All checksums display as "decimal (0xhex)"

#### Example Debug Output
```
[DEBUG:10] FrTOCData::Bytes() entry, stream version 9
[DEBUG:20] FrTOCData::Bytes() main header block: 1024 bytes, nFrames=100
[DEBUG:30] FrTOCData::Load() read nFrame=100
[DEBUG:20] FrEndOfFile::readFromStream() verifying file checksum - calculated: 123456789 (0x75bcd15), stored: 123456789 (0x75bcd15)
```

### Key Files Modified

#### Core Implementation
- `src/Universal/impl/FrTOCDataData.hh` - Base logger and ChecksumFormatter
- `src/Universal/FrTOCData.cc` - Comprehensive Bytes/Load/write debugging
- `src/Universal/impl/FrEndOfFileData.hh` - FrEndOfFile logger support
- `src/Universal/impl/FrEndOfFileClassicIO.hh` - Bytes/Write debugging
- `src/Universal/FrEndOfFile.cc` - Load/assign debugging with checksum validation

#### Debug Management System
- `src/OOInterface/FrameCPPDebugManager.hh` - frameCPP-specific wrapper for ldastoolsal DebugLevelManager
- `test/FrQuery.cc` - Integration example in framecpp_dump_toc utility
- **Inheritance**: Extends `ldastoolsal::DebugLevelManager` for clean code reuse

#### Build System Updates
- `src/Utilities/CMakeLists.txt` - Updated comment referencing ldastoolsal dependency
- `test/CMakeLists.txt` - Integration with framecpp_query utility
- **ldastoolsal Integration**: Core DebugLevelManager implemented in ldastoolsal library

### Benefits
1. **Comprehensive visibility** into frame I/O operations
2. **Flexible debugging** with custom level insertion capability
3. **Clean inheritance design** following DRY principles (no delegation boilerplate)
4. **Reusable infrastructure** shared with other LDAS Tools projects
5. **Performance-conscious** with lazy evaluation
6. **User-friendly** with intuitive command-line options
7. **Production-ready** with runtime configuration support

## Pretty Print Implementation Status (2025-08-07)

### ✅ **COMPLETED**
**Modern Frame Object Pretty Printing System** - Comprehensive boost::serialization-based pretty printing for Frame objects

#### **Build System Integration**
- **DebugArchive**: Fully integrated as static convenience library into framecppcmn
- **Location**: `src/archive/DebugArchive/` with proper CMakeLists.txt integration
- **Architecture**: Header-only implementation with all methods `inline` for template compatibility
- **Legacy Code**: Disabled problematic `framecpp_dump_toc` compilation (preserved for reference)

#### **Core Implementation**
- **DebugArchive Class**: Custom boost::serialization output archive for human-readable debug format
- **FramePrinter Class**: High-level fluent interface in `src/OOInterface/FrameDebugPrint.hh`
- **Three Alignment Modes**: NONE (compact), SEPARATOR (aligned), COLUMNS (tabular)
- **Version Awareness**: Support for frame specification versions v3-v9 with proper field evolution

#### **Key Features Available**
- **Field Name Extraction**: Automatic field name display using boost::serialization::nvp
- **Type Information**: Demangled C++ type names for readable output
- **Configurable Formatting**: Separators, indentation, field/value width control
- **Template Support**: Works with all Frame types through boost::serialization
- **✅ Field Filtering (Phase 1)**: Complete implementation with abstract base class and concrete filters

#### **✅ Phase 1 Completed: Field Filtering System**
- **FieldFilter Abstract Base**: Flexible filtering interface in `DebugArchive.hh`
- **Concrete Filter Classes**: `SkipBinaryData`, `SkipEmptyFields`, `IncludeOnlyFields`, `ExcludeFields`
- **FramePrinter Integration**: `setFieldFilter()` method with fluent interface support
- **Comprehensive Testing**: 4 test cases covering all filter types and method chaining
- **Production Ready**: Selective field display for cleaner debug output

#### **✅ Phase 2 Completed: Value Transformation System**
- **ValueTransformer Abstract Base**: Flexible transformation interface for custom formatting
- **Concrete Transformer Classes**: 
  - `GPSTimeFormatter` - Annotates GPS time fields with epoch reference
  - `HexFormatter` - Adds hexadecimal display for checksums/flags/addresses
  - `SizeFormatter` - Converts byte counts to human-readable units (KB/MB/GB)
  - `CompositeTransformer` - Chains multiple transformers in sequence
- **FramePrinter Integration**: `setValueTransformer()` method with fluent interface support
- **Field + Transform Combination**: Works seamlessly with field filtering
- **Comprehensive Testing**: 5 test cases including composite and combined filter+transform
- **Production Ready**: Human-readable value formatting for better comprehension

#### **✅ Phase 3 Completed: Specialized Formatters**
- **Enhanced GPSTimeFormatter**: Converts GPS seconds to actual date/time strings with fractional seconds
- **BinaryDataFormatter**: Annotates binary data fields for clear identification
- **ArrayFormatter**: Smart truncation for large arrays showing first/last elements
- **FloatFormatter**: Scientific notation for very large/small floating point values
- **EnumFormatter**: Shows bit flags and enum values with symbolic information
- **All Formatters Composable**: Work individually or combined via CompositeTransformer
- **Comprehensive Testing**: 6 test cases covering all specialized formatters
- **Production Ready**: Professional-grade formatting for all common data types

### 🔄 **CURRENT STATE - READY FOR USE**

#### **Immediate Usage Pattern**
```cpp
#include "framecpp/OOInterface/FrameDebugPrint.hh"

// Basic usage with defaults (version=9, SEPARATOR alignment, std::cout)
FrTOCData tocData;
FrameCPP::Debug::FramePrinter printer;
printer(tocData);

// Advanced usage with method chaining and field filtering
FrVect vect;
SkipBinaryData filter;
printer.setAlignment(AlignmentMode::COLUMNS)
       .setVersion(7)
       .setSeparator(" => ")
       .setIndentation(4)
       .setFieldFilter(&filter)
       .showTypeInfo(false);
printer(vect);
```

#### **Available Factory Functions**
```cpp
auto compact_printer = FrameCPP::Debug::compactPrinter(std::cout);
auto aligned_printer = FrameCPP::Debug::alignedPrinter(std::cout);
auto columnar_printer = FrameCPP::Debug::columnarPrinter(std::cout);
```

### 📋 **ENHANCEMENT ROADMAP**

#### **✅ Phase 1: Field Filtering (COMPLETED)**
```cpp
// Field filtering now available with 4 concrete filter classes:
SkipBinaryData filter1;           // Skip compress, data, nBytes fields  
SkipEmptyFields filter2;          // Skip comment, history fields (empty check TBD)
IncludeOnlyFields filter3({"name", "comment"}); // Whitelist approach
ExcludeFields filter4({"compress", "data"});    // Blacklist approach

printer.setFieldFilter(&filter1)(frame_object);
```

#### **✅ Phase 2: Value Transformers (COMPLETED)**
```cpp
// Value transformation now available with 4 concrete transformer classes:
GPSTimeFormatter gps_formatter;    // Adds [GPS seconds since 1980-01-06] annotation
HexFormatter hex_formatter;        // Shows hex for checksum/flag fields (e.g., "123 (0x7b)")
SizeFormatter size_formatter;      // Human-readable sizes (e.g., "1048576 (1.00 MB)")
CompositeTransformer composite;    // Chain multiple transformers together

printer.setValueTransformer(&gps_formatter)(frame_object);

// Combine with field filtering
printer.setFieldFilter(&filter)
       .setValueTransformer(&transformer)
       (frame_object);
```

#### **✅ Phase 3: Specialized Formatters (COMPLETED)**
```cpp
// Enhanced formatters now available with sophisticated formatting:
GPSTimeFormatter gps;              // Shows actual date/time: "1234567890 [2019-02-13 23:31:30 UTC]"
BinaryDataFormatter binary;        // Annotates binary fields: "data [binary field]"
ArrayFormatter array(10, 3);       // Smart truncation: "[1, 2, 3, ... 98, 99, 100 ... truncated]"
FloatFormatter float_fmt(6, 1e6);  // Scientific notation: "1.234568e+09"
EnumFormatter enum_fmt;            // Shows bit flags: "15 [bit0, bit1, bit2, bit3]"

// All formatters work with CompositeTransformer for combined formatting
CompositeTransformer all_formatters;
all_formatters.addTransformer(&gps);
all_formatters.addTransformer(&binary);
// ... add all desired formatters
```

#### **Phase 4: Additional Output Formats (Low Priority)**
- **JsonArchive**: JSON output for structured data export
- **YamlArchive**: YAML output for configuration-style display
- **DiffArchive**: Side-by-side version comparison

#### **Phase 4: Command-Line Utility (Low Priority)**
- **framecpp_dump**: Replace legacy dump utilities with modern implementation
- **Multiple formats**: Support all archive types
- **Frame file integration**: Read and filter frame objects

### 🔧 **Integration with Existing Systems**

#### **Compatibility**
- **Boost.Serialization**: Leverages existing SerialIO save() methods
- **Version Evolution**: Automatic handling of field differences across v3-v9
- **Memory Efficient**: Header-only design with lazy evaluation
- **Thread Safe**: Stateless archive design supports concurrent usage

#### **Test Framework**
- **Location**: `test/test_frame_debug_print.cc`
- **Coverage**: All alignment modes, multiple Frame types, version compatibility
- **Integration**: Uses boost::test framework with manual inspection output

### 📁 **Key Files for Development**
- `src/archive/DebugArchive/DebugArchive.hh` - Core serialization archive implementation
- `src/OOInterface/FrameDebugPrint.hh` - High-level fluent interface and factory functions
- `test/test_frame_debug_print.cc` - Comprehensive test suite with examples
- `src/archive/DebugArchive/DebugArchive.cc` - Minimal build system integration file

## framecpp_dump_toc Migration (2025-12-01)

### ✅ **COMPLETED**
**Version-Aware TOC Dumping for Universal Frame Objects** - Complete rewrite of framecpp_dump_toc to work with Universal namespace and support version-specific output.

#### **Problem Solved**
The legacy framecpp_dump_toc utility used template-based printers (toc*.tcc files) that relied on version-specific frame types that no longer exist after the Universal namespace migration. The old implementation had compilation errors and couldn't work with the modern Universal::FrTOC structure.

#### **Key Challenge: v8 Self-Describing Transition**
Frame specifications v3-v7 use **parallel array format** (not self-describing):
```cpp
// v7 and earlier
std::vector<nameEvent_type> names;
std::vector<nEvent_type> counts;
std::vector<GTimeSEvent_type> times_s;  // Flattened parallel array
std::vector<amplitudeEvent_type> amps;   // Flattened parallel array
```

Frame specifications v8+ use **structured format** (self-describing):
```cpp
// v8+
struct event_type {
    GTimeEvent_type GTime;
    amplitudeEvent_type amplitudeEvent;
    positionEvent_type positionEvent;
};
std::map<nameEvent_type, std::vector<event_type>> events;  // Self-contained structure
```

**Universal Implementation**: Internally stores ALL versions in v9 structured format after Load(), requiring version-aware flattening for v<8 output.

#### **Architecture: Dual-Path Printer**
```
dump_toc.cc
├─> if (version >= 8)
│   └─> ModernTOCPrinter (v8+ with nTotalEvent, no FrStatData in v9)
└─> else (version < 8)
    └─> LegacyTOCPrinter (v3-7 parallel arrays, version-specific field names)
```

#### **Implementation Details**

##### **LegacyTOCPrinter** (v3-7)
- **Purpose**: Reconstructs parallel array format from Universal's v9 structure
- **Field Names**: Version-specific (`nTrig` vs `nEventType`, `nameTrig` vs `nameEvent`)
- **Flattening Logic**: Manually iterates structured events and outputs as parallel arrays
- **FrStatData**: Included for all versions < 9
- **Files**:
  - `test/LegacyTOCPrinter.hh` - Class interface
  - `test/LegacyTOCPrinter.cc` - Implementation with hardcoded version knowledge

##### **ModernTOCPrinter** (v8+)
- **Purpose**: Outputs v8+ format with nTotalEvent field
- **Format**: Maintains parallel array format for consistency, but includes v8+ fields
- **FrStatData**: Only for v8, omitted in v9 (deprecated)
- **Files**:
  - `test/ModernTOCPrinter.hh` - Class interface
  - `test/ModernTOCPrinter.cc` - Implementation with minor v8+ differences

##### **Version Dispatch**
```cpp
const FrameCPP::Universal::FrTOC* toc = dynamic_cast<...>(ifs.GetTOC());
unsigned int version = ifs.Version();

if (version >= 8) {
    ModernTOCPrinter printer(std::cout);
    printer.print(toc, version);
} else {
    LegacyTOCPrinter printer(std::cout);
    printer.print(toc, version);
}
```

#### **Field Caching Strategy**
- **No modifications to Universal::Load()** - Kept existing implementation unchanged
- **GetDescription() as schema oracle** - Determines which fields exist in each version
- **Hardcoded version logic** - Explicit `if (version >= X)` checks for field inclusion
- **Example**: `amplitudeEvent` only printed for v5+, `nTotalEvent` only for v8+

#### **Legacy Files Archived**
```
toc.hh      → toc.hh.legacy      (template dispatch infrastructure)
toc4.tcc    → toc4.tcc.legacy    (v4 printer template)
toc6.tcc    → toc6.tcc.legacy    (v6 printer template)
toc8.tcc    → toc8.tcc.legacy    (v8 printer template)
toc9.tcc    → toc9.tcc.legacy    (v9 printer template)
```

Preserved for reference but removed from build system.

#### **Benefits**
1. **Spec Compliance**: Output matches exact frame specification for each version
2. **Universal Compatible**: Works with modern Universal::FrTOC structure
3. **Version Correct**: v4 shows `nTrig`, v6 shows `amplitudeEvent`, v8 shows `nTotalEvent`
4. **FrStatData Handling**: Correctly omitted for v9 (deprecated), shown for v<9
5. **Maintainable**: Clear separation of v<8 and v8+ logic, no template metaprogramming
6. **Robust Error Handling**: Gracefully handles missing TOC (optional structure)

#### **Error Handling**
- **Missing TOC**: Gracefully handles frame files without TOC (optional structure)
  - GetTOC() throws exception when no TOC present - caught and handled
  - Displays: "No table of contents (TOC) present in this file."
  - Continues processing remaining files instead of crashing
  - Explicit cleanup: IFrameStream deleted before continuing to next file
- **Type Mismatch**: Checks dynamic_cast result for Universal::FrTOC
- **Exception Safety**: All file I/O wrapped in try-catch blocks
- **Clean Exit**: Uses `_exit()` to bypass buggy static destructor mutex cleanup

#### **Testing Validation**
- v4: `nTrig`, no `amplitudeEvent`, parallel arrays
- v6: `nEventType`, has `amplitudeEvent`, parallel arrays, FrStatData present
- v8: `nTotalEvent` field added, FrStatData present
- v9: No FrStatData (deprecated), `fileBaseName` field added
- **Missing TOC**: Files without TOC handled gracefully without crashing

#### **Files Modified**
- `test/dump_toc.cc` - Main program with version dispatch
- `test/LegacyTOCPrinter.hh/cc` - New v3-7 printer
- `test/ModernTOCPrinter.hh/cc` - New v8+ printer
- `test/CMakeLists.txt` - Re-enabled framecpp_dump_toc target
- `test/toc*.{hh,tcc}` - Archived as *.legacy files

## Development Patterns

### C++17 Modern Features Used
- **Fold expressions**: `(expression, ...)` for variadic template expansion
- **std::tuple**: Compile-time type lists for metaprogramming
- **std::index_sequence**: Template parameter pack generation
- **auto return types**: Type deduction for iterators
- **Range-based loops**: Enhanced container iteration

### Error Handling Patterns
```cpp
// Comprehensive input validation
if (object_types.empty()) {
    throw std::invalid_argument("At least one object type must be specified");
}

// Stream state checking
if (!output_stream) {
    throw std::runtime_error("Failed to open output file: " + output_file);
}

// Dynamic cast validation with informative errors
auto* frAdcData = dynamic_cast<const FrameCPP::Universal::FrAdcData*>(object.get());
if (!frAdcData) {
    std::cerr << "Warning: Failed to cast object to FrAdcData" << std::endl;
    continue;
}
```

### Testing Methodology
- **Unit tests**: Individual class functionality
- **Integration tests**: Complete workflows
- **Command-line testing**: Utility validation with various parameters
- **Error case testing**: Invalid input handling verification