# RadioPhotonic PCB — Laser Controller GUI application and embeddable Python module for controlling a dual-laser board over UART (115 200 baud). Designed to run on a Raspberry Pi or any Linux machine. --- ## Project structure ``` . ├── _device_main.py # GUI application entry point ├── gui.py # FreeSimpleGUI layout definition ├── device_interaction.py # High-level device commands (legacy) ├── device_commands.py # Low-level protocol helpers (legacy) ├── device_conversion.py # Physical-unit conversion formulas (legacy) │ ├── laser_control/ # Standalone embeddable module │ ├── __init__.py # Public API │ ├── controller.py # LaserController class │ ├── protocol.py # Command encoding / response decoding │ ├── validators.py # Input validation │ ├── conversions.py # Physical-unit conversions │ ├── models.py # Dataclasses (Measurements, DeviceStatus, …) │ ├── constants.py # Protocol constants and physical limits │ ├── exceptions.py # Exception hierarchy │ └── example_usage.py # Usage examples │ ├── tests/ # pytest test suite (75 tests) │ ├── conftest.py │ ├── test_validation.py │ ├── test_protocol.py │ └── test_integration.py │ ├── pyproject.toml # Package metadata (laser_control) ├── run # Launch script for the GUI app └── deploy # First-time environment setup script ``` --- ## Setting up the virtual environment ### First-time setup ```bash # 1. Create virtual environment python3 -m venv .venv # 2. Activate it source .venv/bin/activate # 3. Install GUI and serial dependencies pip install -r requirements.txt # 4. Install laser_control as an editable package # (required for imports to work in any subdirectory) pip install -e . # 5. Install pytest (for running tests) pip install pytest ``` ### Every subsequent session ```bash source .venv/bin/activate ``` --- ## Running the GUI application ```bash source .venv/bin/activate ./run # or directly: python3 _device_main.py ``` The application auto-detects the USB serial port. If more than one port is present, the first one found is used. --- ## Running the tests ```bash source .venv/bin/activate python3 -m pytest tests/ -v ``` Expected result: **75 passed**. --- ## Running the usage example ```bash source .venv/bin/activate # Auto-detect port: python3 laser_control/example_usage.py # Specify port explicitly: python3 laser_control/example_usage.py /dev/ttyUSB0 ``` --- ## Embedding laser_control in another application After `pip install -e .` (or copying the `laser_control/` folder into your project and running `pip install -e .` there), import as follows: ```python from laser_control import ( LaserController, VariationType, ValidationError, CommunicationError, ) # --- Manual mode --- with LaserController(port='/dev/ttyUSB0') as ctrl: try: ctrl.set_manual_mode( temp1=25.0, # °C [15 … 40] temp2=30.0, # °C [15 … 40] current1=40.0, # mA [15 … 60] current2=35.0, # mA [15 … 60] ) data = ctrl.get_measurements() if data: print(f"3.3 V rail: {data.voltage_3v3:.3f} V") print(f"Laser 1 temperature: {data.temp1:.2f} °C") except ValidationError as e: print(f"Bad parameter: {e}") except CommunicationError as e: print(f"Device not responding: {e}") # --- Current variation mode --- def on_data(m): print(f"I1={m.current1:.3f} mA T1={m.temp1:.2f} °C") with LaserController(port=None, on_data=on_data) as ctrl: # port=None → auto-detect ctrl.start_variation( variation_type=VariationType.CHANGE_CURRENT_LD1, params={ 'min_value': 20.0, # mA 'max_value': 50.0, # mA 'step': 0.5, # mA [0.002 … 0.5] 'time_step': 50, # µs [20 … 100] 'delay_time': 5, # ms [3 … 10] 'static_temp1': 25.0, 'static_temp2': 30.0, 'static_current1': 35.0, 'static_current2': 35.0, } ) import time; time.sleep(2) ctrl.stop_task() ``` ### Parameter limits | Parameter | Min | Max | Unit | |---|---|---|---| | Temperature (T1, T2) | 15.0 | 40.0 | °C | | Current (I1, I2) | 15.0 | 60.0 | mA | | Current variation step | 0.002 | 0.5 | mA | | Temperature variation step | 0.05 | 1.0 | °C | | Time step | 20 | 100 | µs | | Delay time | 3 | 10 | ms | ### Exception hierarchy ``` LaserControlError ├── ValidationError │ ├── TemperatureOutOfRangeError │ ├── CurrentOutOfRangeError │ └── InvalidParameterError ├── CommunicationError │ ├── PortNotFoundError │ ├── DeviceNotRespondingError │ ├── CRCError │ └── ProtocolError └── DeviceError ├── DeviceOverheatingError ├── PowerSupplyError └── DeviceStateError ``` --- ## Device output Each measurement response contains: | Field | Description | Unit | |---|---|---| | `temp1`, `temp2` | Laser temperatures | °C | | `temp_ext1`, `temp_ext2` | External thermistor temperatures | °C | | `current1`, `current2` | Photodiode currents | mA | | `voltage_3v3` | 3.3 V power rail | V | | `voltage_5v1`, `voltage_5v2` | 5 V power rails | V | | `voltage_7v0` | 7 V power rail | V |