"""SCPI command parsing. This module provides SCPI (Standard Commands for Programmable Instruments) command parsing for instrument communication. It handles IEEE 488.2 common commands (*IDN?, *RST, etc.) and instrument-specific commands. """ from dataclasses import dataclass @dataclass class SCPICommand: """Parsed SCPI command. Attributes: header: The command header (e.g., "TEMP:SETPOINT" or "*IDN"). arguments: List of command arguments (e.g., ["85.0"]). is_query: True if the command ends with '?' (query command). """ header: str arguments: list[str] is_query: bool @property def keyword(self) -> str: """Return the command keyword without '?'. For query commands like "TEMP:SETPOINT?", returns "TEMP:SETPOINT". For regular commands like "VOLT", returns "VOLT". """ return self.header.rstrip("?") class SCPIParser: """Parse SCPI command strings. Handles both IEEE 488.2 common commands (e.g., *IDN?, *RST) and instrument-specific commands (e.g., VOLT 3.3, TEMP:SETPOINT?). Examples: >>> parser = SCPIParser() >>> cmd = parser.parse("*IDN?") >>> cmd.header, cmd.is_query ('*IDN?', True) >>> cmd = parser.parse("VOLT 3.3") >>> cmd.header, cmd.arguments ('VOLT', ['3.3']) """ def parse(self, command_string: str) -> SCPICommand: """Parse a SCPI command string. Args: command_string: The raw SCPI command string to parse. Returns: SCPICommand with parsed header, arguments, and query flag. Examples: "*IDN?" -> SCPICommand("*IDN?", [], True) "VOLT 3.3" -> SCPICommand("VOLT", ["3.3"], False) "TEMP:SETPOINT?" -> SCPICommand("TEMP:SETPOINT?", [], True) "CONF:VOLT:DC 10,0.001" -> SCPICommand("CONF:VOLT:DC", ["10", "0.001"], False) """ command_string = command_string.strip() if not command_string: return SCPICommand(header="", arguments=[], is_query=False) # Split into header and arguments on first whitespace parts = command_string.split(None, 1) header = parts[0] arguments: list[str] = [] if len(parts) > 1: # Parse comma-separated arguments arg_string = parts[1] arguments = [arg.strip() for arg in arg_string.split(",")] # Query is determined by whether the header ends with '?' is_query = header.endswith("?") return SCPICommand( header=header, arguments=arguments, is_query=is_query, )