Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python: added missing Python bindings. #443

Merged
merged 2 commits into from
Apr 22, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
293 changes: 291 additions & 2 deletions bindings/python/iio.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.

from ctypes import Structure, c_char_p, c_uint, c_int, c_size_t, \
c_ssize_t, c_char, c_void_p, c_bool, create_string_buffer, \
from ctypes import Structure, c_char_p, c_uint, c_int, c_long, c_longlong, c_size_t, \
c_ssize_t, c_char, c_void_p, c_bool, create_string_buffer, c_double, \
POINTER as _POINTER, CDLL as _cdll, memmove as _memmove, byref as _byref
from ctypes.util import find_library
from enum import Enum
from os import strerror as _strerror
from platform import system as _system
import weakref
Expand Down Expand Up @@ -60,13 +61,114 @@ class _Channel(Structure):
pass
class _Buffer(Structure):
pass
class DataFormat(Structure):
"""Represents the data format of an IIO channel."""

_fields_ = [('length', c_uint),
('bits', c_uint),
('shift', c_uint),
('is_signed', c_bool),
('is_fully_defined', c_bool),
('is_be', c_bool),
('with_scale', c_bool),
('scale', c_double),
('repeat', c_uint)]

class ChannelModifier(Enum):
"""Contains the modifier types of an IIO channel."""

IIO_NO_MOD = 0
IIO_MOD_X = 1
IIO_MOD_Y = 2
IIO_MOD_Z = 3
IIO_MOD_X_AND_Y = 4
IIO_MOD_X_AND_Z = 5
IIO_MOD_Y_AND_Z = 6
IIO_MOD_X_AND_Y_AND_Z = 7
IIO_MOD_X_OR_Y = 8
IIO_MOD_X_OR_Z = 9
IIO_MOD_Y_OR_Z = 10
IIO_MOD_X_OR_Y_OR_Z = 11
IIO_MOD_LIGHT_BOTH = 12
IIO_MOD_LIGHT_IR = 13
IIO_MOD_ROOT_SUM_SQUARED_X_Y = 14
IIO_MOD_SUM_SQUARED_X_Y_Z = 15
IIO_MOD_LIGHT_CLEAR = 16
IIO_MOD_LIGHT_RED = 17
IIO_MOD_LIGHT_GREEN = 18
IIO_MOD_LIGHT_BLUE = 19
IIO_MOD_QUATERNION = 20
IIO_MOD_TEMP_AMBIENT = 21
IIO_MOD_TEMP_OBJECT = 22
IIO_MOD_NORTH_MAGN = 23
IIO_MOD_NORTH_TRUE = 24
IIO_MOD_NORTH_MAGN_TILT_COMP = 25
IIO_MOD_NORTH_TRUE_TILT_COMP = 26
IIO_MOD_RUNNING = 27
IIO_MOD_JOGGING = 28
IIO_MOD_WALKING = 29
IIO_MOD_STILL = 30
IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z = 31
IIO_MOD_I = 32
IIO_MOD_Q = 33
IIO_MOD_CO2 = 34
IIO_MOD_VOC = 35
IIO_MOD_LIGHT_UV = 36
IIO_MOD_LIGHT_DUV = 37
IIO_MOD_PM1 = 38
IIO_MOD_PM2P5 = 39
IIO_MOD_PM4 = 40
IIO_MOD_PM10 = 41
IIO_MOD_ETHANOL = 42
IIO_MOD_H2 = 43

class ChannelType(Enum):
"""Contains the type of an IIO channel."""

IIO_VOLTAGE = 0
IIO_CURRENT = 1
IIO_POWER = 2
IIO_ACCEL = 3
IIO_ANGL_VEL = 4
IIO_MAGN = 5
IIO_LIGHT = 6
IIO_INTENSITY = 7
IIO_PROXIMITY = 8
IIO_TEMP = 9
IIO_INCLI = 10
IIO_ROT = 11
IIO_ANGL = 12
IIO_TIMESTAMP = 13
IIO_CAPACITANCE = 14
IIO_ALTVOLTAGE = 15
IIO_CCT = 16
IIO_PRESSURE = 17
IIO_HUMIDITYRELATIVE = 18
IIO_ACTIVITY = 19
IIO_STEPS = 20
IIO_ENERGY = 21
IIO_DISTANCE = 22
IIO_VELOCITY = 23
IIO_CONCENTRATION = 24
IIO_RESISTANCE = 25
IIO_PH = 26
IIO_UVINDEX = 27
IIO_ELECTRICALCONDUCTIVITY = 28
IIO_COUNT = 29
IIO_INDEX = 30
IIO_GRAVITY = 31
IIO_POSITIONRELATIVE = 32
IIO_PHASE = 33
IIO_MASSCONCENTRATION = 34
IIO_CHAN_TYPE_UNKNOWN = 0x7fffffff

_ScanContextPtr = _POINTER(_ScanContext)
_ContextInfoPtr = _POINTER(_ContextInfo)
_ContextPtr = _POINTER(_Context)
_DevicePtr = _POINTER(_Device)
_ChannelPtr = _POINTER(_Channel)
_BufferPtr = _POINTER(_Buffer)
_DataFormatPtr = _POINTER(DataFormat)

if 'Windows' in _system():
_iiolib = 'libiio.dll'
Expand All @@ -92,6 +194,14 @@ class _Buffer(Structure):
_destroy_scan_context = _lib.iio_scan_context_destroy
_destroy_scan_context.argtypes = (_ScanContextPtr, )

_iio_has_backend = _lib.iio_has_backend
_iio_has_backend.argtypes = (c_char_p, )
_iio_has_backend.restype = c_bool

_iio_strerror = _lib.iio_strerror
_iio_strerror.argtypes = (c_int, c_char_p, c_uint)
_iio_strerror.restype = None

_get_context_info_list = _lib.iio_scan_context_get_info_list
_get_context_info_list.argtypes = (_ScanContextPtr, _POINTER(_POINTER(_ContextInfoPtr)))
_get_context_info_list.restype = c_ssize_t
Expand Down Expand Up @@ -229,6 +339,29 @@ class _Buffer(Structure):
_d_write_debug_attr.argtypes = (_DevicePtr, c_char_p, c_char_p)
_d_write_debug_attr.errcheck = _checkNegative

_d_buffer_attr_count = _lib.iio_device_get_buffer_attrs_count
_d_buffer_attr_count.restype = c_uint
_d_buffer_attr_count.argtypes = (_DevicePtr, )

_d_get_buffer_attr = _lib.iio_device_get_buffer_attr
_d_get_buffer_attr.restype = c_char_p
_d_get_buffer_attr.argtypes = (_DevicePtr, )
_d_get_buffer_attr.errcheck = _checkNull

_d_read_buffer_attr = _lib.iio_device_buffer_attr_read
_d_read_buffer_attr.restype = c_ssize_t
_d_read_buffer_attr.argtypes = (_DevicePtr, c_char_p, c_char_p, c_size_t)
_d_read_buffer_attr.errcheck = _checkNegative

_d_write_buffer_attr = _lib.iio_device_buffer_attr_write
_d_write_buffer_attr.restype = c_ssize_t
_d_write_buffer_attr.argtypes = (_DevicePtr, c_char_p, c_char_p)
_d_write_buffer_attr.errcheck = _checkNegative

_d_get_context = _lib.iio_device_get_context
_d_get_context.restype = _ContextPtr
_d_get_context.argtypes = (_DevicePtr, )

_d_reg_write = _lib.iio_device_reg_write
_d_reg_write.restype = c_int
_d_reg_write.argtypes = (_DevicePtr, c_uint, c_uint)
Expand Down Expand Up @@ -339,6 +472,30 @@ class _Buffer(Structure):
_c_write_raw.restype = c_ssize_t
_c_write_raw.argtypes = (_ChannelPtr, _BufferPtr, c_void_p, c_size_t, )

_channel_get_device = _lib.iio_channel_get_device
_channel_get_device.restype = _DevicePtr
_channel_get_device.argtypes = (_ChannelPtr, )

_channel_get_index = _lib.iio_channel_get_index
_channel_get_index.restype = c_long
_channel_get_index.argtypes = (_ChannelPtr, )

_channel_get_data_format = _lib.iio_channel_get_data_format
_channel_get_data_format.restype = _DataFormatPtr
_channel_get_data_format.argtypes = (_ChannelPtr, )

_channel_get_modifier = _lib.iio_channel_get_modifier
_channel_get_modifier.restype = c_int
_channel_get_modifier.argtypes = (_ChannelPtr, )

_channel_get_type = _lib.iio_channel_get_type
_channel_get_type.restype = c_int
_channel_get_type.argtypes = (_ChannelPtr, )

_channel_convert = _lib.iio_channel_convert
_channel_convert.restype = None
_channel_convert.argtypes = (_ChannelPtr, c_void_p, c_void_p)

_create_buffer = _lib.iio_device_create_buffer
_create_buffer.restype = _BufferPtr
_create_buffer.argtypes = (_DevicePtr, c_size_t, c_bool, )
Expand All @@ -365,13 +522,45 @@ class _Buffer(Structure):
_buffer_end.restype = c_void_p
_buffer_end.argtypes = (_BufferPtr, )

_buffer_cancel = _lib.iio_buffer_cancel
_buffer_cancel.restype = c_void_p
_buffer_cancel.argtypes = (_BufferPtr, )

_buffer_get_data = _lib.iio_buffer_get_data
_buffer_get_data.restype = c_void_p
_buffer_get_data.argtypes = (_BufferPtr, )

_buffer_get_device = _lib.iio_buffer_get_device
_buffer_get_device.restype = _DevicePtr
_buffer_get_device.argtypes = (_BufferPtr, )

_buffer_get_poll_fd = _lib.iio_buffer_get_poll_fd
_buffer_get_poll_fd.restype = c_int
_buffer_get_poll_fd.argtypes = (_BufferPtr, )

_buffer_step = _lib.iio_buffer_step
_buffer_step.restype = c_longlong
_buffer_step.argtypes = (_BufferPtr, )

_buffer_set_blocking_mode = _lib.iio_buffer_set_blocking_mode
_buffer_set_blocking_mode.restype = c_uint
_buffer_set_blocking_mode.argtypes = (_BufferPtr, c_bool)

def _get_lib_version():
major = c_uint()
minor = c_uint()
buf = create_string_buffer(8)
_get_library_version(_byref(major), _byref(minor), buf)
return (major.value, minor.value, buf.value.decode('ascii') )

def _has_backend(backend):
b_backend = backend.encode('utf-8')
return _iio_has_backend(b_backend)

def iio_strerror(err, buf, length):
b_buf = buf.encode('utf-8')
_iio_strerror(err, b_buf, length)

version = _get_lib_version()
backends = [ _get_backend(x).decode('ascii') for x in range(0, _get_backends_count()) ]

Expand Down Expand Up @@ -474,6 +663,32 @@ def _Attr__read(self):
def _Attr__write(self, value):
_d_write_debug_attr(self._device, self._name_ascii, value.encode('ascii'))

class DeviceBufferAttr(DeviceAttr):
"""Represents a buffer attribute of an IIO device."""

def __init__(self, device, name):
"""
Initializes a new instance of the DeviceBufferAttr class.

parameters:
device: type=iio.Device
A valid instance of the iio.Device class.
name: type=str
The device buffer attribute's name

returns: type=iio.DeviceBufferAttr
A new instance of this class
"""
super(DeviceBufferAttr, self).__init__(device, name)

def _Attr__read(self):
buf = create_string_buffer(1024)
_d_read_buffer_attr(self._device, self._name_ascii, buf, len(buf))
return buf.value.decode('ascii')

def _Attr__write(self, value):
_d_write_buffer_attr(self._device, self._name_ascii, value.encode('ascii'))

class Channel(object):
"""Represents a channel of an IIO device."""

Expand Down Expand Up @@ -558,6 +773,46 @@ def write(self, buf, array, raw = False):
lambda self, x: _c_enable(self._channel) if x else _c_disable(self._channel),
None, "Configured state of the channel\n\ttype=bool")

@property
def device(self):
"""
This channel's corresponding device.
type: iio.Device
"""
c_dev = _channel_get_device(self._channel)
return Device(_d_get_context(c_dev), c_dev)

@property
def index(self):
return _channel_get_index(self._channel)

@property
def data_format(self):
"""
This channel's data format.
type: iio.DataFormat
"""
return _channel_get_data_format(self._channel).contents

@property
def modifier(self):
"""
This channel's modifier.
type: iio.ChannelModifier(Enum)
"""
return ChannelModifier(_channel_get_modifier(self._channel))

@property
def type(self):
"""
This channel's type.
type: iio.ChannelType(Enum)
"""
return ChannelType(_channel_get_type(self._channel))

def convert(self, dst, src):
_channel_convert(self._channel, c_void_p(*dst), c_void_p(*src))

class Buffer(object):

"""The class used for all I/O operations."""
Expand Down Expand Up @@ -648,13 +903,41 @@ def write(self, array):
_memmove(start, c_array, length)
return length

def cancel(self):
_buffer_cancel(self._buffer)

def get_data(self):
return _buffer_get_data(self._buffer)

def set_blocking_mode(self, blocking):
return _buffer_set_blocking_mode(self._buffer, c_bool(blocking))

@property
def device(self):
"""
This buffer's corresponding device.
type: iio.Device
"""
return Device(self._ctx, _buffer_get_device(self._buffer))

@property
def poll_fd(self):
return _buffer_get_poll_fd(self._buffer)

@property
def step(self):
return _buffer_step(self._buffer)

class _DeviceOrTrigger(object):
def __init__(self, _device):
self._device = _device
self._context = _d_get_context(_device)
self._attrs = { name : DeviceAttr(_device, name) for name in \
[_d_get_attr(_device, x).decode('ascii') for x in range(0, _d_attr_count(_device))] }
self._debug_attrs = { name: DeviceDebugAttr(_device, name) for name in \
[_d_get_debug_attr(_device, x).decode('ascii') for x in range(0, _d_debug_attr_count(_device))] }
self._buffer_attrs = { name: DeviceBufferAttr(_device, name) for name in \
[_d_get_buffer_attr(_device, x).decode('ascii') for x in range(0, _d_buffer_attr_count(_device))] }

# TODO(pcercuei): Use a dictionary for the channels.
chans = [ Channel(_get_channel(self._device, x))
Expand Down Expand Up @@ -739,6 +1022,8 @@ def sample_size(self):
"List of attributes for this IIO device.\n\ttype=dict of iio.DeviceAttr")
debug_attrs = property(lambda self: self._debug_attrs, None, None,
"List of debug attributes for this IIO device.\n\ttype=dict of iio.DeviceDebugAttr")
buffer_attrs = property(lambda self: self._buffer_attrs, None, None,
"List of buffer attributes for this IIO device.\n\ttype=dict of iio.DeviceBufferAttr")
channels = property(lambda self: self._channels, None, None,
"List of channels available with this IIO device.\n\ttype=list of iio.Channel objects")

Expand Down Expand Up @@ -803,6 +1088,10 @@ def _get_trigger(self):
trigger = property(_get_trigger, _set_trigger, None, \
"Contains the configured trigger for this IIO device.\n\ttype=iio.Trigger")

@property
def context(self):
return self.ctx()

class Context(object):

"""Contains the representation of an IIO context."""
Expand Down