"""
Project generated by builder 0.10.31 protocol 1.1.2
"""
import logging
from sys import version_info
import struct
from ctypes import CDLL, Structure, Array, CFUNCTYPE, byref, create_string_buffer, cast
from ctypes import c_ushort, c_float, c_ubyte, c_uint, c_short
from ctypes import c_wchar_p, c_int, c_void_p, c_size_t, c_char_p
import atexit
try:
    from typing import overload, Union, Sequence, Optional
except ImportError:
    def overload(method):
        return method

    class _GenericTypeMeta(type):
        def __getitem__(self, _):
            return None

    class Union(metaclass=_GenericTypeMeta):
        pass

    class Sequence(metaclass=_GenericTypeMeta):
        pass

    class Optional(metaclass=_GenericTypeMeta):
        pass

urpc_builder_version_major = 0
urpc_builder_version_minor = 10
urpc_builder_version_bugfix = 31
urpc_builder_version_suffix = ""
urpc_builder_version = "0.10.31"
_Ok = 0
_Error = -1
_NotImplemented = -2
_ValueError = -3
_NoDevice = -4
_DeviceUndefined = -1


class UrpcError(Exception):
    pass


class UrpcValueError(UrpcError, ValueError):
    pass


class UrpcNotImplementedError(UrpcError, NotImplementedError):
    pass


class UrpcNoDeviceError(UrpcError, RuntimeError):
    pass


class UrpcDeviceUndefinedError(UrpcError, RuntimeError):
    pass


class UrpcUnknownError(UrpcError, RuntimeError):
    pass


class _IterableStructure(Structure):
    def __iter__(self):
        return (getattr(self, n) for n, t in self._fields_)


def _validate_call(result):
    if result == _ValueError:
        raise UrpcValueError()
    elif result == _NotImplemented:
        raise UrpcNotImplementedError()
    elif result == _NoDevice:
        raise UrpcNoDeviceError()
    elif result == _DeviceUndefined:
        raise UrpcDeviceUndefinedError()
    elif result != _Ok:
        raise UrpcUnknownError()


def _normalize_arg(value, desired_ctype):
    from collections.abc import Sequence
    if isinstance(value, desired_ctype):
        return value
    elif issubclass(desired_ctype, Array) and isinstance(value, Sequence):
        member_type = desired_ctype._type_
        if desired_ctype._length_ < len(value):
            raise ValueError()
        if issubclass(member_type, c_ubyte) and isinstance(value, bytes):
            return desired_ctype.from_buffer_copy(value)
        elif issubclass(member_type, c_ubyte) and isinstance(value, bytearray):
            return desired_ctype.from_buffer(value)
        else:
            return desired_ctype(*value)
    else:
        return desired_ctype(value)


_logger = logging.getLogger(__name__)


def _check_library_existence(paths):
    import os
    import sysconfig

    for path in paths:
        if os.path.exists(path):
            return

    error_msg = ("This version of the package does not contain binaries for the " + sysconfig.get_platform() +
                 " platform. For correct operation on this system, you need to rebuild the package with "
                 "binaries for your system. If necessary, you can consult with the developer of the package: "
                 "info@physlab.ru.")
    raise RuntimeError(error_msg)


def _get_possible_library_paths_for_platform():
    import platform
    import sysconfig

    os_kind = platform.system().lower()
    if sysconfig.get_platform() == "win32":
        return (_near_script_path("ivm-win32\\ivm.dll"),
                _near_script_path("ivm.dll"),
                "ivm.dll")

    if sysconfig.get_platform() == "win-amd64":
        return (_near_script_path("ivm-win64\\ivm.dll"),
                _near_script_path("ivm.dll"),
                "ivm.dll")

    if os_kind == "darwin":
        return (_near_script_path("ivm-darwin/libivm.dylib"),
                _near_script_path("libivm.dylib"),
                "libivm.dylib")

    if os_kind == "freebsd" or "linux" in os_kind:
        if sysconfig.get_platform() == "linux-aarch64":
            return (_near_script_path("ivm-debian_arm64/libivm.so"),
                    _near_script_path("libivm.so"),
                    "libivm.so")

        return (_near_script_path("ivm-debian/libivm.so"),
                _near_script_path("libivm.so"),
                "libivm.so")

    raise RuntimeError("Unexpected OS: " + sysconfig.get_platform())


def _load_specific_lib(path):
    try:
        lib = CDLL(path)
        _logger.debug("Load library " + path + ": success")
        return lib
    except OSError as exc:
        _logger.debug("Load library " + path + ": failed, " + str(exc))
        raise exc


def _near_script_path(libname):
    from os.path import abspath, dirname, join
    return join(abspath(dirname(__file__)), libname)


def _load_lib():
    import platform
    import sysconfig

    paths = _get_possible_library_paths_for_platform()
    _check_library_existence(paths)

    errors = []
    for path in paths:
        try:
            lib = _load_specific_lib(path)
        except Exception as exc:
            errors.append(str(exc))
        else:
            return lib

    error_msg = "Failed to load library. Tried paths:\n"
    for i, path in enumerate(paths):
        error_msg = error_msg + str(path) + " - got error: " + errors[i] + "\n"

    if platform.system().lower() == "windows":
        error_msg += ("\nCheck that Visual C++ Redistributable Packages for Visual Studio 2013 are "
                      "installed.\nYou can download the installers from "
                      "https://www.microsoft.com/en-us/download/details.aspx?id=40784.\n")

    raise RuntimeError(error_msg)


_lib = _load_lib()


# Hack to prevent auto-conversion to native Python int
class _device_t(c_int):
    def from_param(self, *args):
        return self


_lib.ivm_open_device.restype = _device_t


@CFUNCTYPE(None, c_int, c_wchar_p, c_void_p)
def _logging_callback(loglevel, message, user_data):
    if loglevel == 0x01:
        _logger.error(message)
    elif loglevel == 0x02:
        _logger.warning(message)
    elif loglevel == 0x03:
        _logger.info(message)
    elif loglevel == 0x04:
        _logger.debug(message)


_lib.ivm_set_logging_callback(_logging_callback, 0)
atexit.register(lambda: _lib.ivm_set_logging_callback(None, 0))


def reset_locks():
    _validate_call(_lib.ivm_reset_locks())


def fix_usbser_sys():
    _validate_call(_lib.ivm_fix_usbser_sys())


class IvmDeviceHandle:
    class GetMeasurementRequest(_IterableStructure):
        _fields_ = (
            ("_frame_number", c_ushort),
        )

        class FrameNumber(int):
            FRAME_SIZE = 25

            @property
            def frame_size(self) -> int:
                return self & self.FRAME_SIZE

        @property
        def frame_number(self) -> "FrameNumber":
            return self.FrameNumber(self._frame_number)

        @frame_number.setter
        def frame_number(self, value: Union[int, c_ushort]) -> None:
            self._frame_number = _normalize_arg(value, c_ushort)

    class GetMeasurementResponse(_IterableStructure):
        _fields_ = (
            ("_voltage", c_float*25),
            ("_current", c_float*25),
        )

        @property
        def voltage(self) -> c_float*25:
            return self._voltage

        @voltage.setter
        def voltage(self, value: Union[Sequence[float], c_float*25]) -> None:
            self._voltage = _normalize_arg(value, c_float*25)

        @property
        def current(self) -> c_float*25:
            return self._current

        @current.setter
        def current(self, value: Union[Sequence[float], c_float*25]) -> None:
            self._current = _normalize_arg(value, c_float*25)

    @overload  # noqa: F811
    def get_measurement(
            self,
            frame_number: Union[int, c_ushort],
            *,
            dst_buffer: Optional[GetMeasurementResponse]=None
    ) -> "GetMeasurementResponse": pass

    @overload  # noqa: F811
    def get_measurement(
            self,
            src_buffer: GetMeasurementRequest,
            *,
            dst_buffer: Optional[GetMeasurementResponse]=None
    ) -> "GetMeasurementResponse": pass

    def get_measurement(self, *args, **kwargs) -> "GetMeasurementResponse":  # noqa: F811
        src_buffer = None
        if len(args) != 1 or not isinstance(args[0], self.GetMeasurementRequest):
            src_buffer = self.GetMeasurementRequest(
                frame_number=_normalize_arg(args[0], c_ushort)
            )
        else:
            src_buffer = args[0]
        dst_buffer = kwargs.get("dst_buffer", self.GetMeasurementResponse())
        _validate_call(_lib.ivm_get_measurement(self._handle, byref(src_buffer), byref(dst_buffer)))
        return dst_buffer

    class GetIdentityInformationResponse(_IterableStructure):
        _fields_ = (
            ("_manufacturer", c_ubyte*16),
            ("_product_name", c_ubyte*16),
            ("_controller_name", c_ubyte*16),
            ("_hardware_major", c_ubyte),
            ("_hardware_minor", c_ubyte),
            ("_hardware_bugfix", c_ushort),
            ("_bootloader_major", c_ubyte),
            ("_bootloader_minor", c_ubyte),
            ("_bootloader_bugfix", c_ushort),
            ("_firmware_major", c_ubyte),
            ("_firmware_minor", c_ubyte),
            ("_firmware_bugfix", c_ushort),
            ("_serial_number", c_uint),
            ("_reserved", c_ubyte*8),
        )

        @property
        def manufacturer(self) -> c_ubyte*16:
            return self._manufacturer

        @manufacturer.setter
        def manufacturer(self, value: Union[Sequence[int], c_ubyte*16]) -> None:
            self._manufacturer = _normalize_arg(value, c_ubyte*16)

        @property
        def product_name(self) -> c_ubyte*16:
            return self._product_name

        @product_name.setter
        def product_name(self, value: Union[Sequence[int], c_ubyte*16]) -> None:
            self._product_name = _normalize_arg(value, c_ubyte*16)

        @property
        def controller_name(self) -> c_ubyte*16:
            return self._controller_name

        @controller_name.setter
        def controller_name(self, value: Union[Sequence[int], c_ubyte*16]) -> None:
            self._controller_name = _normalize_arg(value, c_ubyte*16)

        @property
        def hardware_major(self) -> c_ubyte:
            return self._hardware_major

        @hardware_major.setter
        def hardware_major(self, value: Union[int, c_ubyte]) -> None:
            self._hardware_major = _normalize_arg(value, c_ubyte)

        @property
        def hardware_minor(self) -> c_ubyte:
            return self._hardware_minor

        @hardware_minor.setter
        def hardware_minor(self, value: Union[int, c_ubyte]) -> None:
            self._hardware_minor = _normalize_arg(value, c_ubyte)

        @property
        def hardware_bugfix(self) -> c_ushort:
            return self._hardware_bugfix

        @hardware_bugfix.setter
        def hardware_bugfix(self, value: Union[int, c_ushort]) -> None:
            self._hardware_bugfix = _normalize_arg(value, c_ushort)

        @property
        def bootloader_major(self) -> c_ubyte:
            return self._bootloader_major

        @bootloader_major.setter
        def bootloader_major(self, value: Union[int, c_ubyte]) -> None:
            self._bootloader_major = _normalize_arg(value, c_ubyte)

        @property
        def bootloader_minor(self) -> c_ubyte:
            return self._bootloader_minor

        @bootloader_minor.setter
        def bootloader_minor(self, value: Union[int, c_ubyte]) -> None:
            self._bootloader_minor = _normalize_arg(value, c_ubyte)

        @property
        def bootloader_bugfix(self) -> c_ushort:
            return self._bootloader_bugfix

        @bootloader_bugfix.setter
        def bootloader_bugfix(self, value: Union[int, c_ushort]) -> None:
            self._bootloader_bugfix = _normalize_arg(value, c_ushort)

        @property
        def firmware_major(self) -> c_ubyte:
            return self._firmware_major

        @firmware_major.setter
        def firmware_major(self, value: Union[int, c_ubyte]) -> None:
            self._firmware_major = _normalize_arg(value, c_ubyte)

        @property
        def firmware_minor(self) -> c_ubyte:
            return self._firmware_minor

        @firmware_minor.setter
        def firmware_minor(self, value: Union[int, c_ubyte]) -> None:
            self._firmware_minor = _normalize_arg(value, c_ubyte)

        @property
        def firmware_bugfix(self) -> c_ushort:
            return self._firmware_bugfix

        @firmware_bugfix.setter
        def firmware_bugfix(self, value: Union[int, c_ushort]) -> None:
            self._firmware_bugfix = _normalize_arg(value, c_ushort)

        @property
        def serial_number(self) -> c_uint:
            return self._serial_number

        @serial_number.setter
        def serial_number(self, value: Union[int, c_uint]) -> None:
            self._serial_number = _normalize_arg(value, c_uint)

        @property
        def reserved(self) -> c_ubyte*8:
            return self._reserved

        @reserved.setter
        def reserved(self, value: Union[Sequence[int], c_ubyte*8]) -> None:
            self._reserved = _normalize_arg(value, c_ubyte*8)

    def get_identity_information(self, **kwargs) -> "GetIdentityInformationResponse":
        dst_buffer = kwargs.get("dst_buffer", self.GetIdentityInformationResponse())
        _validate_call(_lib.ivm_get_identity_information(self._handle, byref(dst_buffer)))
        return dst_buffer

    class StartAutocalibrationResponse(_IterableStructure):
        _fields_ = (
            ("_result", c_ubyte),
        )

        class Result(int):
            CALIBRATION_OK = 0

            @property
            def calibration_ok(self) -> int:
                return self & self.CALIBRATION_OK

        @property
        def result(self) -> "Result":
            return self.Result(self._result)

        @result.setter
        def result(self, value: Union[int, c_ubyte]) -> None:
            self._result = _normalize_arg(value, c_ubyte)

    def start_autocalibration(self, **kwargs) -> "StartAutocalibrationResponse":
        dst_buffer = kwargs.get("dst_buffer", self.StartAutocalibrationResponse())
        _validate_call(_lib.ivm_start_autocalibration(self._handle, byref(dst_buffer)))
        return dst_buffer

    class GetStatusResponse(_IterableStructure):
        _fields_ = (
            ("_status", c_uint),
            ("_temperature", c_short),
            ("_reserved0", c_ubyte*2),
            ("_io_state", c_ushort),
            ("_io_events", c_ushort),
            ("_reserved1", c_ubyte*42),
        )

        class Status(int):
            STATUS_OK = 0

            @property
            def status_ok(self) -> int:
                return self & self.STATUS_OK

        @property
        def status(self) -> "Status":
            return self.Status(self._status)

        @status.setter
        def status(self, value: Union[int, c_uint]) -> None:
            self._status = _normalize_arg(value, c_uint)

        @property
        def temperature(self) -> c_short:
            return self._temperature

        @temperature.setter
        def temperature(self, value: Union[int, c_short]) -> None:
            self._temperature = _normalize_arg(value, c_short)

        @property
        def reserved0(self) -> c_ubyte*2:
            return self._reserved0

        @reserved0.setter
        def reserved0(self, value: Union[Sequence[int], c_ubyte*2]) -> None:
            self._reserved0 = _normalize_arg(value, c_ubyte*2)

        class IOState(int):
            IOSTATE_GEN_PROBE_BUTTON_PRESSED = 1
            IOSTATE_RECV_PROBE_BUTTON_PRESSED = 2

            @property
            def iostate_gen_probe_button_pressed(self) -> int:
                return self & self.IOSTATE_GEN_PROBE_BUTTON_PRESSED

            @property
            def iostate_recv_probe_button_pressed(self) -> int:
                return self & self.IOSTATE_RECV_PROBE_BUTTON_PRESSED

        @property
        def io_state(self) -> "IOState":
            return self.IOState(self._io_state)

        @io_state.setter
        def io_state(self, value: Union[int, c_ushort]) -> None:
            self._io_state = _normalize_arg(value, c_ushort)

        class IOEvents(int):
            IOEVENTS_GEN_PROBE_BUTTON_PRESSED = 1
            IOEVENTS_GEN_PROBE_BUTTON_RELEASED = 2
            IOEVENTS_RECV_PROBE_BUTTON_PRESSED = 4
            IOEVENTS_RECV_PROBE_BUTTON_RELEASED = 8

            @property
            def ioevents_gen_probe_button_pressed(self) -> int:
                return self & self.IOEVENTS_GEN_PROBE_BUTTON_PRESSED

            @property
            def ioevents_gen_probe_button_released(self) -> int:
                return self & self.IOEVENTS_GEN_PROBE_BUTTON_RELEASED

            @property
            def ioevents_recv_probe_button_pressed(self) -> int:
                return self & self.IOEVENTS_RECV_PROBE_BUTTON_PRESSED

            @property
            def ioevents_recv_probe_button_released(self) -> int:
                return self & self.IOEVENTS_RECV_PROBE_BUTTON_RELEASED

        @property
        def io_events(self) -> "IOEvents":
            return self.IOEvents(self._io_events)

        @io_events.setter
        def io_events(self, value: Union[int, c_ushort]) -> None:
            self._io_events = _normalize_arg(value, c_ushort)

        @property
        def reserved1(self) -> c_ubyte*42:
            return self._reserved1

        @reserved1.setter
        def reserved1(self, value: Union[Sequence[int], c_ubyte*42]) -> None:
            self._reserved1 = _normalize_arg(value, c_ubyte*42)

    def get_status(self, **kwargs) -> "GetStatusResponse":
        dst_buffer = kwargs.get("dst_buffer", self.GetStatusResponse())
        _validate_call(_lib.ivm_get_status(self._handle, byref(dst_buffer)))
        return dst_buffer

    def start_measurement(self) -> None:
        _validate_call(_lib.ivm_start_measurement(self._handle))

    class CheckMeasurementStatusResponse(_IterableStructure):
        _fields_ = (
            ("_ready_status", c_ubyte),
            ("_reserved", c_ubyte*15),
        )

        class ReadyStatus(int):
            MEASUREMENT_NOT_COMPLETE = 0
            MEASUREMENT_COMPLETE = 1

            @property
            def measurement_not_complete(self) -> int:
                return self & self.MEASUREMENT_NOT_COMPLETE

            @property
            def measurement_complete(self) -> int:
                return self & self.MEASUREMENT_COMPLETE

        @property
        def ready_status(self) -> "ReadyStatus":
            return self.ReadyStatus(self._ready_status)

        @ready_status.setter
        def ready_status(self, value: Union[int, c_ubyte]) -> None:
            self._ready_status = _normalize_arg(value, c_ubyte)

        @property
        def reserved(self) -> c_ubyte*15:
            return self._reserved

        @reserved.setter
        def reserved(self, value: Union[Sequence[int], c_ubyte*15]) -> None:
            self._reserved = _normalize_arg(value, c_ubyte*15)

    def check_measurement_status(self, **kwargs) -> "CheckMeasurementStatusResponse":
        dst_buffer = kwargs.get("dst_buffer", self.CheckMeasurementStatusResponse())
        _validate_call(_lib.ivm_check_measurement_status(self._handle, byref(dst_buffer)))
        return dst_buffer

    class GetMeasurementRawRequest(_IterableStructure):
        _fields_ = (
            ("_frame", c_ushort),
        )

        @property
        def frame(self) -> c_ushort:
            return self._frame

        @frame.setter
        def frame(self, value: Union[int, c_ushort]) -> None:
            self._frame = _normalize_arg(value, c_ushort)

    class GetMeasurementRawResponse(_IterableStructure):
        _fields_ = (
            ("_adc_high_code", c_ushort*25),
            ("_adc_low_code", c_ushort*25),
        )

        @property
        def adc_high_code(self) -> c_ushort*25:
            return self._adc_high_code

        @adc_high_code.setter
        def adc_high_code(self, value: Union[Sequence[int], c_ushort*25]) -> None:
            self._adc_high_code = _normalize_arg(value, c_ushort*25)

        @property
        def adc_low_code(self) -> c_ushort*25:
            return self._adc_low_code

        @adc_low_code.setter
        def adc_low_code(self, value: Union[Sequence[int], c_ushort*25]) -> None:
            self._adc_low_code = _normalize_arg(value, c_ushort*25)

    @overload  # noqa: F811
    def get_measurement_raw(
            self,
            frame: Union[int, c_ushort],
            *,
            dst_buffer: Optional[GetMeasurementRawResponse]=None
    ) -> "GetMeasurementRawResponse": pass

    @overload  # noqa: F811
    def get_measurement_raw(
            self,
            src_buffer: GetMeasurementRawRequest,
            *,
            dst_buffer: Optional[GetMeasurementRawResponse]=None
    ) -> "GetMeasurementRawResponse": pass

    def get_measurement_raw(self, *args, **kwargs) -> "GetMeasurementRawResponse":  # noqa: F811
        src_buffer = None
        if len(args) != 1 or not isinstance(args[0], self.GetMeasurementRawRequest):
            src_buffer = self.GetMeasurementRawRequest(
                frame=_normalize_arg(args[0], c_ushort)
            )
        else:
            src_buffer = args[0]
        dst_buffer = kwargs.get("dst_buffer", self.GetMeasurementRawResponse())
        _validate_call(_lib.ivm_get_measurement_raw(self._handle, byref(src_buffer), byref(dst_buffer)))
        return dst_buffer

    class ResetEventsRequest(_IterableStructure):
        _fields_ = (
            ("_io_events_rst", c_ushort),
            ("_reserved0", c_ubyte*30),
        )

        class IOEventsRst(int):
            IOEVENTSRST_GEN_PROBE_BUTTON_PRESSED = 1
            IOEVENTSRST_GEN_PROBE_BUTTON_RELEASED = 2
            IOEVENTSRST_RECV_PROBE_BUTTON_PRESSED = 4
            IOEVENTSRST_RECV_PROBE_BUTTON_RELEASED = 8

            @property
            def ioeventsrst_gen_probe_button_pressed(self) -> int:
                return self & self.IOEVENTSRST_GEN_PROBE_BUTTON_PRESSED

            @property
            def ioeventsrst_gen_probe_button_released(self) -> int:
                return self & self.IOEVENTSRST_GEN_PROBE_BUTTON_RELEASED

            @property
            def ioeventsrst_recv_probe_button_pressed(self) -> int:
                return self & self.IOEVENTSRST_RECV_PROBE_BUTTON_PRESSED

            @property
            def ioeventsrst_recv_probe_button_released(self) -> int:
                return self & self.IOEVENTSRST_RECV_PROBE_BUTTON_RELEASED

        @property
        def io_events_rst(self) -> "IOEventsRst":
            return self.IOEventsRst(self._io_events_rst)

        @io_events_rst.setter
        def io_events_rst(self, value: Union[int, c_ushort]) -> None:
            self._io_events_rst = _normalize_arg(value, c_ushort)

        @property
        def reserved0(self) -> c_ubyte*30:
            return self._reserved0

        @reserved0.setter
        def reserved0(self, value: Union[Sequence[int], c_ubyte*30]) -> None:
            self._reserved0 = _normalize_arg(value, c_ubyte*30)

    class ResetEventsResponse(_IterableStructure):
        _fields_ = (
            ("_reserved0", c_ubyte*16),
        )

        @property
        def reserved0(self) -> c_ubyte*16:
            return self._reserved0

        @reserved0.setter
        def reserved0(self, value: Union[Sequence[int], c_ubyte*16]) -> None:
            self._reserved0 = _normalize_arg(value, c_ubyte*16)

    @overload  # noqa: F811
    def reset_events(
            self,
            io_events_rst: Union[int, c_ushort],
            reserved0: Union[Sequence[int], c_ubyte*30],
            *,
            dst_buffer: Optional[ResetEventsResponse]=None
    ) -> "ResetEventsResponse": pass

    @overload  # noqa: F811
    def reset_events(
            self,
            src_buffer: ResetEventsRequest,
            *,
            dst_buffer: Optional[ResetEventsResponse]=None
    ) -> "ResetEventsResponse": pass

    def reset_events(self, *args, **kwargs) -> "ResetEventsResponse":  # noqa: F811
        src_buffer = None
        if len(args) != 1 or not isinstance(args[0], self.ResetEventsRequest):
            src_buffer = self.ResetEventsRequest(
                io_events_rst=_normalize_arg(args[0], c_ushort),
                reserved0=_normalize_arg(args[1], c_ubyte*30)
            )
        else:
            src_buffer = args[0]
        dst_buffer = kwargs.get("dst_buffer", self.ResetEventsResponse())
        _validate_call(_lib.ivm_reset_events(self._handle, byref(src_buffer), byref(dst_buffer)))
        return dst_buffer

    class MeasurementSettingsRequest(_IterableStructure):
        _fields_ = (
            ("_sampling_rate", c_float),
            ("_probe_signal_frequency", c_float),
            ("_number_points", c_uint),
            ("_number_charge_points", c_uint),
            ("_max_voltage", c_float),
            ("_reserved0", c_ubyte*4),
            ("_current_sensor_mode", c_uint),
            ("_output_mode", c_ubyte),
            ("_reserved1", c_ubyte*19),
        )

        @property
        def sampling_rate(self) -> c_float:
            return self._sampling_rate

        @sampling_rate.setter
        def sampling_rate(self, value: Union[float, c_float]) -> None:
            self._sampling_rate = _normalize_arg(value, c_float)

        @property
        def probe_signal_frequency(self) -> c_float:
            return self._probe_signal_frequency

        @probe_signal_frequency.setter
        def probe_signal_frequency(self, value: Union[float, c_float]) -> None:
            self._probe_signal_frequency = _normalize_arg(value, c_float)

        class NumberPoints(int):
            MIN_NUMBER_POINTS = 10
            MAX_NUMBER_POINTS = 1000

            @property
            def min_number_points(self) -> int:
                return self & self.MIN_NUMBER_POINTS

            @property
            def max_number_points(self) -> int:
                return self & self.MAX_NUMBER_POINTS

        @property
        def number_points(self) -> "NumberPoints":
            return self.NumberPoints(self._number_points)

        @number_points.setter
        def number_points(self, value: Union[int, c_uint]) -> None:
            self._number_points = _normalize_arg(value, c_uint)

        @property
        def number_charge_points(self) -> c_uint:
            return self._number_charge_points

        @number_charge_points.setter
        def number_charge_points(self, value: Union[int, c_uint]) -> None:
            self._number_charge_points = _normalize_arg(value, c_uint)

        @property
        def max_voltage(self) -> c_float:
            return self._max_voltage

        @max_voltage.setter
        def max_voltage(self, value: Union[float, c_float]) -> None:
            self._max_voltage = _normalize_arg(value, c_float)

        @property
        def reserved0(self) -> c_ubyte*4:
            return self._reserved0

        @reserved0.setter
        def reserved0(self, value: Union[Sequence[int], c_ubyte*4]) -> None:
            self._reserved0 = _normalize_arg(value, c_ubyte*4)

        class CurrentSensorMode(int):
            CURRENT_SENSE_MODE_ISOLATED = 0
            CURRENT_SENSE_MODE_I_LOW = 1
            CURRENT_SENSE_MODE_I_MID = 2
            CURRENT_SENSE_MODE_I_HIGH = 3

            @property
            def current_sense_mode_isolated(self) -> int:
                return self & self.CURRENT_SENSE_MODE_ISOLATED

            @property
            def current_sense_mode_i_low(self) -> int:
                return self & self.CURRENT_SENSE_MODE_I_LOW

            @property
            def current_sense_mode_i_mid(self) -> int:
                return self & self.CURRENT_SENSE_MODE_I_MID

            @property
            def current_sense_mode_i_high(self) -> int:
                return self & self.CURRENT_SENSE_MODE_I_HIGH

        @property
        def current_sensor_mode(self) -> "CurrentSensorMode":
            return self.CurrentSensorMode(self._current_sensor_mode)

        @current_sensor_mode.setter
        def current_sensor_mode(self, value: Union[int, c_uint]) -> None:
            self._current_sensor_mode = _normalize_arg(value, c_uint)

        class OutputMode(int):
            OUT_MODE_PROBE_SIGNAL_CONTINUOUS = 0
            OUT_MODE_GROUNDED_CONTINUOUS = 1
            OUT_MODE_PROBE_SIGNAL_WITH_GROUNDING = 2

            @property
            def out_mode_probe_signal_continuous(self) -> int:
                return self & self.OUT_MODE_PROBE_SIGNAL_CONTINUOUS

            @property
            def out_mode_grounded_continuous(self) -> int:
                return self & self.OUT_MODE_GROUNDED_CONTINUOUS

            @property
            def out_mode_probe_signal_with_grounding(self) -> int:
                return self & self.OUT_MODE_PROBE_SIGNAL_WITH_GROUNDING

        @property
        def output_mode(self) -> "OutputMode":
            return self.OutputMode(self._output_mode)

        @output_mode.setter
        def output_mode(self, value: Union[int, c_ubyte]) -> None:
            self._output_mode = _normalize_arg(value, c_ubyte)

        @property
        def reserved1(self) -> c_ubyte*19:
            return self._reserved1

        @reserved1.setter
        def reserved1(self, value: Union[Sequence[int], c_ubyte*19]) -> None:
            self._reserved1 = _normalize_arg(value, c_ubyte*19)

    MeasurementSettingsResponse = MeasurementSettingsRequest

    def get_measurement_settings(self, **kwargs) -> "MeasurementSettingsResponse":
        dst_buffer = kwargs.get("dst_buffer", self.MeasurementSettingsResponse())
        _validate_call(_lib.ivm_get_measurement_settings(self._handle, byref(dst_buffer)))
        return dst_buffer

    @overload  # noqa: F811
    def set_measurement_settings(
            self,
            sampling_rate: Union[float, c_float],
            probe_signal_frequency: Union[float, c_float],
            number_points: Union[int, c_uint],
            number_charge_points: Union[int, c_uint],
            max_voltage: Union[float, c_float],
            reserved0: Union[Sequence[int], c_ubyte*4],
            current_sensor_mode: Union[int, c_uint],
            output_mode: Union[int, c_ubyte],
            reserved1: Union[Sequence[int], c_ubyte*19]
    ) -> None: pass

    @overload  # noqa: F811
    def set_measurement_settings(
            self,
            src_buffer: MeasurementSettingsRequest
    ) -> None: pass

    def set_measurement_settings(self, *args) -> None:  # noqa: F811
        src_buffer = None
        if len(args) != 1 or not isinstance(args[0], self.MeasurementSettingsRequest):
            src_buffer = self.MeasurementSettingsRequest(
                sampling_rate=_normalize_arg(args[0], c_float),
                probe_signal_frequency=_normalize_arg(args[1], c_float),
                number_points=_normalize_arg(args[2], c_uint),
                number_charge_points=_normalize_arg(args[3], c_uint),
                max_voltage=_normalize_arg(args[4], c_float),
                reserved0=_normalize_arg(args[5], c_ubyte*4),
                current_sensor_mode=_normalize_arg(args[6], c_uint),
                output_mode=_normalize_arg(args[7], c_ubyte),
                reserved1=_normalize_arg(args[8], c_ubyte*19)
            )
        else:
            src_buffer = args[0]
        _validate_call(_lib.ivm_set_measurement_settings(self._handle, byref(src_buffer)))

    class CalibrationSettingsRequest(_IterableStructure):
        _fields_ = (
            ("_reserved0", c_ubyte*8),
            ("_adc_mult", c_float),
            ("_adcv_offset", c_float),
            ("_current_sense1_mult", c_float),
            ("_current_sense1_offset", c_float),
            ("_current_sense2_mult", c_float),
            ("_current_sense2_offset", c_float),
            ("_current_sense3_mult", c_float),
            ("_current_sense3_offset", c_float),
            ("_reserved1", c_ubyte*72),
        )

        @property
        def reserved0(self) -> c_ubyte*8:
            return self._reserved0

        @reserved0.setter
        def reserved0(self, value: Union[Sequence[int], c_ubyte*8]) -> None:
            self._reserved0 = _normalize_arg(value, c_ubyte*8)

        @property
        def adc_mult(self) -> c_float:
            return self._adc_mult

        @adc_mult.setter
        def adc_mult(self, value: Union[float, c_float]) -> None:
            self._adc_mult = _normalize_arg(value, c_float)

        @property
        def adcv_offset(self) -> c_float:
            return self._adcv_offset

        @adcv_offset.setter
        def adcv_offset(self, value: Union[float, c_float]) -> None:
            self._adcv_offset = _normalize_arg(value, c_float)

        @property
        def current_sense1_mult(self) -> c_float:
            return self._current_sense1_mult

        @current_sense1_mult.setter
        def current_sense1_mult(self, value: Union[float, c_float]) -> None:
            self._current_sense1_mult = _normalize_arg(value, c_float)

        @property
        def current_sense1_offset(self) -> c_float:
            return self._current_sense1_offset

        @current_sense1_offset.setter
        def current_sense1_offset(self, value: Union[float, c_float]) -> None:
            self._current_sense1_offset = _normalize_arg(value, c_float)

        @property
        def current_sense2_mult(self) -> c_float:
            return self._current_sense2_mult

        @current_sense2_mult.setter
        def current_sense2_mult(self, value: Union[float, c_float]) -> None:
            self._current_sense2_mult = _normalize_arg(value, c_float)

        @property
        def current_sense2_offset(self) -> c_float:
            return self._current_sense2_offset

        @current_sense2_offset.setter
        def current_sense2_offset(self, value: Union[float, c_float]) -> None:
            self._current_sense2_offset = _normalize_arg(value, c_float)

        @property
        def current_sense3_mult(self) -> c_float:
            return self._current_sense3_mult

        @current_sense3_mult.setter
        def current_sense3_mult(self, value: Union[float, c_float]) -> None:
            self._current_sense3_mult = _normalize_arg(value, c_float)

        @property
        def current_sense3_offset(self) -> c_float:
            return self._current_sense3_offset

        @current_sense3_offset.setter
        def current_sense3_offset(self, value: Union[float, c_float]) -> None:
            self._current_sense3_offset = _normalize_arg(value, c_float)

        @property
        def reserved1(self) -> c_ubyte*72:
            return self._reserved1

        @reserved1.setter
        def reserved1(self, value: Union[Sequence[int], c_ubyte*72]) -> None:
            self._reserved1 = _normalize_arg(value, c_ubyte*72)

    CalibrationSettingsResponse = CalibrationSettingsRequest

    def get_calibration_settings(self, **kwargs) -> "CalibrationSettingsResponse":
        dst_buffer = kwargs.get("dst_buffer", self.CalibrationSettingsResponse())
        _validate_call(_lib.ivm_get_calibration_settings(self._handle, byref(dst_buffer)))
        return dst_buffer

    @overload  # noqa: F811
    def set_calibration_settings(
            self,
            reserved0: Union[Sequence[int], c_ubyte*8],
            adc_mult: Union[float, c_float],
            adcv_offset: Union[float, c_float],
            current_sense1_mult: Union[float, c_float],
            current_sense1_offset: Union[float, c_float],
            current_sense2_mult: Union[float, c_float],
            current_sense2_offset: Union[float, c_float],
            current_sense3_mult: Union[float, c_float],
            current_sense3_offset: Union[float, c_float],
            reserved1: Union[Sequence[int], c_ubyte*72]
    ) -> None: pass

    @overload  # noqa: F811
    def set_calibration_settings(
            self,
            src_buffer: CalibrationSettingsRequest
    ) -> None: pass

    def set_calibration_settings(self, *args) -> None:  # noqa: F811
        src_buffer = None
        if len(args) != 1 or not isinstance(args[0], self.CalibrationSettingsRequest):
            src_buffer = self.CalibrationSettingsRequest(
                reserved0=_normalize_arg(args[0], c_ubyte*8),
                adc_mult=_normalize_arg(args[1], c_float),
                adcv_offset=_normalize_arg(args[2], c_float),
                current_sense1_mult=_normalize_arg(args[3], c_float),
                current_sense1_offset=_normalize_arg(args[4], c_float),
                current_sense2_mult=_normalize_arg(args[5], c_float),
                current_sense2_offset=_normalize_arg(args[6], c_float),
                current_sense3_mult=_normalize_arg(args[7], c_float),
                current_sense3_offset=_normalize_arg(args[8], c_float),
                reserved1=_normalize_arg(args[9], c_ubyte*72)
            )
        else:
            src_buffer = args[0]
        _validate_call(_lib.ivm_set_calibration_settings(self._handle, byref(src_buffer)))

    def __init__(self, uri, defer_open=False):
        if isinstance(uri, str):
            uri = uri.encode("utf-8")
        if not isinstance(uri, (bytes, bytearray)):
            raise ValueError()
        self._uri = uri
        self._handle = None
        if not defer_open:
            self.open_device()
    if version_info >= (3, 4):
        def __del__(self):
            if self._handle:
                self.close_device()

    @property
    def uri(self):
        return self._uri

    def open_device(self):
        if self._handle is not None:
            return False

        handle = _lib.ivm_open_device(self._uri)
        if handle.value == _DeviceUndefined:
            raise UrpcDeviceUndefinedError()

        self._handle = handle
        return True

    def lib_version(self):
        ver_lib = create_string_buffer(str.encode("00.00.00"))
        result = _lib.ivm_libversion(ver_lib)
        _validate_call(result)
        version_lib = ver_lib.value.decode("utf-8")
        return version_lib

    def close_device(self):
        if self._handle is None:
            return False

        try:
            result = _lib.ivm_close_device(byref(self._handle))
            _validate_call(result)
        except Exception as e:
            raise e
        else:
            return True
        finally:
            self._handle = None

    def get_profile(self):
        buffer = c_char_p()

        @CFUNCTYPE(c_void_p, c_size_t)
        def allocate(size):
            # http://bugs.python.org/issue1574593
            return cast(create_string_buffer(size+1), c_void_p).value

        _validate_call(_lib.ivm_get_profile(self._handle, byref(buffer), allocate))
        return buffer.value.decode("utf-8")

    def set_profile(self, source):
        if isinstance(source, str):
            source = source.encode("utf-8")
        _validate_call(_lib.ivm_set_profile(self._handle, c_char_p(source), len(source)))
