Source code for iio_attr

#!/usr/bin/env python
"""
Copyright (C) 2020 Analog Devices, Inc.
Author: Cristian Iacob <cristian.iacob@analog.com>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
"""

import sys
import argparse
import iio


def _str_match(string, other_string, ignore_case):
    if ignore_case:
        string = string.lower()
        other_string = other_string.lower()

    return string == other_string


[docs] class Arguments: """Class for parsing the input arguments.""" def __init__(self): """Arguments class constructor.""" self.device = None self.channel = None self.attr = None self.buffer = None self.search_context = False self.search_device = False self.search_channel = False self.search_buffer = False self.search_debug = False self.detect_context = None self.arg_uri = None self.input_only = None self.output_only = None self.scan_only = None self.ignore_case = None self.quiet = None self.parser = argparse.ArgumentParser(description="iio_attr") self._add_required_mutex_group() self._add_help_group() self._add_context_group() self._add_channel_group() args = self.parser.parse_args() self._read_arguments(args) def _add_required_mutex_group(self): self._required_mutex_group = self.parser.add_mutually_exclusive_group(required=True) self._required_mutex_group.add_argument("-d", "--device-attr", type=str, metavar="", nargs="*", help="Usage: [device] [attr] [value]\nRead/Write device attributes") self._required_mutex_group.add_argument("-c", "--channel-attr", type=str, metavar="", nargs="*", help="Usage: [device] [channel] [attr] [value]\n" "Read/Write channel attributes.") self._required_mutex_group.add_argument("-B", "--buffer-attr", type=str, metavar="", nargs="*", help="Usage: [device] [attr] [value]\nRead/Write buffer attributes.") self._required_mutex_group.add_argument("-D", "--debug-attr", type=str, metavar="", nargs="*", help="Usage: [device] [attr] [value]\nRead/Write debug attributes.") self._required_mutex_group.add_argument("-C", "--context-attr", type=str, metavar="", nargs="*", help="Usage: [attr]\nRead IIO context attributes.") def _add_help_group(self): self._help_group = self.parser.add_argument_group("General") self._help_group.add_argument("-I", "--ignore-case", action="store_true", help="Ignore case distinctions.") self._help_group.add_argument("-q", "--quiet", action="store_true", help="Return result only.") def _add_context_group(self): self._context_group = self.parser.add_argument_group("Context connection") self._context_group.add_argument("-u", "--uri", metavar="", type=str, nargs=1, help="Use the context at the provided URI.") self._context_group.add_argument("-a", "--auto", action="store_true", help="Use the first context found.") def _add_channel_group(self): self._channel_group = self.parser.add_argument_group("Channel qualifiers") self._channel_group.add_argument("-i", "--input-channel", action="store_true", help="Filter Input Channels only.") self._channel_group.add_argument("-o", "--output-channel", action="store_true", help="Filter Output Channels only.") self._channel_group.add_argument("-s", "--scan-channel", action="store_true", help="Filter Scan Channels only.") def _read_optional_arguments(self, args): self.detect_context = args.auto self.arg_uri = args.uri[0] if args.uri is not None else None self.input_only = args.input_channel self.output_only = args.output_channel self.scan_only = args.scan_channel self.ignore_case = args.ignore_case self.quiet = args.quiet def _read_device_arguments(self, args): if len(args.device_attr) >= 4: print("Too many options for searching for device attributes") sys.exit(1) self.search_device = True self.device = args.device_attr[0] if len(args.device_attr) >= 1 else None self.attr = args.device_attr[1] if len(args.device_attr) >= 2 else None self.buffer = args.device_attr[2] if len(args.device_attr) >= 3 else None def _read_channel_arguments(self, args): if len(args.channel_attr) >= 5: print("Too many options for searching for channel attributes") sys.exit(1) self.search_channel = True self.device = args.channel_attr[0] if len(args.channel_attr) >= 1 else None self.channel = args.channel_attr[1] if len(args.channel_attr) >= 2 else None self.attr = args.channel_attr[2] if len(args.channel_attr) >= 3 else None self.buffer = args.channel_attr[3] if len(args.channel_attr) >= 4 else None def _read_buffer_arguments(self, args): if len(args.buffer_attr) >= 4: print("Too many options for searching for buffer attributes") sys.exit(1) self.search_buffer = True self.device = args.buffer_attr[0] if len(args.buffer_attr) >= 1 else None self.attr = args.buffer_attr[1] if len(args.buffer_attr) >= 2 else None self.buffer = args.buffer_attr[2] if len(args.buffer_attr) >= 3 else None def _read_debug_arguments(self, args): if len(args.debug_attr) >= 4: print("Too many options for searching for debug attributes") sys.exit(1) self.search_debug = True self.device = args.debug_attr[0] if len(args.debug_attr) >= 1 else None self.attr = args.debug_attr[1] if len(args.debug_attr) >= 2 else None self.buffer = args.debug_attr[2] if len(args.debug_attr) >= 3 else None def _read_context_arguments(self, args): if len(args.context_attr) >= 2: print("Too many options for searching for context attributes") sys.exit(1) self.search_context = True self.attr = args.context_attr[0] if len(args.context_attr) >= 1 else None def _read_arguments(self, args): self._read_optional_arguments(args) if args.device_attr is not None: self._read_device_arguments(args) if args.channel_attr is not None: self._read_channel_arguments(args) if args.buffer_attr is not None: self._read_buffer_arguments(args) if args.debug_attr is not None: self._read_debug_arguments(args) if args.context_attr is not None: self._read_context_arguments(args)
[docs] class ContextBuilder: """Class for creating the requested context.""" def __init__(self, arguments): """ Class constructor. Args: arguments: type=Arguments Contains the input arguments. """ self.ctx = None self.arguments = arguments def _auto(self): contexts = iio.scan_contexts() if len(contexts) == 0: raise Exception("No IIO context found.\n") if len(contexts) == 1: uri, _ = contexts.popitem() self.ctx = iio.Context(_context=uri) else: print("Multiple contexts found. Please select one using --uri!") for uri, _ in contexts.items(): print(uri) sys.exit(0) return self def _uri(self): self.ctx = iio.Context(_context=self.arguments.arg_uri) return self def _default(self): self.ctx = iio.Context() return self
[docs] def create(self): """Create the requested context.""" try: if self.arguments.detect_context: self._auto() elif self.arguments.arg_uri: self._uri() else: self._default() except FileNotFoundError: raise Exception("Unable to create IIO context!\n") return self.ctx
[docs] class Information: """Class for receiving the requested information about the attributes.""" def __init__(self, arguments, context): """ Class constructor. Args: arguments: type=Arguments Contains the input arguments. context: type=iio.Context The created context. """ self.arguments = arguments self.context = context
[docs] def write_information(self): """Write the requested information.""" self._context_information() if self.arguments.search_device or self.arguments.search_channel or \ self.arguments.search_buffer or self.arguments.search_debug: self._devices_information()
def _context_information(self): if self.context is None: print("Unable to create IIO context") sys.exit(1) if self.arguments.search_context: if self.arguments.attr is None and len(self.context.attrs) > 0: print("IIO context with " + str(len(self.context.attrs)) + " attributes:") for key, value in self.context.attrs.items(): if self.arguments.attr is None or \ _str_match(key, self.arguments.attr, self.arguments.ignore_case): print(key + ": " + value) def _devices_information(self): if self.arguments.device is None: print("IIO context has " + str(len(self.context.devices)) + " devices:") for dev in self.context.devices: self._device_information(dev) self._device_attributes_information(dev) self._buffer_attributes_information(dev) self._debug_attributes_information(dev) def _device_information(self, dev): if self.arguments.device is not None and \ not _str_match(dev.name, self.arguments.device, self.arguments.ignore_case): return if self.arguments.device is None: print("\t" + dev.id + ":", end="") if dev.name is not None: print(" " + dev.name, end="") print(", ", end="") if self.arguments.search_channel and self.arguments.device is None: print("found " + str(len(dev.channels)) + " channels") for channel in dev.channels: self._channel_information(dev, channel) def _channel_information(self, dev, channel): channel_stop = not self.arguments.search_channel or self.arguments.device is None input_stop = self.arguments.input_only and channel.output output_stop = self.arguments.output_only and not channel.output scan_stop = self.arguments.scan_only and not channel.scan_element if channel_stop or input_stop or output_stop or scan_stop: return type_name = "output" if channel.output else "input" if not _str_match(self.arguments.device, dev.name, self.arguments.ignore_case): return if self.arguments.channel is not None and \ not _str_match(channel.id, self.arguments.channel, self.arguments.ignore_case) and \ (channel.name is None or (channel.name is not None and not _str_match(channel.name, self.arguments.channel, self.arguments.ignore_case))): return if (not self.arguments.scan_only and self.arguments.channel is None) or \ (self.arguments.scan_only and channel.scan_element): print("dev \'" + dev.name + "\', channel \'" + channel.id + "\'", end="") if channel.name is not None: print(", id \'" + channel.name + "\'", end="") print(" (" + type_name, end="") if channel.scan_element: self._scan_channel_information(channel) else: print("), ", end="") self._channel_attributes_information(dev, channel) def _scan_channel_information(self, channel): sign = "s" if channel.data_format.is_signed else "u" if channel.data_format.is_fully_defined: sign = sign.upper() if channel.data_format.repeat > 1: print("X" + str(channel.data_format.repeat), end="") print(", index: " + str(channel.index) + ", format: " + "b" if channel.data_format.is_be else "l" + "e:" + sign + str(channel.data_format.bits) + "/" + str(channel.data_format.length) + str(channel.data_format.repeat) + ">>" + str(channel.data_format.shift)) print("" if self.arguments.scan_only else ", ", end="") def _channel_attributes_information(self, dev, channel): if self.arguments.channel is None: print("found " + str(len(channel.attrs)) + " channel-specific attributes") if len(channel.attrs) == 0 or self.arguments.channel is None: return for key, _ in channel.attrs.items(): if self.arguments.attr is not None and \ not _str_match(key, self.arguments.attr, self.arguments.ignore_case): continue self._channel_attribute_information(dev, channel, key) def _channel_attribute_information(self, dev, channel, attr): if self.arguments.buffer is None or not self.arguments.quiet: type_name = "output" if channel.output else "input" if not self.arguments.quiet: print("dev \'" + dev.name + "\', channel \'" + channel.id + "\' (" + type_name + "), ", end="") if channel.name is not None: print("id \'" + channel.name + "\', ", end="") print("attr \'" + attr + "\', ", end="") try: print(channel.attrs[attr].value if self.arguments.quiet else "value \'" + channel.attrs[attr].value + "\'") except OSError as err: print("ERROR: " + err.strerror + " (-" + str(err.errno) + ")") if self.arguments.buffer is not None: channel.attrs[attr].value = self.arguments.buffer if not self.arguments.quiet: print("wrote " + str(len(self.arguments.buffer)) + " bytes to " + attr) self.arguments.buffer = None self._channel_attribute_information(dev, channel, attr) def _device_attributes_information(self, dev): if self.arguments.search_device and self.arguments.device is None: print("found " + str(len(dev.attrs)) + " device attributes") if self.arguments.search_device and self.arguments.device is not None and len(dev.attrs) > 0: for key, _ in dev.attrs.items(): if self.arguments.attr is not None and \ not _str_match(key, self.arguments.attr, self.arguments.ignore_case): continue self._device_attribute_information(dev, key) def _device_attribute_information(self, dev, attr): if self.arguments.buffer is None or not self.arguments.quiet: if not self.arguments.quiet: print("dev \'" + dev.name + "\', attr \'" + attr + "\', value: ", end="") try: print(dev.attrs[attr].value if self.arguments.quiet else "\'" + dev.attrs[attr].value + "\'") except OSError as err: print("ERROR: " + err.strerror + " (-" + str(err.errno) + ")") if self.arguments.buffer is not None: dev.attrs[attr].value = self.arguments.buffer if not self.arguments.quiet: print("wrote " + str(len(self.arguments.buffer)) + " bytes to " + attr) self.arguments.buffer = None self._device_attribute_information(dev, attr) def _buffer_attributes_information(self, dev): if self.arguments.search_buffer and self.arguments.device is None: print("found " + str(len(dev.buffer_attrs)) + " buffer attributes") elif self.arguments.search_buffer and _str_match(self.arguments.device, dev.name, self.arguments.ignore_case) \ and len(dev.buffer_attrs) > 0: for key, _ in dev.buffer_attrs.items(): if (self.arguments.attr is not None and _str_match(key, self.arguments.attr, self.arguments.ignore_case)) or \ self.arguments.attr is None: self._buffer_attribute_information(dev, key) def _buffer_attribute_information(self, dev, attr): if self.arguments.buffer is None or not self.arguments.quiet: if not self.arguments.quiet: print("dev \'" + dev.name + "\', buffer attr \'" + attr + "\', value: ", end="") try: print(dev.buffer_attrs[attr].value if self.arguments.quiet else "\'" + dev.buffer_attrs[attr].value + "\'") except OSError as err: print("ERROR: " + err.strerror + " (-" + str(err.errno) + ")") if self.arguments.buffer is not None: dev.buffer_attrs[attr].value = self.arguments.buffer if not self.arguments.quiet: print("wrote " + str(len(self.arguments.buffer)) + " bytes to " + attr) self.arguments.buffer = None self._buffer_attribute_information(dev, attr) def _debug_attributes_information(self, dev): if self.arguments.search_debug and self.arguments.device is None: print("found " + str(len(dev.debug_attrs)) + " debug attributes") elif self.arguments.search_debug and _str_match(self.arguments.device, dev.name, self.arguments.ignore_case) \ and len(dev.debug_attrs) > 0: for key, _ in dev.debug_attrs.items(): if (self.arguments.attr is not None and _str_match(key, self.arguments.attr, self.arguments.quiet)) \ or self.arguments.attr is None: self._debug_attribute_information(dev, key) def _debug_attribute_information(self, dev, attr): if self.arguments.buffer is None or not self.arguments.quiet: if not self.arguments.quiet: print("dev \'" + dev.name + "\', debug attr \'" + attr + "\', value: ", end="") try: print(dev.debug_attrs[attr].value if self.arguments.quiet else "\'" + dev.debug_attrs[attr].value + "\'") except OSError as err: print("ERROR: " + err.strerror + " (-" + str(err.errno) + ")") if self.arguments.buffer is not None: dev.debug_attrs[attr].value = self.arguments.buffer if not self.arguments.quiet: print("wrote " + str(len(self.arguments.buffer)) + " bytes to " + attr) self.arguments.buffer = None self._debug_attribute_information(dev, attr)
[docs] def main(): """Module's main method.""" arguments = Arguments() context_builder = ContextBuilder(arguments) context = context_builder.create() information = Information(arguments, context) information.write_information()
if __name__ == "__main__": main()