# team1k Python control library and server for the TEAM1k X-ray detector. Communicates directly with the detector FPGA via UDP, replacing the previous `k_test` C++ program. Uses EPICS PV Access (PVA) for command/status and ZMQ for bulk data transfer. ## Architecture ``` Client machine Detector machine +--------------+ +-------------------------------+ | | PVA (commands/status) | team1k-server | | Client |<---------------------->| Register I/O (UDP:42000) | | | | PVA server | | | ZMQ (frame data) | PVA streamer thread | | |<---------------------->| Frame capture thread | | | | ZMQ data transfer thread | +--------------+ | | | Acquisition subprocess | | UDP data recv (UDP:41000) | | Frame assembly | | -> locking_shmring | +-------------------------------+ ``` ## Installation ```bash pip install . ``` For HDF5 support (optional): ```bash pip install ".[hdf5]" ``` ### Dependencies - `locking_shmring` — shared memory ring buffer (must be installed separately) - `p4p` — EPICS PV Access for Python - `pyzmq` — ZeroMQ for bulk data transfer - `numpy`, `pyserial` ## Running the server ```bash team1k-server --detector-ip 10.0.0.32 --log-level INFO ``` All options: ``` --detector-ip Detector IP address (default: 10.0.0.32) --register-port Detector register port (default: 42000) --data-port Detector data port (default: 41000) --pv-prefix PVA prefix (default: TEAM1K:) --zmq-port ZMQ data transfer port (default: 42005) --config Parameter file to apply on startup --bellow-port Bellow stage serial port (default: /dev/CameraBellowStage) --log-level DEBUG, INFO, WARNING, ERROR (default: INFO) ``` ## Client usage ### Acquire frames ```python from team1k import Client, ExposureModes client = Client(data_host="detector-machine") # Configure client.set_exposure_mode(ExposureModes.GLOBAL_SHUTTER_CDS) client.set_integration_time(6.0) # ms # One-shot: start DAQ, capture 100 frames, stop DAQ frames = client.acquire_frames(100) print(frames.shape) # (100, 1024, 1024) print(frames.dtype) # uint16 client.close() ``` ### Manual DAQ control ```python client = Client(data_host="detector-machine") client.start_daq() # Grab frames from the running stream batch1 = client.get_frames(50) batch2 = client.get_frames(50) client.stop_daq() client.close() ``` ### Live image monitoring ```python client = Client() def on_frame(image): print(f"Frame received: {image.shape}") client.monitor_image(on_frame) # ... later client.stop_monitor("IMAGE") client.close() ``` ### Status ```python client = Client() print(client.get_status()) print(client.is_acquiring()) print(client.get_frame_rate()) print(client.get_exposure_mode()) print(client.get_integration_time()) client.close() ``` ### Other commands ```python client.set_trigger_mode(TriggerModes.EXTERNAL) client.set_adc_clock_freq(60.0) # MHz client.set_adc_data_delay(0x1A7) client.load_parameter_file("/path/to/params.txt") client.set_test_mode(True) # FPGA test pattern client.reset_connection() # Peripherals client.insert_detector() client.retract_detector() client.power_on() client.power_off() ``` ## PV Access interface All PVs are prefixed with `TEAM1K:` by default. ### Status PVs (read-only) | PV | Type | Description | |----|------|-------------| | `STATUS` | string[] | Server status | | `ACQUIRING` | bool | DAQ running | | `FRAME_RATE` | float | Current frame rate (Hz) | | `FRAME_COUNT` | int | Total frames acquired | | `EXPOSURE_MODE` | int | Current exposure mode (0-3) | | `TRIGGER_MODE` | int | Current trigger mode | | `INTEGRATION_TIME` | float | Integration time (ms) | | `CAPTURE:STATUS` | string | IDLE / CAPTURING / READY / ERROR | | `CAPTURE:PROGRESS` | int | Frames captured so far | | `CAPTURE:TOTAL` | int | Frames requested | | `IMAGE` | NTNDArray | Live image stream | ### Command PVs (writable) | PV | Type | Description | |----|------|-------------| | `CMD:EXPOSURE_MODE` | int | Set exposure mode | | `CMD:TRIGGER_MODE` | int | Set trigger mode | | `CMD:INTEGRATION_TIME` | float | Set integration time (ms) | | `CMD:START_DAQ` | int | 1=start, 0=stop | | `CMD:CAPTURE` | int | Capture N frames | | `CMD:ADC_CLOCK_FREQ` | float | Set ADC clock (MHz) | | `CMD:ADC_DATA_DELAY` | int | Set ADC data delay | | `CMD:PARAMETER_FILE` | string | Apply parameter file | | `CMD:RESET` | int | 1=reset connection | | `CMD:TEST_MODE` | int | 1=enable FPGA test data | ## Package structure ``` src/team1k/ detector/ # Direct UDP communication with detector FPGA udp_transport.py # Low-level UDP socket registers.py # Register read/write protocol data_port.py # Data port + loopback registration chip_config.py # Chip constants (1024x1024, packet layout) commands.py # Detector commands (exposure, trigger, etc.) adc.py # Si570 I2C clock programming parameter_file.py # Parameter file parser acquisition/ # High-throughput data path receiver.py # Acquisition subprocess (UDP -> shmring) filewriter/ # On-demand frame capture capture.py # FrameCapture + ZMQ DataTransferServer pva/ # EPICS PV Access interface.py # PVA server, command/status PVs streamer.py # shmring -> NTNDArray live stream peripherals/ # Hardware peripherals bellow_stage.py # Camera bellow stage (serial) power_supply.py # Power supply control server.py # Main server entry point Client.py # PVA + ZMQ client library ```