Source code for trgenpy.configuration

"""
TrGEN Configuration Management for Python

This module provides classes and utilities for exporting and importing TrGEN configurations
to/from JSON files with .trgen extension. It supports full trigger port configurations
including memory instructions, network settings, and metadata.

Classes:
    TrgenConfiguration: Main configuration container
    ConfigurationMetadata: Configuration file metadata
    DefaultSettings: Default trigger settings
    TriggerPortConfig: Individual trigger port configuration
    NetworkSettings: Network connection settings
    PortProgrammingState: Enumeration for port programming states
"""

import json
import os
from datetime import datetime
from enum import Enum
from typing import Dict, List, Optional, Any
from .trgen_pin import TrgenPin


[docs] class PortProgrammingState(Enum): """ Represents the programming state of a trigger port. """ NOT_PROGRAMMED = "not_programmed" PROGRAMMED = "programmed" RESET = "reset" UNKNOWN = "unknown"
[docs] class ConfigurationMetadata: """ Metadata for TrGEN configuration files. Contains information about the configuration file such as version, dates, author, etc. """ def __init__(self): self.version = "1.0" self.created_at = datetime.now() self.modified_at = datetime.now() self.description = "" self.project_name = "" self.author = ""
[docs] def to_dict(self) -> Dict[str, Any]: """Convert metadata to dictionary for JSON serialization.""" return { "version": self.version, "created_at": self.created_at.isoformat(), "modified_at": self.modified_at.isoformat(), "description": self.description, "project_name": self.project_name, "author": self.author }
[docs] @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'ConfigurationMetadata': """Create metadata instance from dictionary.""" metadata = cls() metadata.version = data.get("version", "1.0") metadata.created_at = datetime.fromisoformat(data.get("created_at", datetime.now().isoformat())) metadata.modified_at = datetime.fromisoformat(data.get("modified_at", datetime.now().isoformat())) metadata.description = data.get("description", "") metadata.project_name = data.get("project_name", "") metadata.author = data.get("author", "") return metadata
[docs] class DefaultSettings: """ Default settings for all triggers in the configuration. Contains global default values that apply to all trigger ports. """ def __init__(self): self.default_trigger_duration_us = 20 # Changed from 40 to 20 as per request self.default_log_level = "warn" self.default_timeout_ms = 2000 self.auto_reset_enabled = True self.auto_reset_delay_us = 100
[docs] def to_dict(self) -> Dict[str, Any]: """Convert default settings to dictionary for JSON serialization.""" return { "default_trigger_duration_us": self.default_trigger_duration_us, "default_log_level": self.default_log_level, "default_timeout_ms": self.default_timeout_ms, "auto_reset_enabled": self.auto_reset_enabled, "auto_reset_delay_us": self.auto_reset_delay_us }
[docs] @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'DefaultSettings': """Create default settings instance from dictionary.""" settings = cls() settings.default_trigger_duration_us = data.get("default_trigger_duration_us", 20) settings.default_log_level = data.get("default_log_level", "warn") settings.default_timeout_ms = data.get("default_timeout_ms", 2000) settings.auto_reset_enabled = data.get("auto_reset_enabled", True) settings.auto_reset_delay_us = data.get("auto_reset_delay_us", 100) return settings
[docs] class TriggerPortConfig: """ Configuration for a specific trigger port. Contains all the information needed to configure and program a single trigger port, including its memory instructions and settings. """ def __init__(self, memory_length: int = 32): self.id = 0 self.name = "" self.type = "" self.enabled = True self.custom_duration_us = None self.memory_instructions = [0] * memory_length self.memory_length = memory_length self.last_instruction_index = -1 self.programming_state = PortProgrammingState.NOT_PROGRAMMED self.last_programmed_at = None self.notes = "" self.custom_settings = {}
[docs] def set_memory_from_trgen_port(self, trgen_port): """ Set the memory content from a TrgenPort object. Args: trgen_port: TrgenPort instance to copy memory from """ if trgen_port is None: raise ValueError("trgen_port cannot be None") self.id = trgen_port.id self.type = trgen_port.type self.memory_length = len(trgen_port.memory) self.memory_instructions = trgen_port.memory.copy() # Find last valid instruction self._find_last_instruction_index() # Update programming state self.programming_state = (PortProgrammingState.PROGRAMMED if self.last_instruction_index >= 0 else PortProgrammingState.NOT_PROGRAMMED) self.last_programmed_at = datetime.now()
[docs] def apply_to_trgen_port(self, trgen_port): """ Apply this configuration to a TrgenPort object. Args: trgen_port: TrgenPort instance to apply configuration to """ if trgen_port is None: raise ValueError("trgen_port cannot be None") if trgen_port.id != self.id: raise ValueError(f"ID mismatch: TrgenPort has ID {trgen_port.id}, configuration has ID {self.id}") # Apply memory instructions copy_length = min(len(self.memory_instructions), len(trgen_port.memory)) for i in range(copy_length): trgen_port.setInstruction(i, self.memory_instructions[i])
def _find_last_instruction_index(self): """Find the index of the last valid instruction in memory.""" self.last_instruction_index = -1 for i in range(len(self.memory_instructions) - 1, -1, -1): if self.memory_instructions[i] != 0: self.last_instruction_index = i break
[docs] def has_programmed_instructions(self) -> bool: """Check if the port has programmed instructions.""" return self.last_instruction_index >= 0
[docs] def get_instructions_string(self) -> str: """Get a string representation of the programmed instructions.""" if not self.has_programmed_instructions(): return "No instructions programmed" instructions = [] for i in range(self.last_instruction_index + 1): instructions.append(f"[{i}]: 0x{self.memory_instructions[i]:08X}") return ", ".join(instructions)
[docs] def to_dict(self) -> Dict[str, Any]: """Convert trigger port config to dictionary for JSON serialization.""" return { "id": self.id, "name": self.name, "type": self.type, "enabled": self.enabled, "custom_duration_us": self.custom_duration_us, "memory_instructions": self.memory_instructions, "memory_length": self.memory_length, "last_instruction_index": self.last_instruction_index, "programming_state": self.programming_state.value, "last_programmed_at": self.last_programmed_at.isoformat() if self.last_programmed_at else None, "notes": self.notes, "custom_settings": self.custom_settings }
[docs] @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'TriggerPortConfig': """Create trigger port config instance from dictionary.""" memory_length = data.get("memory_length", 32) config = cls(memory_length) config.id = data.get("id", 0) config.name = data.get("name", "") config.type = data.get("type", "") config.enabled = data.get("enabled", True) config.custom_duration_us = data.get("custom_duration_us") config.memory_instructions = data.get("memory_instructions", [0] * memory_length) config.last_instruction_index = data.get("last_instruction_index", -1) config.programming_state = PortProgrammingState(data.get("programming_state", "not_programmed")) config.notes = data.get("notes", "") config.custom_settings = data.get("custom_settings", {}) last_programmed_str = data.get("last_programmed_at") if last_programmed_str: config.last_programmed_at = datetime.fromisoformat(last_programmed_str) return config
[docs] class NetworkSettings: """ Network configuration settings for TrGEN device connection. Contains IP address, port, and timeout settings. """ def __init__(self): self.ip_address = "192.168.123.1" self.port = 4242 self.timeout_ms = 2000
[docs] def to_dict(self) -> Dict[str, Any]: """Convert network settings to dictionary for JSON serialization.""" return { "ip_address": self.ip_address, "port": self.port, "timeout_ms": self.timeout_ms }
[docs] @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'NetworkSettings': """Create network settings instance from dictionary.""" settings = cls() settings.ip_address = data.get("ip_address", "192.168.123.1") settings.port = data.get("port", 4242) settings.timeout_ms = data.get("timeout_ms", 2000) return settings
[docs] class TrgenConfiguration: """ Main configuration class that contains all TrGEN settings. This is the root configuration object that gets serialized to/from JSON files. """ def __init__(self): self.metadata = ConfigurationMetadata() self.defaults = DefaultSettings() self.trigger_ports = {} # Dict[str, TriggerPortConfig] self.network = NetworkSettings()
[docs] def to_dict(self) -> Dict[str, Any]: """Convert configuration to dictionary for JSON serialization.""" return { "metadata": self.metadata.to_dict(), "defaults": self.defaults.to_dict(), "trigger_ports": {key: port.to_dict() for key, port in self.trigger_ports.items()}, "network": self.network.to_dict() }
[docs] @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'TrgenConfiguration': """Create configuration instance from dictionary.""" config = cls() config.metadata = ConfigurationMetadata.from_dict(data.get("metadata", {})) config.defaults = DefaultSettings.from_dict(data.get("defaults", {})) config.network = NetworkSettings.from_dict(data.get("network", {})) # Load trigger ports trigger_ports_data = data.get("trigger_ports", {}) for key, port_data in trigger_ports_data.items(): config.trigger_ports[key] = TriggerPortConfig.from_dict(port_data) return config