#!/usr/bin/env python3 """ Global Clock - Timestamp Synchronization ========================================= Singleton clock for synchronizing timestamps across UART, I2C, and other modules. All timestamps use the same time reference (app start), enabling: - Aligned plotting of UART and I2C data - Consistent timeline across all modules - Database storage with unified timestamp column Usage: from global_clock import GlobalClock clock = GlobalClock.instance() timestamp = clock.now() # Seconds since app start Author: Kynsight Version: 1.0.0 """ import time from typing import Optional class GlobalClock: """ Singleton clock for application-wide timestamp synchronization. Uses monotonic time (time.perf_counter) for stability. All timestamps are relative to application start time. """ _instance: Optional['GlobalClock'] = None def __init__(self): """Initialize clock at application start.""" self._start_time = time.perf_counter() @classmethod def instance(cls) -> 'GlobalClock': """Get singleton instance (creates if needed).""" if cls._instance is None: cls._instance = GlobalClock() return cls._instance def now(self) -> float: """ Get current timestamp in seconds since app start. Returns: float: Time in seconds (e.g., 123.456789) """ return time.perf_counter() - self._start_time def now_ns(self) -> int: """ Get current timestamp in nanoseconds since app start. Returns: int: Time in nanoseconds """ return int((time.perf_counter() - self._start_time) * 1_000_000_000) def reset(self): """Reset clock to zero (useful for testing or new sessions).""" self._start_time = time.perf_counter() # ============================================================================= # Module-level convenience functions # ============================================================================= def now() -> float: """ Get current timestamp (seconds since app start). Convenience function for GlobalClock.instance().now() """ return GlobalClock.instance().now() def now_ns() -> int: """ Get current timestamp (nanoseconds since app start). Convenience function for GlobalClock.instance().now_ns() """ return GlobalClock.instance().now_ns() # ============================================================================= # Demo # ============================================================================= if __name__ == "__main__": import time as time_module print("Global Clock Demo") print("=" * 50) # Get clock instance clock = GlobalClock.instance() print(f"App start time: {clock.now():.6f}s") # Simulate some operations time_module.sleep(0.1) print(f"After 100ms: {clock.now():.6f}s") time_module.sleep(0.2) print(f"After 300ms total: {clock.now():.6f}s") # Nanosecond precision print(f"\nNanoseconds: {clock.now_ns()} ns") # Demonstrate synchronization print("\n" + "=" * 50) print("Synchronization Demo:") print("=" * 50) uart_timestamp = clock.now() print(f"UART packet at: {uart_timestamp:.6f}s") time_module.sleep(0.05) i2c_timestamp = clock.now() print(f"I2C reading at: {i2c_timestamp:.6f}s") print(f"\nTime difference: {(i2c_timestamp - uart_timestamp)*1000:.2f}ms") print("✓ Both timestamps use same reference!")