#!/usr/bin/env python3
""" ctypes wrapper for AudioScience HPI library

This is a very thin wrapper around the HPI C API,
you can use the C API docs as a reference

The main differences are
- The subsys pointer parameter is not present as the
  first parameter of most functions
- the 'HPI_' prefix is replaced with the 'hpi.' namespace of this module
- parameters that return values become python return values in
  a tuple with the function's error code.
  E.g. C:     err = HPI_OutStreamOpen(phSS, adapter_index, 0, &stream_handle)
  python:  err, stream_handle = hpi.OutStream_Open(adapter_index, 0)
- Function names consistently have an underscore between the object and
  the operation, whether or not the C function does.

Other differences
  HPI_OutStreamWriteBuf does not require a byte count,
  as it is implicit in the python string parameter
  HPI_FormatCreate bitrate and attributes parameters default to 0
  Some functions not implemented, see the end of this file for details.

Note: brief benchmark suggest negligible slowdown compared with SWIG wrapper

(c) AudioScience Inc 2010-2011
"""


__version__ = "1.0.0"

from ctypes import *
from ctypes.util import find_library
import sys
import time

class HpiError(Exception):

    def __init__(self, value, comment=None, handle=None, func=None, args=None, kwargs=None):
        self.value = value
        self.comment = comment
        self.handle = handle
    def __str__(self):
        msg = 'HPI Error %s' % GetErrorText(self.value)
        if self.comment:
           msg = self.comment + ':'+ msg
        return msg


def always_tuple(var):
    try:
        return tuple(var)
    except TypeError:
        return (var, )

def raise_error(var, comment=''):
    """Raise HpiError if first element of var is non-zero

    This is intended as a cleaner way of testing for an error being returned by
    an HPI function.

    If the first item in the returned tuple is None or zero no exception is triggered
    >>> raise_err( (None, 1, 2, 3) )
    (1, 2, 3)

    If the first item in the tuple is different from None an exception wrapping
    the error is created and raised

    >>> try:
    ...     raise_err( ('anything really...', 1, 2) )
    ...     print("Exception expected")
    ... except Exception, e:
    ...     pass
    """
    # print 'testErr', comment, var, type(var)
    # var or its first element if it is an iterable
    # is treated as an HPI error code
    if hasattr(var,'__iter__'):
        l = len(var)
        # Raise an exception in case of error
        if var[0]:
            raise HpiError(var[0], comment)
        # or return the remaining items in the iterable if there is no error
        if (l > 2):
            return var[1:]
        return var[1]
    else:
        if var:
            raise HpiError(var, comment)

def raise_error_detailed(func, *args):
    """
    Raise error, with details of function and arguments that returned it
    """
    return raise_error(func(*args), comment='%s%s' % (func, args))


_libhpi = None
_ss = None

if sys.platform.startswith('win'):
    plat_loader = windll
    plat_lib_name = 'asihpi32'
    # need to handle 'asihpi64' here somehow?
else:
    plat_loader = cdll
    plat_lib_name = 'hpi'

def loadlib(libname, ipaddr=None):
    '''Load new library by name.
    Allows switching between different libs at runtime'''
    global _libhpi
    global _ss
    hpilibpath = find_library(libname)
    if hpilibpath == None:
        raise IOError('Could not find library with base name "%s"' % libname)

    _libhpi = plat_loader.LoadLibrary(hpilibpath)

def SubSys_Create():
    #_libhpi.HPI_SubSysCreate.restype = PHPI_HSUBSYS
    #_ss = _libhpi.HPI_SubSysCreate()
    _libhpi.HPI_SubSysCreate()

# Wait till setup() to load library. All hpi apps must call setup now.
# This is to allow SubSysSetHostNetworkInterface to be called before
# SubSysCreate
#loadlib(plat_lib_name)

_current_adapter_setup = None
def setup(adapter=0, ipaddr=None, subsyscreate=True):
    '''Special initialization based on adapter index and os'''
    global _current_adapter_setup
    if sys.platform.startswith('win'):
        loadlib(plat_lib_name, ipaddr)
        # windows hpiudp discovery is always asynchronous
        time.sleep(2)
    elif adapter >= 20:
        loadlib('hpiudp', ipaddr)
    else:
        loadlib(plat_lib_name)
    if sys.platform.startswith('win') and (ipaddr == None):
        import socket
        ipaddr = socket.gethostbyname(socket.gethostname())

    if (ipaddr != None):
        SubSys_SetHostNetworkInterface(ipaddr)

    if subsyscreate:
        SubSys_Create()
    _current_adapter_setup = adapter

def close():
    if _libhpi:
        _libhpi.HPI_SubSysFree(None)

# DATATYPES
err_t = c_uint16 # hpi error type
handle_t = c_uint32 # hpi handle type
int16_array2_t = c_int16 * 2 # Array of 2 log values e.g. meter, volume, level

class hpi_format(Structure):
    _pack_ = 1
    _fields_ = [ # could just use opaque 20 byte array
        ('samplerate', c_uint32),
        ('bitrate', c_uint32),
        ('attributes', c_uint32),
        ('mode_legacy', c_uint16),
        ('unused', c_uint16),
        ('channels', c_uint16),
        ('format', c_uint16),
    ]

# CONSTANTS
# Adapter mode commands
ADAPTER_MODE_SET = 0
ADAPTER_MODE_QUERY = 1

## adapter modes
ADAPTER_MODE_4OSTREAM  = 1
ADAPTER_MODE_6OSTREAM  = 2
ADAPTER_MODE_8OSTREAM = 3
ADAPTER_MODE_16OSTREAM = 4
ADAPTER_MODE_1OSTREAM = 5
ADAPTER_MODE_1 = 6
ADAPTER_MODE_2 = 7
ADAPTER_MODE_3 = 8
ADAPTER_MODE_MULTICHANNEL = 9
ADAPTER_MODE_12OSTREAM = 10
ADAPTER_MODE_9OSTREAM = 11
ADAPTER_MODE_MONO = 12
ADAPTER_MODE_LOW_LATENCY = 13

## ADAPTER PROPERTIES
ADAPTER_PROPERTY_ERRATA_1 =		1
ADAPTER_PROPERTY_GROUPING =	2
ADAPTER_PROPERTY_ENABLE_SSX2 =	3
ADAPTER_PROPERTY_SSX2_SETTING =	4
ADAPTER_PROPERTY_IRQ_RATE = 5

ADAPTER_PROPERTY_LATENCY  = 256
ADAPTER_PROPERTY_GRANULARITY  = 257
ADAPTER_PROPERTY_CURCHANNELS  = 258
ADAPTER_PROPERTY_SOFTWARE_VERSION  =259
ADAPTER_PROPERTY_MAC_ADDRESS_MSB  = 260
ADAPTER_PROPERTY_MAC_ADDRESS_LSB  = 261
ADAPTER_PROPERTY_EXTENDED_ADAPTER_TYPE = 262
ADAPTER_PROPERTY_LOGTABLEN  = 263
ADAPTER_PROPERTY_LOGTABBEG  = 264
ADAPTER_PROPERTY_IP_ADDRESS  = 265
ADAPTER_PROPERTY_BUFFER_UPDATE_COUNT  = 266
ADAPTER_PROPERTY_INTERVAL  = 267
ADAPTER_PROPERTY_CAPS1  = 268
ADAPTER_PROPERTY_CAPS2  = 269
ADAPTER_PROPERTY_SYNC_HEADER_CONNECTIONS  = 270
ADAPTER_PROPERTY_SUPPORTS_SSX2 = 271
ADAPTER_PROPERTY_SUPPORTS_IRQ = 272
ADAPTER_PROPERTY_SUPPORTS_FW_UPDATE = 273

## HPI ERRORS
# Message type does not exist.
ERROR_INVALID_TYPE	= 100
# Object type does not exist.
ERROR_INVALID_OBJ	= 101
# Function does not exist.
ERROR_INVALID_FUNC	= 102
# The specified object (adapter/Stream) does not exist.
ERROR_INVALID_OBJ_INDEX= 103
# Trying to access an object that has not been opened yet.
ERROR_OBJ_NOT_OPEN	= 104
# Trying to open an already open object.
ERROR_OBJ_ALREADY_OPEN= 105
# PCI ISA resource not valid.
ERROR_INVALID_RESOURCE= 106
# GetInfo call from SubSysFindAdapters failed.
ERROR_SUBSYSFINDADAPTERS_GETINFO= 107
# Default response was never updated with actual error code.
ERROR_INVALID_RESPONSE= 108
# wSize field of response was not updated indicating that the message was not processed.
ERROR_PROCESSING_MESSAGE= 109
# The network did not respond in a timely manner.
ERROR_NETWORK_TIMEOUT= 110
# An HPI handle is invalid (uninitialised?).
ERROR_INVALID_HANDLE= 111
# A function or attribute has not been implemented yet.
ERROR_UNIMPLEMENTED	= 112
# There are too many clients attempting to access a network resource.
ERROR_NETWORK_TOO_MANY_CLIENTS= 113
# Response buffer passed to Message was smaller than returned response
ERROR_RESPONSE_BUFFER_TOO_SMALL = 114
# The returned response did not match the sent message
ERROR_RESPONSE_MISMATCH = 115

# Too many adapters.
ERROR_TOO_MANY_ADAPTERS= 200
# Bad adpater.
ERROR_BAD_ADAPTER	= 201
# Adapter number out of range or not set properly.
ERROR_BAD_ADAPTER_NUMBER= 202
# 2 adapters with the same adapter number.
DUPLICATE_ADAPTER_NUMBER= 203
# DSP code failed to bootload.
ERROR_DSP_BOOTLOAD	= 204
# Failure during message/response
ERROR_DSP_COMMUNICATION	= 900
# Couldn't find or open the DSP code file.
ERROR_DSP_FILE_NOT_FOUND= 206
# Internal DSP hardware error.
ERROR_DSP_HARDWARE	= 207
# Could not allocate memory in DOS.
ERROR_DOS_MEMORY_ALLOC= 208
# Could not allocate memory
ERROR_MEMORY_ALLOC	= 208
# Failed to correctly load/config PLD .
ERROR_PLD_LOAD	= 209
# Unexpected end of file block length too big etc.
ERROR_DSP_FILE_FORMAT= 210

# Found but could not open DSP code file.
ERROR_DSP_FILE_ACCESS_DENIED = 211
# First DSP code section header not found in DSP file.
ERROR_DSP_FILE_NO_HEADER= 212
# File read operation on DSP code file failed.
ERROR_DSP_FILE_READ_ERROR= 213
# DSP code for adapter family not found.
ERROR_DSP_SECTION_NOT_FOUND= 214
# Other OS specific error opening DSP file.
ERROR_DSP_FILE_OTHER_ERROR= 215
# Sharing violation opening DSP code file.
ERROR_DSP_FILE_SHARING_VIOLATION= 216
# DSP code section header had size == 0.
ERROR_DSP_FILE_NULL_HEADER= 217

# Base number for flash errors.
ERROR_FLASH 		= 220

# Flash has bad checksum
ERROR_BAD_CHECKSUM =(ERROR_FLASH+1)
ERROR_BAD_SEQUENCE = (ERROR_FLASH+2)
ERROR_FLASH_ERASE = (ERROR_FLASH+3)
ERROR_FLASH_PROGRAM = (ERROR_FLASH+4)
ERROR_FLASH_VERIFY = (ERROR_FLASH+5)
ERROR_FLASH_TYPE = (ERROR_FLASH+6)
ERROR_FLASH_START = (ERROR_FLASH+7)
ERROR_FLASH_READ = (ERROR_FLASH+8)
ERROR_FLASH_READ_NO_FILE = (ERROR_FLASH+9)
ERROR_FLASH_BUSY = (ERROR_FLASH+10)
ERROR_FLASH_SIZE = (ERROR_FLASH+11)

# Reserved for OEMs.
ERROR_RESERVED_1	= 290

# Stream does not exist.
ERROR_INVALID_STREAM= 300
# Invalid compression format.
ERROR_INVALID_FORMAT= 301
# Invalid format samplerate
ERROR_INVALID_SAMPLERATE = 302
# Invalid format number of channels.
ERROR_INVALID_CHANNELS = 303
# Invalid format bitrate.
ERROR_INVALID_BITRATE = 304
# Invalid datasize used for stream read/write.
ERROR_INVALID_DATASIZE = 305
# Stream buffer is full during stream write.
ERROR_BUFFER_FULL	= 306
# Stream buffer is empty during stream read.
ERROR_BUFFER_EMPTY	= 307
# Invalid datasize used for stream read/write.
ERROR_INVALID_DATA_TRANSFER = 308
# Packet ordering error for stream read/write.
ERROR_INVALID_PACKET_ORDER = 309

# Object can't do requested operation in its current state eg set format change rec mux state while recording.
ERROR_INVALID_OPERATION= 310

# Where an SRG is shared amongst streams an incompatible samplerate is one
# that is different to any currently playing or recording stream.
ERROR_INCOMPATIBLE_SAMPLERATE = 311
# Adapter mode is illegal.
ERROR_BAD_ADAPTER_MODE = 312

# There have been too many attempts to set the adapter's
# capabilities (using bad keys) the card should be returned
# to ASI if further capabilities updates are required
ERROR_TOO_MANY_CAPABILITY_CHANGE_ATTEMPTS = 313
# Streams on different adapters cannot be grouped.
ERROR_NO_INTERADAPTER_GROUPS = 314
# Streams on different DSPs cannot be grouped.
ERROR_NO_INTERDSP_GROUPS = 315

# Wait cancelled or timed out
ERROR_WAIT_CANCELLED = 316

# Invalid mixer node for this adapter.
ERROR_INVALID_NODE	= 400
# Invalid control.
ERROR_INVALID_CONTROL = 401
# Invalid control value was passed.
ERROR_INVALID_CONTROL_VALUE = 402
# Control attribute not supported by this control.
ERROR_INVALID_CONTROL_ATTRIBUTE = 403
# Control is disabled.
ERROR_CONTROL_DISABLED = 404
# I2C transaction failed due to a missing ACK.
ERROR_CONTROL_I2C_MISSING_ACK= 405
# Control attribute is valid but not supported by this hardware.
ERROR_UNSUPPORTED_CONTROL_ATTRIBUTE = 406
# Control is busy or coming out of reset and cannot be accessed at this time.
ERROR_CONTROL_NOT_READY = 407

# Non volatile memory
ERROR_NVMEM_BUSY	= 450
ERROR_NVMEM_FULL	= 451
ERROR_NVMEM_FAIL	= 452

# I2C
ERROR_I2C_MISSING_ACK = ERROR_CONTROL_I2C_MISSING_ACK
ERROR_I2C_BAD_ADR	= 460

# Entity errors
ERROR_ENTITY_TYPE_MISMATCH = 470
ERROR_ENTITY_ITEM_COUNT = 471
ERROR_ENTITY_TYPE_INVALID = 472
ERROR_ENTITY_ROLE_INVALID = 473
ERROR_ENTITY_SIZE_MISMATCH = 474

# custom error to use for debugging
ERROR_CUSTOM =		600

# hpioct32.c can't obtain mutex
ERROR_MUTEX_TIMEOUT =		700

# errors from HPI backends have values >= this
ERROR_BACKEND_BASE =		900

## STREAM FORMATS
FORMAT_MIXER_NATIVE = 0
FORMAT_PCM8_UNSIGNED = 1
FORMAT_PCM16_SIGNED = 2
FORMAT_MPEG_L1 = 3
FORMAT_MPEG_L2 = 4
FORMAT_MPEG_L3 = 5
FORMAT_DOLBY_AC2 = 6
FORMAT_DOLBY_AC3 = 7
FORMAT_PCM16_BIGENDIAN = 8
FORMAT_AA_TAGIT1_HITS = 9
FORMAT_AA_TAGIT1_INSERTS = 10
FORMAT_PCM32_SIGNED = 11
FORMAT_RAW_BITSTREAM = 12
FORMAT_AA_TAGIT1_HITS_EX1 = 13
FORMAT_PCM32_FLOAT = 14
FORMAT_PCM24_SIGNED = 15
FORMAT_OEM1 = 16
FORMAT_OEM2 = 17
FORMAT_UNDEFINED = 0xffff

## STREAM STATES
STATE_STOPPED = 1
STATE_PLAYING = 2
STATE_RECORDING = 3
STATE_DRAINED = 4
STATE_SINEGEN = 5
STATE_WAIT = 6

## SOURCENODES
SOURCENODE_NONE = 100
SOURCENODE_OSTREAM = 101
SOURCENODE_LINEIN = 102
SOURCENODE_AESEBU_IN = 103
SOURCENODE_TUNER = 104
SOURCENODE_RF = 105
SOURCENODE_CLOCK_SOURCE = 106
SOURCENODE_RAW_BITSTREAM = 107
SOURCENODE_MICROPHONE = 108
SOURCENODE_COBRANET = 109
SOURCENODE_ANALOG = 110
SOURCENODE_ADAPTER = 111
SOURCENODE_RTP_DESTINATION = 112
SOURCENODE_INTERNAL = 113
SOURCENODE_AVB = 114
SOURCENODE_BLULINK = 115
SOURCENODE_AVB_AUDIO = 116

class SOURCENODE(object):
    NONE = 100
    OSTREAM = 101
    LINEIN = 102
    AESEBU_IN = 103
    TUNER = 104
    RF = 105
    CLOCK_SOURCE = 106
    RAW_BITSTREAM = 107
    MICROPHONE = 108
    COBRANET = 109
    ANALOG = 110
    ADAPTER = 111
    RTP_DESTINATION = 112
    INTERNAL = 113
    AVB = 114
    BLULINK = 115
    AVB_AUDIO = 116

## DESTNODES
DESTNODE_NONE = 200
DESTNODE_ISTREAM = 201
DESTNODE_LINEOUT = 202
DESTNODE_AESEBU_OUT = 203
DESTNODE_RF = 204
DESTNODE_SPEAKER = 205
DESTNODE_COBRANET = 206
DESTNODE_ANALOG = 207
DESTNODE_RTP_SOURCE = 208
DESTNODE_AVB = 209
DESTNODE_INTERNAL = 210
DESTNODE_BLULINK = 211
DESTNODE_AVB_AUDIO = 212

class DESTNODE(object):
    NONE = 200
    ISTREAM = 201
    LINEOUT = 202
    AESEBU_OUT = 203
    RF = 204
    SPEAKER = 205
    COBRANET = 206
    ANALOG = 207
    RTP_SOURCE = 208
    AVB = 209
    INTERNAL = 210
    BLULINK = 211
    AVB_AUDIO = 212

## CONTROL TYPES
CONTROL_GENERIC     = 0
CONTROL_CONNECTION = 1
CONTROL_VOLUME     = 2
CONTROL_METER = 3
CONTROL_MUTE = 4
CONTROL_MULTIPLEXER = 5
CONTROL_AESEBU_TRANSMITTER = 6
CONTROL_AESEBU_RECEIVER = 7
CONTROL_LEVEL = 8
CONTROL_TUNER = 9
CONTROL_VOX = 11
CONTROL_CHANNEL_MODE = 15
CONTROL_BITSTREAM = 16
CONTROL_SAMPLECLOCK = 17
CONTROL_MICROPHONE     = 18
CONTROL_PARAMETRIC_EQ = 19
CONTROL_EQUALIZER = CONTROL_PARAMETRIC_EQ
CONTROL_COMPANDER = 20
CONTROL_COBRANET = 21
CONTROL_TONEDETECTOR = 22
CONTROL_SILENCEDETECTOR = 23
CONTROL_PAD = 24
CONTROL_SRC = 25
CONTROL_UNIVERSAL = 26

class CONTROL(object):
    GENERIC = 0
    CONNECTION = 1
    VOLUME = 2
    METER = 3
    MUTE = 4
    MULTIPLEXER = 5
    AESEBU_TRANSMITTER = 6
    AESEBU_RECEIVER = 7
    LEVEL = 8
    TUNER = 9
    VOX = 11
    CHANNEL_MODE = 15
    BITSTREAM = 16
    SAMPLECLOCK = 17
    MICROPHONE = 18
    PARAMETRIC_EQ = 19
    EQUALIZER = 19
    COMPANDER = 20
    COBRANET = 21
    TONEDETECTOR = 22
    SILENCEDETECTOR = 23
    PAD = 24
    SRC = 25
    UNIVERSAL = 26

## VOLUME AUTOFADE PROFILES
VOLUME_AUTOFADE_LOG = 2
VOLUME_AUTOFADE_LINEAR	= 3

## CHANNEL MODES
CHANNEL_MODE_INVALID = 0
CHANNEL_MODE_NORMAL = 1
CHANNEL_MODE_SWAP = 2
CHANNEL_MODE_LEFT_TO_STEREO = 3
CHANNEL_MODE_RIGHT_TO_STEREO = 4
CHANNEL_MODE_STEREO_TO_LEFT = 5
CHANNEL_MODE_STEREO_TO_RIGHT = 6

## MIXER STORE COMMANDS
MIXER_STORE_SAVE = 1
MIXER_STORE_RESTORE = 2
MIXER_STORE_DELETE = 3
MIXER_STORE_ENABLE = 4
MIXER_STORE_DISABLE = 5
MIXER_STORE_SAVE_SINGLE = 6

## RDS DATATYPES
RDS_DATATYPE_RDS = 0
RDS_DATATYPE_RBDS = 1

## SAMPLECLOCK SOURCES
SAMPLECLOCK_SOURCE_INVALID = 0
SAMPLECLOCK_SOURCE_LOCAL = 1
SAMPLECLOCK_SOURCE_AESEBU_SYNC = 2
SAMPLECLOCK_SOURCE_WORD = 3
SAMPLECLOCK_SOURCE_WORD_HEADER = 4
SAMPLECLOCK_SOURCE_SMPTE  = 5
SAMPLECLOCK_SOURCE_AESEBU_INPUT  = 6
SAMPLECLOCK_SOURCE_NETWORK = 8
SAMPLECLOCK_SOURCE_PREV_MODULE = 10
SAMPLECLOCK_SOURCE_BLULINK = 11

## TUNER BANDS
TUNER_BAND_INVALID = 0
TUNER_BAND_AM = 1
TUNER_BAND_FM = 2
TUNER_BAND_TV_NTSC_M = 3
TUNER_BAND_TV = 3
TUNER_BAND_FM_STEREO = 4
TUNER_BAND_AUX = 5
TUNER_BAND_TV_PAL_BG = 6
TUNER_BAND_TV_PAL_I = 7
TUNER_BAND_TV_PAL_DK = 8
TUNER_BAND_TV_SECAM_L = 9
TUNER_BAND_DAB = 10

UNITS_PER_dB = 100.0

BITMASK_ALL_CHANNELS = 0xFFFFFFFF

d = dir()
# Group some of the constants into dictionaries, get name from value
def make_dict(root, d):
    '''Create dictionary mapping between symbol names and values,
    list of strings is passed in in d,  only symbols starting with string root are included'''
    n = [x for x in d if (x.startswith(root) and not (x.endswith('SET') or x.endswith('QUERY'))) ]
    v = [eval(s) for s in n]
    return dict(list(zip(v,n)))

def reverse_dict(d):
    '''Create a dict with keys and values swapped from the input dict'''
    return dict((v,k) for k, v in d.items())

AdapterModeDict = make_dict('ADAPTER_MODE_', d)
AdapterPropertyDict = make_dict('ADAPTER_PROPERTY_', d)
ControlDict = make_dict('CONTROL_', d)
SourceNodeDict = make_dict('SOURCENODE', d)
DestNodeDict = make_dict('DESTNODE', d)
ChannelModeDict = make_dict('CHANNEL_MODE_', d)
TunerBandDict = make_dict('TUNER_BAND_', d)
SampleClockSourceDict = make_dict('SAMPLECLOCK_SOURCE_', d)
FormatDict = make_dict('FORMAT_', d)
ErrorDict = make_dict('ERROR_', d)

SourceDict = SourceNodeDict
DestDict = DestNodeDict

# UTILITY FUNCTIONS
def info_string(thing, index, ai, swver=None):
    if ai[0]:
        return 'invalid'

    s = "%s %2d ASI%X, " % (thing, index, ai[5])
    if (ai[4]):
        s = s + 'serial %d, ' % ai[4]
    if swver is not None:
        s = s + "SW version %s, " % swver
    s = s + "HW version %c%d, " % (chr(ord('A')+((ai[3] >> 3)& 0xF)) , ((ai[3] >> 0) & 0x7))
    s = s + "%d inputs, %d outputs" % (ai[2],ai[1])
    return s

def GetErrorText(e):
    if not e:
        return 'No Error'

    s = ErrorDict.get(e, 'Unknown Error Code')
    return '#%d - %s' % (e, s)

def Format_Create(channels, format, samplerate, bitrate=0, attributes=0):
    f = hpi_format()
    _libhpi.HPI_FormatCreate.restype = err_t
    e = _libhpi.HPI_FormatCreate(byref(f), channels, format,
            samplerate, bitrate, attributes)
    return e, f

def Message(m, max_rsize=128):
    '''Low level HPI message
    '''
    msize = ord(m[0]) + 256 * ord(m[1])
    if msize != len(m):
        print('Message size mismatch %d %d' % (msize, len(m)))

    cm = create_string_buffer(m)
    s1 = max_rsize // 256
    s0 = max_rsize - s1 * 256
    r = chr(s0) + chr(s1) # response wSize field
    cr = create_string_buffer(r, max_rsize)

    _libhpi.HPI_Message(byref(cm), byref(cr))
    r = cr.raw
    rsize = ord(r[0]) + 256 * ord(r[1])
    if rsize < 12: # HPI header size
        rsize = 12
        print('Invalid response size %d' % rsize)
    return cr.raw[0:rsize]

def MessageUDP(m, timeout=20, max_rsize=128):
    '''Low level HPI message
    '''
    msize = ord(m[0]) + 256 * ord(m[1])
    if msize != len(m):
        print('Message size mismatch %d %d' % (msize, len(m)))

    cm = create_string_buffer(m)
    s1 = max_rsize // 256
    s0 = max_rsize - s1 * 256
    r = chr(s0) + chr(s1) # response wSize field
    cr = create_string_buffer(r, max_rsize)

    _libhpi.HPI_MessageUDP(byref(cm), byref(cr), timeout)
    r = cr.raw
    rsize = ord(r[0]) + 256 * ord(r[1])
    if rsize < 12: # HPI header size
        rsize = 12
        print('Invalid response size %d' % rsize)
    return cr.raw[0:rsize]

## Entity

#enum e_entity_type
entity_type_null = 0
entity_type_sequence = 1
entity_type_reference =  2
entity_type_int =   3
entity_type_float =  4
entity_type_double = 5
entity_type_cstring = 6
entity_type_octet = 7
entity_type_ip4_address = 8
entity_type_ip6_address = 9
entity_type_mac_address = 10
entity_type_bit = 11

et2ct = {
    entity_type_null : None,
    entity_type_sequence : c_char,
    entity_type_reference :  c_uint32,
    entity_type_int :   c_int32,
    entity_type_float :  c_float,
    entity_type_double : c_double,
    entity_type_cstring : c_char,
    entity_type_octet : c_uint8,
    entity_type_ip4_address :  c_uint8 * 4,
    entity_type_ip6_address :  c_uint8 * 16,
    entity_type_mac_address :  c_uint8 * 6,
    entity_type_bit : c_char
}

#enum e_entity_role
entity_role_null = 0
entity_role_value = 1
entity_role_classname = 2
entity_role_units = 3
entity_role_flags = 4
entity_role_range = 5
entity_role_mapping = 6
entity_role_enum = 7
entity_role_instance_of = 8
entity_role_depends_on = 9
entity_role_member_of_group = 10
entity_role_value_constraint = 11
entity_role_parameter_port = 12
entity_role_block = 13
entity_role_label = 14
entity_role_key = 15
entity_role_value_label = 16
#entity_role_node_group = 14
#entity_role_audio_port = 15
#entity_role_clock_port = 16

entity_flag_writeable = 1
entity_flag_readable = 2
entity_flag_volatile = 4
entity_flag_volatile_info = 8

d = dir()
EntityTypeDict = make_dict('entity_type_', d)
EntityRoleDict = make_dict('entity_role_', d)
EntityFlagDict = make_dict('entity_flag_', d)

entity = c_void_p

def print_entity(ent, level=0):
    e,t,i,r,v = Entity_Unpack(ent)
    print('--' * level, end='')
    stype = EntityTypeDict.get(t, 'entity_type_unknown_%d' % t)
    srole = EntityRoleDict.get(r, 'entity_role_unknown_%d' % r)
    stype = stype[12:]
    srole = srole[12:]
    print('%s %s[%d]' % (stype, srole, i), end='')

    if t == entity_type_sequence:
        print()
        current = entity()
        while True:
            e, current = Entity_FindNext(ent, entity_type_null, entity_role_null, 0, current)
            if current.value == None: break
            print_entity(current, level = level + 1)

#    elif t == entity_type_reference:
#        print 'reference'
#        get referenced entity, print it

    elif r == entity_role_null:
        print('padding?')
    else:
        e, v = Entity_CopyValueFrom(ent, t, i)
        if not e:
            print('=',v, end='')
            if r == entity_role_flags and v:
                for b in range(8):
                    bm = 1 << b
                    if v & bm:
                        fs = EntityFlagDict.get(bm, 'entity_flag_unknown_%d' % bm)[12:]
                        print(fs, end='')
            print()
        else:
            print(GetErrorText(e))

def ct_val(type, value):
    '''Create initialized ctypes variable from value, given type'''
    ct = et2ct[type]
    item_count = 1
    if type ==  entity_type_cstring:
        val = create_string_buffer(value)
        item_count = len(value)
    elif (type == entity_type_ip4_address or
        type == entity_type_ip6_address or
        type == entity_type_ip6_address):
        try: # value is list of lists or tuples
            vl = len(value[0])
            item_count = len(value)
            vt = ct * item_count
        except TypeError:
            vl = len(value)
            item_count = 1
            vt = ct
        val = vt(*value)
    else:
        try:
            item_count = len(value)
            vt = ct * item_count
            val = vt(*value)
        except:
            vt = ct
            val = vt(value)

    return item_count, val

def ct_var(type, count):
    '''Create empty ctypes variable for type,count'''
    ct = et2ct[type]
    if type == entity_type_cstring:
        val = create_string_buffer(count+1)
    else:
        if count > 1:
            vt = count * ct
        else:
            vt = ct
        val = vt()
    return val

def ct_retval(type, val, count):
    if type == entity_type_ip4_address:
        subcount = 4
    elif type == entity_type_ip6_address:
        subcount = 16
    elif type == entity_type_mac_address:
        subcount = 6;
    else:
        subcount = 1;


    if type == entity_type_cstring or (count < 2 and subcount == 1):
        v = val.value
    else:
        if count == 1:
            count = subcount
            subcount = 1
        v = []
        for i in range(count):
            if subcount > 1:
                subval = val[i]
                sv = []
                for j in range(subcount):
                    sv.append(subval[j])
                v.append(tuple(sv))
            else:
                v.append(val[i])
    return v

def Entity_FindNext(cont, type, role, recurse, current=None):
    if current == None:
        current = entity()
    _libhpi.HPI_Entity_FindNext.restype = err_t
    e = _libhpi.HPI_Entity_FindNext(cont, type, role, recurse, byref(current))
    return e, current

def Entity_CopyValueFrom(ent, type, count):
    val = ct_var(type, count)
    _libhpi.HPI_Entity_CopyValueFrom.restype = err_t
    e = _libhpi.HPI_Entity_CopyValueFrom(ent, type, count, byref(val), sizeof(val))
    return e, ct_retval(type, val, count)

def Entity_Unpack(ent):
    '''Unpack entity, returning
       err, type, items,role, value pointer
    '''
    type = c_int32()
    role = c_int32()
    val = c_void_p()
    items = c_size_t()
    _libhpi.HPI_Entity_Unpack.restype = err_t
    e = _libhpi.HPI_Entity_Unpack(ent, byref(type), byref(items), byref(role), byref(val))
    return e, type.value, items.value, role.value, val

def Entity_AllocAndPack(type, role, value):
    'allocates entity internally, must follow with Entity_Free'
    item_count, val = ct_val(type, value)
    ent = entity()
    _libhpi.HPI_Entity_AllocAndPack.restype = err_t
    e = _libhpi.HPI_Entity_AllocAndPack(type, item_count, role, byref(val), sizeof(val), byref(ent))
    return e, ent

def Entity_Free(e):
    _libhpi.HPI_Entity_Free(e)

def MemFree(e):
    _libhpi.HPI_MemFree(e)

def _test_entity():
    # see that count is not needed, can take len(val) inside func
    val = [1234, 5678]
    e, ent = Entity_AllocAndPack(entity_type_int, entity_role_value, val)
    print('Entity_AllocAndPack', e, ent)
    e,t,i,r,v = Entity_Unpack(ent)

    print('Entity_Unpack', e, EntityTypeDict[t], EntityRoleDict[r], 'items=', i)
    pi = cast(v, POINTER(c_int32))

    r = Entity_CopyValueFrom(ent, t, i)
    print(r)
    Entity_Free(ent)

    val = b"Test string"
    e, ent = Entity_AllocAndPack(entity_type_cstring, entity_role_value, val)
    print('Entity_AllocAndPack', e, ent)
    e,t,i,r,v = Entity_Unpack(ent)

    print('Entity_Unpack', e, EntityTypeDict[t], EntityRoleDict[r], 'items=', i)

    r = Entity_CopyValueFrom(ent, t, i)
    print(r)
    Entity_Free(ent)

def Object_UriToHandle(uri):
    cth = c_uint32()
    uri = create_string_buffer(uri)
    _libhpi.HPI_Object_UriToHandle.restype = err_t
    e = _libhpi.HPI_Object_UriToHandle(uri, byref(cth))
    return e, cth.value

def Object_GetInfoEntity(h):
    ent = entity()
    _libhpi.HPI_Object_GetInfoEntity.restype = err_t
    e = _libhpi.HPI_Object_GetInfoEntity(h, byref(ent))
    return e, ent

def Object_GetValueEntity(h):
    ent = entity()
    _libhpi.HPI_Object_GetValueEntity.restype = err_t
    e = _libhpi.HPI_Object_GetValueEntity(h, byref(ent))
    return e, ent

def Object_SetValueEntity(h, ent):
    _libhpi.HPI_Object_SetValueEntity.restype = err_t
    return _libhpi.HPI_Object_SetValueEntity(h, ent)

def Object_GetValue(h, type, count):
    val = ct_var(type, count)
    _libhpi.HPI_Object_GetValue.restype = err_t
    e = _libhpi.HPI_Object_GetValue(h, type, count, byref(val), sizeof(val))
    return e, ct_retval(type, val, count)

def Object_SetValue(h, type, value):
    count, val = ct_val(type, value)
    _libhpi.HPI_Object_SetValue.restype = err_t
    e = _libhpi.HPI_Object_SetValue(h, type, count, byref(val), sizeof(val))
    return e

def Object_BlockHandle(hm, snt, sni, dnt, dni, cn):
    hctrl = handle_t()
    bname = create_string_buffer(cn)
    _libhpi.HPI_Object_BlockHandle.restype = err_t
    e = _libhpi.HPI_Object_BlockHandle(hm, snt, sni, dnt, dni, bname, byref(hctrl))
    return e, hctrl.value

def Object_ParameterHandle(hm, hb, cn):
    hctrl = handle_t()
    pname = create_string_buffer(cn)
    _libhpi.HPI_Object_ParameterHandle.restype = err_t
    e = _libhpi.HPI_Object_ParameterHandle(hm, hb, pname, byref(hctrl))
    return e, hctrl.value

def _test_obj2():
    objname = 'hpi://subsystem/network/enabled'
    e, h = Object_UriToHandle(objname)
    e, value = Object_GetValue(h, entity_type_int, 1)
    if not e:
            print('%s value is %d' % (objname, value))
    value = 0
    e = Object_SetValue(h, entity_type_int, value)
    if not e:
            print('Succeeded in setting %s to %d' % (objname, value))

def _test_obj():
    for uri in [
        'hpi://subsystem/network/enabled',
        'hpi://subsystem/network/ip/address',
        'hpi://subsystem/network/ip/mask',
        'hpi://subsystem/network/ip/udp/broadcast_enabled',
        'hpi://subsystem/network/ip/udp/unicast_enabled',
        'hpi://subsystem/network/ip/adapter_address_add',
        'hpi://other',
        'hpi://subsystem/other',
        'hpi://subsystem/network/other',
        'http://audioscience.com'
    ]:
        print('=' * 80)
        print('Getting',uri)
        e, h = Object_UriToHandle(uri)
        if not e and h:
            e, ent = Object_GetInfoEntity(h)
            if not e:
                print('**INFO ENTITY**')
                print_entity(ent)

            e, ent = Object_GetValueEntity(h)
            if not e:
                print('**VALUE ENTITY**')
                print_entity(ent)
                e, value = Entity_CopyValueFrom(ent, entity_type_int, 1)
                if not e: print('Entity_CopyValueFrom', value)
            e, value = Object_GetValue(h, entity_type_int, 1)
            if e: # Yuk!
                e, value = Object_GetValue(h, entity_type_ip4_address, 1)
            if not e:
                print('**VALUE**')
                print('Object_GetValue', e,value)

            e = Object_SetValue(h, entity_type_int, 2)
            print('Object_SetValue')
            if not e:
                e, value = Object_GetValue(h, entity_type_int, 1)
            if not e:
                print('**VALUE 2**')
                print('Object_GetValue', e, value)

        if e:
            print('Error',GetErrorText(e))

# SUBSYS FUNCTIONS

def SubSys_GetVersionEx():
    v = c_uint32()
    _libhpi.HPI_SubSysGetVersionEx.restype = err_t
    e = _libhpi.HPI_SubSysGetVersionEx(_ss, byref(v))
    return e, v.value

def SubSys_GetNumAdapters():
    v = c_int32()
    _libhpi.HPI_SubSysGetNumAdapters.restype = err_t
    e = _libhpi.HPI_SubSysGetNumAdapters(_ss, byref(v))
    return e, v.value

def SubSys_GetAdapter(i):
    ai = c_uint32()
    at = c_uint16()
    _libhpi.HPI_SubSysGetAdapter.restype = err_t
    e = _libhpi.HPI_SubSysGetAdapter(_ss, i, byref(ai), byref(at))
    return e, ai.value, at.value

def SubSys_Ssx2Bypass(bypass):
    _libhpi.HPI_SubSysSsx2Bypass.restype = err_t
    return _libhpi.HPI_SubSysSsx2Bypass(_ss, bypass)

def SubSys_SetHostNetworkInterface(interface):

    s = create_string_buffer(interface)
    e = c_uint16()
    _libhpi.HPI_SubSysSetHostNetworkInterface.restype = err_t
    return _libhpi.HPI_SubSysSetHostNetworkInterface(_ss, s)

def SubSys_OptionInfo(id):
    'allocates entity internally, must follow with Entity_Free'
    ge = entity()
    _libhpi.HPI_SubSys_OptionGet.restype = err_t
    e = _libhpi.HPI_SubSys_OptionInfo(_ss, id, byref(ge))
    return e, ge

def SubSys_OptionGet(id):
    'allocates entity internally, must follow with Entity_Free'
    ge = entity()
    _libhpi.HPI_SubSys_OptionGet.restype = err_t
    e = _libhpi.HPI_SubSys_OptionGet(_ss, id, byref(ge))
    return e, ge

def SubSys_OptionSet(id, ent):
    _libhpi.HPI_SubSys_OptionSet.restype = err_t
    e = _libhpi.HPI_SubSys_OptionSet(_ss, id, ent)
    return e

# ADAPTER FUNCTIONS
def Adapter_Open(index):
    global _current_adapter_setup
    if _current_adapter_setup is None:
        setup(index)
    _libhpi.HPI_AdapterOpen.restype = err_t
    return _libhpi.HPI_AdapterOpen(_ss, index)

def Adapter_Close(index):
    _libhpi.HPI_AdapterClose.restype = err_t
    return _libhpi.HPI_AdapterClose(_ss, index)

def Adapter_GetInfo(ai):
    pwNumOutStreams = c_uint16()
    pwNumInStreams = c_uint16()
    pwVersion = c_uint16()
    dwSerialNumber = c_uint32()
    pwAdapterType = c_uint16()
    _libhpi.HPI_AdapterGetInfo.restype = err_t
    e = _libhpi.HPI_AdapterGetInfo(_ss, ai,
        byref(pwNumOutStreams), byref(pwNumInStreams),
        byref(pwVersion), byref(dwSerialNumber), byref(pwAdapterType))
    return (e, pwNumOutStreams.value, pwNumInStreams.value,
            pwVersion.value, dwSerialNumber.value, pwAdapterType.value)

def Adapter_GetModuleByIndex(ai, mi):
    pwNumOut = c_uint16()
    pwNumIn = c_uint16()
    pwVersion = c_uint16()
    dwSerialNumber = c_uint32()
    pwType = c_uint16()
    mh = handle_t()
    _libhpi.HPI_AdapterGetModuleByIndex.restype = err_t
    e = _libhpi.HPI_AdapterGetModuleByIndex(_ss, ai, mi,
        byref(pwNumOut), byref(pwNumIn), byref(pwVersion),
        byref(dwSerialNumber), byref(pwType), byref(mh))
    return (e, pwNumOut.value, pwNumIn.value,
            pwVersion.value, dwSerialNumber.value, pwType.value,
            mh.value)

def Adapter_GetMode(index):
    mode = c_uint32()
    _libhpi.HPI_AdapterGetMode.restype = err_t
    e = _libhpi.HPI_AdapterGetMode(_ss, index, byref(mode))
    return e, mode.value

def Adapter_SetModeEx(index, mode, queryorset):
    _libhpi.HPI_AdapterSetModeEx.restype = err_t
    return _libhpi.HPI_AdapterSetModeEx(_ss, index, mode, queryorset)

def Adapter_SetProperty(index, prop, p1, p2):
    _libhpi.HPI_AdapterSetProperty.restype = err_t
    return _libhpi.HPI_AdapterSetProperty(_ss, index, prop, p1, p2)

def Adapter_GetProperty(index, prop):
    p1 = c_uint16()
    p2 = c_uint16()
    _libhpi.HPI_AdapterGetProperty.restype = err_t
    e = _libhpi.HPI_AdapterGetProperty(_ss, index, prop, byref(p1), byref(p2))
    return e, p1.value, p2.value

def Adapter_EnumerateProperty(index, i, what, prop):
    r = c_uint32()
    _libhpi.HPI_AdapterEnumerateProperty.restype = err_t
    e = _libhpi.HPI_AdapterEnumerateProperty(_ss, index, i, what, prop, byref(r))
    return e, r.value

def Adapter_DebugRead(index, addr, nbytes):
    bytecount = c_int(nbytes)
    bytes = create_string_buffer(nbytes)
    _libhpi.HPI_AdapterDebugRead.restype = err_t
    e = _libhpi.HPI_AdapterDebugRead(_ss, index, addr, bytes, byref(bytecount))
    if bytecount.value < nbytes:
        nbytes = bytecount.value
    return e, bytes.raw[0:nbytes]

def Adapter_GetAssert2(index):
    count = c_uint16()
    proc_id = c_uint16()
    p1 = c_uint32()
    p2 = c_uint32()
    dsp_addr = c_uint32()
    s = create_string_buffer(17)
    _libhpi.HPI_AdapterGetAssert2.restype = err_t
    e = _libhpi.HPI_AdapterGetAssert2(_ss, index, byref(count), s,
                byref(p1), byref(p2), byref(dsp_addr), byref(proc_id))
    return e, count.value, s.value, p1.value, p2.value, dsp_addr.value, proc_id.value

def Adapter_GetAssertEx(index):
    count = c_uint16()
    proc_id = c_uint16()
    p1 = c_uint32()
    s = create_string_buffer(17)
    _libhpi.HPI_AdapterGetAssertEx.restype = err_t
    e = _libhpi.HPI_AdapterGetAssertEx(_ss, index, byref(count), s,
                byref(p1), byref(proc_id))
    return e, count.value, s.value, p1.value, proc_id.value

def Adapter_TestAssert(index, id):
    _libhpi.HPI_AdapterTestAssert.restype = err_t
    e = _libhpi.HPI_AdapterTestAssert(_ss, index, id)
    return e

def Adapter_Restart(index):
    _libhpi.HPI_AdapterRestart.restype = err_t
    e = _libhpi.HPI_AdapterRestart(index)
    return e

# NVMEMORY FUNCTIONS
def NvMemory_Open(ai):
    h = handle_t()
    n = c_uint16()
    _libhpi.HPI_NvMemoryOpen.restype = err_t
    e = _libhpi.HPI_NvMemoryOpen(_ss, ai, byref(h), byref(n))
    return e, h.value, n.value

def NvMemory_ReadByte(h, i):
    d = c_uint16()
    i = c_uint16(i)
    _libhpi.HPI_NvMemoryReadByte.restype = err_t
    e = _libhpi.HPI_NvMemoryReadByte(_ss, h, i, byref(d))
    return e, d.value

def NvMemory_WriteByte(h, i, d):
    i = c_uint16(i)
    d = c_uint16(d)
    _libhpi.HPI_NvMemoryWriteByte.restype = err_t
    e = _libhpi.HPI_NvMemoryWriteByte(_ss, h, i, d)
    return e

# OUTSTREAM FUNCTIONS
def OutStream_AncillaryGetInfo(hs):
    _libhpi.HPI_OutStreamAncillaryGetInfo.restype = err_t
    fa = c_uint32()
    e = _libhpi.HPI_OutStreamAncillaryGetInfo(_ss, hs, byref(fa))
    return e, fa.value

def OutStream_AncillaryRead(hs, num_frames):
    _libhpi.HPI_OutStreamAncillaryRead.restype = err_t
    bufsize = 256
    bp = create_string_buffer(bufsize)
    e = _libhpi.HPI_OutStreamAncillaryRead(_ss, hs, bp, bufsize, num_frames)
    return e, bp.raw

def OutStream_AncillaryReset(hs, m):
    _libhpi.HPI_OutStreamAncillaryReset.restype = err_t
    _libhpi.HPI_OutStreamAncillaryReset(_ss, hs, m)

def OutStream_Close(hs):
    _libhpi.HPI_OutStreamClose.restype = err_t
    return _libhpi.HPI_OutStreamClose(_ss, hs)

def OutStream_GetInfoEx(hs):
    state = c_uint16()
    bufsize = c_uint32()
    dtp  = c_uint32()
    sp = c_uint32()
    adtp  = c_uint32()
    _libhpi.HPI_OutStreamGetInfoEx.restype = err_t
    e = _libhpi.HPI_OutStreamGetInfoEx(_ss, hs, byref(state), byref(bufsize),
            byref(dtp), byref(sp), byref(adtp))
    return e, state.value, bufsize.value, dtp.value, sp.value, adtp.value

def OutStream_GroupAdd(hos, hs):
    _libhpi.HPI_OutStreamGroupAdd.restype = err_t
    return _libhpi.HPI_OutStreamGroupAdd(_ss, hos, hs)

def OutStream_GroupGetMap(h):
    osm = c_uint32()
    ism = c_uint32()
    _libhpi.HPI_OutStreamGroupGetMap.restype = err_t
    e = _libhpi.HPI_OutStreamGroupGetMap(_ss, h, byref(osm), byref(ism))
    return e, osm.value, ism.value

def OutStream_GroupReset(h):
    _libhpi.HPI_OutStreamGroupReset.restype = err_t
    return _libhpi.HPI_OutStreamGroupReset(_ss, h)


def OutStream_HostBufferAllocate(hs, bs):
    _libhpi.HPI_OutStreamHostBufferAllocate.restype = err_t
    return _libhpi.HPI_OutStreamHostBufferAllocate(_ss, hs, bs)


def OutStream_HostBufferFree(hs, bs):
    _libhpi.HPI_OutStreamHostBufferFree.restype = err_t
    return _libhpi.HPI_OutStreamHostBufferFree(_ss, hs, bs)

def OutStream_Open(ai, i):
    hs = handle_t()
    _libhpi.HPI_OutStreamOpen.restype = err_t
    e = _libhpi.HPI_OutStreamOpen(_ss, ai, i, byref(hs))
    return e, hs.value

def OutStream_QueryFormat(h, fmt):
    _libhpi.HPI_OutStreamQueryFormat.restype = err_t
    return _libhpi.HPI_OutStreamQueryFormat(_ss, h, byref(fmt))

def OutStream_Reset(hs):
    _libhpi.HPI_OutStreamReset.restype = err_t
    return _libhpi.HPI_OutStreamReset(_ss, hs)

def OutStream_SetFormat(hs, fmt):
    _libhpi.HPI_OutStreamSetFormat.restype = err_t
    return _libhpi.HPI_OutStreamSetFormat(_ss, hs, byref(fmt))

def OutStream_SetTimeScale(hs, ts):
    return HPI_OutStreamSetTimeScale(_ss, hs, ts)

def OutStream_SetVelocity(hw, v):
    _libhpi.HPI_OutStreamSetVelocity.restype = err_t
    return _libhpi.HPI_OutStreamSetVelocity(_ss, hs, v)

def OutStream_Start(hs):
    _libhpi.HPI_OutStreamStart.restype = err_t
    return _libhpi.HPI_OutStreamStart(_ss, hs)

def OutStream_Stop(hs):
    _libhpi.HPI_OutStreamStop.restype = err_t
    return _libhpi.HPI_OutStreamStop(_ss, hs)

def OutStream_Wait(hs, v):
    _libhpi.HPI_OutStreamWait.restype = err_t
    return _libhpi.HPI_OutStreamWait(_ss, hs, v)

def OutStream_WaitStart(hs):
    _libhpi.HPI_OutStreamWaitStart.restype = err_t
    return  _libhpi.HPI_OutStreamWaitStart(_ss, hs)

def OutStream_WriteBuf(hs, b, format):
    bp = c_char_p(b)
    _libhpi.HPI_OutStreamWriteBuf.restype = err_t
    return _libhpi.HPI_OutStreamWriteBuf(_ss, hs, bp, len(b), byref(format))


# INSTREAM FUNCTIONS
def InStream_AncillaryGetInfo(hs):
    _libhpi.HPI_InStreamAncillaryGetInfo.restype = err_t
    fs = c_uint32()
    e = _libhpi.HPI_InStreamAncillaryGetInfo(_ss, hs, byref(fs))
    return e, fa.value

def InStream_AncillaryReset(hs, m, a, i):
    _libhpi.HPI_InStreamAncillaryReset.restype = err_t
    return _libhpi.HPI_InStreamAncillaryReset(_ss, hs, m, a, i)

def InStream_AncillaryWrite(hs, data, nbytes, nframes):
    _libhpi.HPI_InStreamAncillaryWrite.restype = err_t
    buf =  create_string_buffer(nbytes)
    e = _libhpi.HPI_InStreamAncillaryWrite(_ss, hs, buf, bytes, nframes)

def InStream_Close(hs):
    _libhpi.HPI_InStreamClose.restype = err_t
    return _libhpi.HPI_InStreamClose(_ss, hs)

def InStream_GetInfoEx(hs):
    state = c_uint16()
    bufsize = c_uint32()
    dtp  = c_uint32()
    sp = c_uint32()
    adtp  = c_uint32()
    _libhpi.HPI_InStreamGetInfoEx.restype = err_t
    e = _libhpi.HPI_InStreamGetInfoEx(_ss, hs, byref(state),
            byref(bufsize), byref(dtp), byref(sp), byref(adtp))
    return e, state.value, bufsize.value, dtp.value, sp.value, adtp.value

def InStream_GroupAdd(hos, hs):
    _libhpi.HPI_InStreamGroupAdd.restype = err_t
    return _libhpi.HPI_InStreamGroupAdd(_ss, hos, hs)

def InStream_GroupGetMap(h):
    osm = c_uint32()
    ism = c_uint32()
    _libhpi.HPI_InStreamGroupGetMap.restype = err_t
    e = _libhpi.HPI_InStreamGroupGetMap(_ss, h, byref(osm), byref(ism))
    return e, osm.value, ism.value

def InStream_GroupReset(h):
    _libhpi.HPI_InStreamGroupReset.restype = err_t
    return _libhpi.HPI_InStreamGroupReset(_ss, h)

def InStream_HostBufferAllocate(hs, bs):
    _libhpi.HPI_InStreamHostBufferAllocate.restype = err_t
    return _libhpi.HPI_InStreamHostBufferAllocate(_ss, hs, bs)

def InStream_HostBufferFree(hs, bs):
    _libhpi.HPI_InStreamHostBufferFree.restype = err_t
    return _libhpi.HPI_InStreamHostBufferFree(_ss, hs)

def InStream_Open(ai, i):
    hs = handle_t()
    _libhpi.HPI_InStreamOpen.restype = err_t
    e = _libhpi.HPI_InStreamOpen(_ss, ai, i, byref(hs))
    return e, hs.value

def InStream_QueryFormat(h, fmt):
    _libhpi.HPI_InStreamQueryFormat.restype = err_t
    return _libhpi.HPI_InStreamQueryFormat(_ss, h, byref(fmt))

def InStream_ReadBuf(hs, nbytes):
    bp = create_string_buffer(nbytes)
    _libhpi.HPI_InStreamReadBuf.restype = err_t
    e = _libhpi.HPI_InStreamReadBuf(_ss, hs, bp, nbytes)
    return e, bp.raw

def InStream_Reset(hs):
    _libhpi.HPI_InStreamReset.restype = err_t
    return _libhpi.HPI_InStreamReset(_ss, hs)

def InStream_SetFormat(hs, fmt):
    _libhpi.HPI_InStreamSetFormat.restype = err_t
    return _libhpi.HPI_InStreamSetFormat(_ss, hs, byref(fmt))

def InStream_Start(hs):
    _libhpi.HPI_InStreamStart.restype = err_t
    e = _libhpi.HPI_InStreamStart(_ss, hs)
    return e

def InStream_Stop(hs):
    _libhpi.HPI_InStreamStop.restype = err_t
    return _libhpi.HPI_InStreamStop(_ss, hs)

def InStream_Wait(hs, v):
    _libhpi.HPI_InStreamWait.restype = err_t
    return _libhpi.HPI_InStreamWait(_ss, hs, v)

def InStream_WaitStart(hs):
    _libhpi.HPI_InStreamWaitStart.restype = err_t
    return  _libhpi.HPI_InStreamWaitStart(_ss, hs)

## FILESTORE
def FileStore_Open(ai, s):
    h = handle_t()
    security = create_string_buffer(s)
    _libhpi.HPI_FileStoreOpen.restype = err_t
    e = _libhpi.HPI_FileStoreOpen(ai, security, byref(h))
    return e, h.value

def FileStore_Dir(h, name):
    name = create_string_buffer(name)
    plist = c_char_p()
    _libhpi.HPI_FileStoreAllocDir.restype = err_t
    e = _libhpi.HPI_FileStoreAllocDir(h, byref(name), byref(plist))
    listing = ''
    if not e:
        listing = plist.value # this had better be null terminated!
    Entity_Free(plist)
    return e, listing

def FileStore_Delete(h, s):
    name = create_string_buffer(s)
    _libhpi.HPI_FileStoreDelete.restype = err_t
    return _libhpi.HPI_FileStoreDelete(h, byref(name))


def FileStore_Get(h, s1, s2):
    name = create_string_buffer(s1)
    local_path = create_string_buffer(s2)
    _libhpi.HPI_FileStoreGet.restype = err_t
    return _libhpi.HPI_FileStoreGet(h, byref(name), byref(local_path))

def FileStore_Put(h, s1, s2):
    name = create_string_buffer(s1)
    local_path = create_string_buffer(s2)
    _libhpi.HPI_FileStorePut.restype = err_t
    return _libhpi.HPI_FileStorePut(h, byref(name), byref(local_path))


# MIXER FUNCTIONS
def Mixer_Open(index):
    hm = handle_t()
    _libhpi.HPI_MixerOpen.restype = err_t
    e = _libhpi.HPI_MixerOpen(_ss, index, byref(hm))
    return e, hm.value

def Mixer_Close(hm):
    _libhpi.HPI_MixerClose.restype = err_t
    return _libhpi.HPI_MixerClose(_ss, hm)

def Mixer_GetControl(hm, snt, sni, dnt, dni, ct):
    hctrl = handle_t()
    _libhpi.HPI_MixerGetControl.restype = err_t
    e = _libhpi.HPI_MixerGetControl(_ss, hm, snt, sni, dnt, dni, ct, byref(hctrl))
    return e, hctrl.value

def Mixer_GetControlByIndex(hm, i):
    srctype = c_uint16()
    dsttype = c_uint16()
    srcindex = c_uint16()
    dstindex = c_uint16()
    ctrltype = c_uint16()
    hctrl = handle_t()
    _libhpi.HPI_MixerGetControlByIndex.restype = err_t
    e = _libhpi.HPI_MixerGetControlByIndex(_ss, hm, i,
            byref(srctype), byref(srcindex), byref(dsttype), byref(dstindex),
            byref(ctrltype), byref(hctrl))
    return (e, srctype.value, srcindex.value, dsttype.value, dstindex.value,
            ctrltype.value, hctrl.value)

def Mixer_Store(hm, cmd, index=0):
    _libhpi.HPI_MixerStore.restype = err_t
    return _libhpi.HPI_MixerStore(_ss, hm, cmd, index)


# CONTROLS
## helpers
def _geta2_int16(h, f):
    p = int16_array2_t()
    f.restype = err_t
    e = f(_ss, h, byref(p))
    return e, (p[0], p[1])

def _query_range(h, f):
    min = c_int16()
    max = c_int16()
    step = c_int16()
    f.restype = err_t
    e = f(_ss, h, byref(min), byref(max), byref(step))
    return e, min.value, max.value, step.value

def _query_channels(h, f):
    c = c_uint32()
    f.restype = err_t
    e = f(_ss, h, byref(c))
    return e, c.value

def _get1_uint16(h, f):
    r1 = c_uint16()
    f.restype = err_t
    e = f(_ss, h, byref(r1))
    return e, r1.value

def _query_1_uint16(h, i, f):
    r1 = c_uint16()
    f.restype = err_t
    e = f(_ss, h, i, byref(r1))
    return e, r1.value

def _get2_uint16(h, f):
    r1 = c_uint16()
    r2 = c_uint16()
    f.restype = err_t
    e = f(_ss, h, byref(r1), byref(r2))
    return e, r1.value, r2.value

def _get1_uint32(h, f):
    r1 = c_uint32()
    f.restype = err_t
    e = f(_ss, h, byref(r1))
    return e, r1.value

def _get2_uint32(h, f):
    r1 = c_uint32()
    r2 = c_uint32()
    f.restype = err_t
    e = f(_ss, h, byref(r1), byref(r2))
    return e, r1.value, r2.value

def _query_1_uint32(h, i, f):
    r1 = c_uint32()
    f.restype = err_t
    e = f(_ss, h, i, byref(r1))
    return e, r1.value

def _get1_short(h, f):
    r1 = c_int16()
    f.restype = err_t
    e = f(_ss, h, byref(r1))
    return e, r1.value

def _getstring256(h, f):
    s = create_string_buffer(256)
    f.restype = err_t
    e = f(_ss, h, byref(s), 256)
    return e, s.value


def Control_WaitReady(func, *args):
    """Call func with *args every 50ms until it doesn't return hpi.ERROR_CONTROL_NOT_READY
       or 500ms has elapsed.
       Should be used to wrap functions that use deferred processing.

       raises hpi.HpiError
    """
    retry = 20
    for i in range(15):
        #if i:
        #    print('wait', func.__name__, args)
        res = always_tuple(func(*args))
        e = res[0]
        if e == ERROR_CONTROL_NOT_READY:
            time.sleep(retry / 1000.0)
            retry += 20
            continue
        break
    if not e:
        if len(res) == 1:
            return
        elif len(res) == 2:
            return res[1]
        else:
            return res[1:]
    raise HpiError(e)

def Control_Query(h, attrib, index, param=0):
    r = c_uint32()
    _libhpi.HPI_ControlQuery.restype = err_t
    e = _libhpi.HPI_ControlQuery(_ss, h, attrib, index, param, byref(r))
    return e, r.value


def Control_GetData(h, attrib, index=0, max_len=300):
    """Generic low-level data read, attrib is control attribute, normally private to
       hpi_internal.h
    """
    _libhpi.HPI_Control_GetData.restype = err_t
    data_len = c_uint32()
    buf = create_string_buffer(max_len)
    e = _libhpi.HPI_Control_GetData(h, attrib, buf, max_len, index, byref(data_len))
    if e:
        return e, data_len.value  # return required minimum buffer size

    return e, buf[:data_len.value]


## AESEBU_Receiver  (incomplete)
def AESEBU_Receiver_GetErrorStatus(h):
    return _get1_uint16(h, _libhpi.HPI_AESEBU_Receiver_GetErrorStatus)

def AESEBU_Receiver_GetSampleRate(h):
    return _get1_uint32(h, _libhpi.HPI_AESEBU_Receiver_GetSampleRate)

def AESEBU_Receiver_GetFormat(h):
    return _get1_uint16(h, _libhpi.HPI_AESEBU_Receiver_GetFormat)

## AESEBU_Transmitter (incomplete)
def AESEBU_Transmitter_GetFormat(h):
    return _get1_uint16(h, _libhpi.HPI_AESEBU_Transmitter_GetFormat)

## CHANNELMODE
def ChannelMode_QueryMode(h, i):
    return _query_1_uint16(h, i, _libhpi.HPI_ChannelMode_QueryMode)

def ChannelMode_Set(h, m):
    _libhpi.HPI_ChannelModeSet.restype = err_t
    return _libhpi.HPI_ChannelModeSet(_ss, h, m)

def ChannelMode_Get(h):
    return _get1_uint16(h, _libhpi.HPI_ChannelModeGet)

## COBRANET CONTROL
def reverse_endian32(s):
    '''Reverse order of bytes in each 32 bit quadlet in (raw) string s
    Cobranet HMI native read is opposite from PC order
    '''
    s = list(s)
    x = len(s) % 4
    if x: # pad to multiple of 4
        x = 4 -x
        s.extend(['\0'] * x)

    r = list(s)
    r[0::4] = s[3::4]
    r[1::4] = s[2::4]
    r[2::4] = s[1::4]
    r[3::4] = s[0::4]

    return ''.join(r)

def cobranet_hmi_to_string(s):
    '''Convert cobranet hmi string with length prefix into
    ordinary string'''
    len = ord(s[3]) # string length in first 4 bytes, big-endian
    return s[4:len+4]  # truncate to valid length

def cobranet_string_to_hmi(s):
    '''convert string into cobranet hmi string with length prefix'''
    l = len(s)
    if (l > 255):
        raise ValueError
    sl = '\0\0\0' + chr(l)
    return sl + s

def Cobranet_HmiWrite(h, hmi_address, data):
    '''data should be a raw string i.e. byte array'''
    data = reverse_endian32(data)
    d = create_string_buffer(data)
    bytes = len(data)
    _libhpi.HPI_Cobranet_HmiWrite.restype = err_t
    return _libhpi.HPI_Cobranet_HmiWrite(_ss, h, hmi_address, bytes, byref(d))

def Cobranet_HmiRead(h, hmi_address, max_bytes=256):
    d = create_string_buffer(max_bytes)
    byte_count = c_uint32()
    _libhpi.HPI_Cobranet_HmiRead.restype = err_t
    e = _libhpi.HPI_Cobranet_HmiRead(_ss, h, hmi_address, max_bytes, byref(byte_count), byref(d))
    data = reverse_endian32(d.raw)
    return e, data[0:byte_count.value]

def Cobranet_HmiGetStatus(h):
    status = c_uint32()
    readable = c_uint32()
    writeable = c_uint32()
    _libhpi.HPI_Cobranet_HmiGetStatus.restype = err_t
    e = _libhpi.HPI_Cobranet_HmiGetStatus(_ss, h, byref(status), byref(readable), byref(writeable))
    return e, status.value, readable.value, writeable.value

## COMPANDER CONTROL

def Compander_SetEnable(h, enable):
    _libhpi.HPI_Compander_SetEnable.restype = err_t
    return _libhpi.HPI_Compander_SetEnable(_ss, h, enable)

def Compander_GetEnable(h):
    return _get1_uint32(h, _libhpi.HPI_Compander_GetEnable)

def Compander_SetMakeupGain(h, g):
    _libhpi.HPI_Compander_SetMakeupGain.restype = err_t
    return _libhpi.HPI_Compander_SetMakeupGain(_ss, h, g)

def Compander_GetMakeupGain(h):
    return _get1_short(h, _libhpi.HPI_Compander_GetMakeupGain)

def Compander_SetAttackTimeConstant(h, i, attack):
    _libhpi.HPI_Compander_SetAttackTimeConstant.restype = err_t
    return _libhpi.HPI_Compander_SetAttackTimeConstant(_ss, h, attack)

def Compander_GetAttackTimeConstant(h, i):
    _libhpi.HPI_Compander_GetAttackTimeConstant.restype = err_t
    r = c_uint32()
    err = _libhpi.HPI_Compander_GetAttackTimeConstant(_ss, h, i, byref(r))
    return err, r.value

def Compander_SetDecayTimeConstant(h, i, attack):
    _libhpi.HPI_Compander_SetDecayTimeConstant.restype = err_t
    return _libhpi.HPI_Compander_SetDecayTimeConstant(_ss, h, attack)

def Compander_GetDecayTimeConstant(h, i):
    _libhpi.HPI_Compander_GetDecayTimeConstant.restype = err_t
    r = c_uint32()
    err = _libhpi.HPI_Compander_GetDecayTimeConstant(_ss, h, i, byref(r))
    return err, r.value

def Compander_SetThreshold(h, i, t):
    _libhpi.HPI_Compander_SetThreshold.restype = err_t
    return _libhpi.HPI_Compander_SetThreshold(_ss, h, i, t)

def Compander_GetThreshold(h, i):
    _libhpi.HPI_Compander_GetThreshold.restype = err_t
    t = c_short()
    err = _libhpi.HPI_Compander_GetThreshold(_ss, h, i, byref(t))
    return err, t.value

def Compander_SetRatio(h, i, r):
    _libhpi.HPI_Compander_SetRatio.restype = err_t
    return _libhpi.HPI_Compander_SetRatio(_ss, h, i, r)

def Compander_GetRatio(h, i):
    _libhpi.HPI_Compander_GetRatio.restype = err_t
    r = c_uint32()
    err = _libhpi.HPI_Compander_GetRatio(_ss, h, i, byref(r))
    return err, r.value

## LEVEL
def Level_GetGain(h):
    return _geta2_int16(h, _libhpi.HPI_LevelGetGain)

def Level_SetGain(h, v):
    p = int16_array2_t(*v)
    _libhpi.HPI_LevelSetGain.restype = err_t
    e = _libhpi.HPI_LevelSetGain(_ss, h, p)
    return e

def Level_QueryRange(h):
    return _query_range(h, _libhpi.HPI_LevelQueryRange)

LevelGetGain = Level_GetGain
LevelSetGain = Level_SetGain
LevelQueryRange = Level_QueryRange

## METER
def Meter_GetPeak(h):
    return _geta2_int16(h, _libhpi.HPI_MeterGetPeak)

def Meter_GetRms(h):
    return _geta2_int16(h, _libhpi.HPI_MeterGetRms)

def Meter_QueryChannels(h):
    return _query_channels(h, _libhpi.HPI_Meter_QueryChannels)

def Meter_SetPeakBallistics(h, a, d):
    _libhpi.HPI_MeterSetPeakBallistics.restype = err_t
    return _libhpi.HPI_MeterSetPeakBallistics(_ss, h, a, d)

def Meter_SetRmsBallistics(h, a, d):
    _libhpi.HPI_MeterSetRmsBallistics.restype = err_t
    return _libhpi.HPI_MeterSetRmsBallistics(_ss, h, a, d)

def Meter_GetPeakBallistics(h):
    return _get2_uint16(h, _libhpi.HPI_MeterGetPeakBallistics)

def Meter_GetRmsBallistics(h):
    return _get2_uint16(h, _libhpi.HPI_MeterGetRmsBallistics)

## MULTIPLEXER
def Multiplexer_SetSource(h, node, index):
    _libhpi.HPI_Multiplexer_SetSource.restype = err_t
    return _libhpi.HPI_Multiplexer_SetSource(_ss, h, node, index)

def Multiplexer_GetSource(h):
    return _get2_uint16(h, _libhpi.HPI_Multiplexer_GetSource)

def Multiplexer_QuerySource(h, i):
    node = c_uint16()
    index = c_uint16()
    _libhpi.HPI_Multiplexer_QuerySource.restype = err_t
    e = _libhpi.HPI_Multiplexer_QuerySource(_ss, h, i, byref(node), byref(index))
    return e, node.value, index.value

## MICROPHONE CONTROL
def Microphone_SetPhantomPower(h, p):
    _libhpi.HPI_Microphone_SetPhantomPower.restype = err_t
    return _libhpi.HPI_Microphone_SetPhantomPower(_ss, h, p)

def Microphone_GetPhantomPower(h):
    return _get1_uint16(h, _libhpi.HPI_Microphone_GetPhantomPower)

## PAD CONTROL
def PAD_GetChannelName(h):
    return _getstring256(h, _libhpi.HPI_PAD_GetChannelName)

def PAD_GetArtist(h):
    return _getstring256(h, _libhpi.HPI_PAD_GetArtist)

def PAD_GetTitle(h):
    return _getstring256(h, _libhpi.HPI_PAD_GetTitle)

def PAD_GetComment(h):
    return _getstring256(h, _libhpi.HPI_PAD_GetComment)

def PAD_GetProgramType(h):
    return _get1_uint32(h, _libhpi.HPI_PAD_GetProgramType)

def PAD_GetRdsPI(h):
    return _get1_uint32(h, _libhpi.HPI_PAD_GetRdsPI)

def PAD_GetProgramTypeString(h, datatype, pty):
    s = create_string_buffer(256)
    _libhpi.HPI_PAD_GetProgramTypeString.restype = err_t
    e = _libhpi.HPI_PAD_GetProgramTypeString(_ss, h, datatype, pty, byref(s), 256)
    return e, s.value

## ParametricEQ

## SAMPLECLOCK
def SampleClock_SetLocalRate(h, rate):
    _libhpi.HPI_SampleClock_SetLocalRate.restype = err_t
    return _libhpi.HPI_SampleClock_SetLocalRate(_ss, h, rate)

def SampleClock_SetLocalRateEx(h, rateHz, ratePPB):
    _libhpi.HPI_SampleClock_SetLocalRateEx.restype = err_t
    return _libhpi.HPI_SampleClock_SetLocalRateEx(_ss, h, rateHz, ratePPB)

def SampleClock_SetSource(h, source):
    _libhpi.HPI_SampleClock_SetSource.restype = err_t
    return _libhpi.HPI_SampleClock_SetSource(_ss, h, source)

def SampleClock_QuerySource(h, i):
    return _query_1_uint16(h, i, _libhpi.HPI_SampleClock_QuerySource)

def SampleClock_GetSource(h):
    return _get1_uint16(h, _libhpi.HPI_SampleClock_GetSource)

def SampleClock_QuerySourceIndex(h, i, s):
    r = c_uint16()
    _libhpi.HPI_SampleClock_QuerySourceIndex.restype = err_t
    e = _libhpi.HPI_SampleClock_QuerySourceIndex(_ss, h, i, s, byref(r))
    return e, r.value

def SampleClock_SetSourceIndex(h, v):
    _libhpi.HPI_SampleClock_SetSourceIndex.restype = err_t
    return _libhpi.HPI_SampleClock_SetSourceIndex(_ss, h, v)

def SampleClock_GetSourceIndex(h):
    return _get1_uint16(h, _libhpi.HPI_SampleClock_GetSourceIndex)

def SampleClock_GetSampleRate(h):
    return _get1_uint32(h, _libhpi.HPI_SampleClock_GetSampleRate)

def SampleClock_QueryLocalRate(h, i):
    return _query_1_uint32(h, i, _libhpi.HPI_SampleClock_QueryLocalRate)

def SampleClock_GetLocalRate(h):
    return _get1_uint32(h, _libhpi.HPI_SampleClock_GetLocalRate)

def SampleClock_SetAuto(h, v):
    _libhpi.HPI_SampleClock_SetAuto.restype = err_t
    return _libhpi.HPI_SampleClock_SetAuto(_ss, h, v)

def SampleClock_GetAuto(h):
    return _get1_uint32(h, _libhpi.HPI_SampleClock_GetAuto)

def SampleClock_SetLocalRateLock(_ss, h, v):
    _libhpi.HPI_SampleClock_SetLocalRateLock.restype = err_t
    return _libhpi.HPI_SampleClock_SetLocalRateLock(_ss, h, v)

def SampleClock_GetLocalRateLock(h):
    return _get1_uint32(h, _libhpi.HPI_SampleClock_GetLocalRateLock)

## SILENCEDETECTOR
#~ /*******************************
  #~ Silence Detector control
#~ *******************************/
def SilenceDetector_GetState(h):
    return _get1_uint32(h, _libhpi.HPI_SilenceDetector_GetState)

def SilenceDetector_SetEnable(h, v):
    _libhpi.HPI_SilenceDetector_SetEnable.restype = err_t
    return _libhpi.HPI_SilenceDetector_SetEnable(_ss, h, v)

def SilenceDetector_GetEnable(h):
    return _get1_uint32(h, _libhpi.HPI_SilenceDetector_GetEnable)

def SilenceDetector_SetEventEnable(h, v):
    _libhpi.HPI_SilenceDetector_SetEventEnable.restype = err_t
    return _libhpi.HPI_SilenceDetector_SetEventEnable(_ss, h, v)

def SilenceDetector_GetEventEnable(h):
    return _get1_uint32(h, _libhpi.HPI_SilenceDetector_GetEventEnable)

def SilenceDetector_SetDelay(h, v):
    _libhpi.HPI_SilenceDetector_SetDelay.restype = err_t
    return _libhpi.HPI_SilenceDetector_SetDelay(_ss, h, v)

def SilenceDetector_GetDelay(h):
    return _get1_uint32(h, _libhpi.HPI_SilenceDetector_GetDelay)

def SilenceDetector_SetThreshold(h, v):
    _libhpi.HPI_SilenceDetector_SetThreshold.restype = err_t
    return _libhpi.HPI_SilenceDetector_SetThreshold(_ss, h, v)

def SilenceDetector_GetThreshold(h):
    r1 = c_int32()
    _libhpi.HPI_SilenceDetector_GetThreshold.restype = err_t
    e = _libhpi.HPI_SilenceDetector_GetThreshold(_ss, h, byref(r1))
    return e, r1.value

## TONEDETECTOR
def ToneDetector_GetState(h):
    return _get1_uint32(h, _libhpi.HPI_ToneDetector_GetState)

def ToneDetector_SetEnable(h, v):
    _libhpi.HPI_ToneDetector_SetEnable.restype = err_t
    return _libhpi.HPI_ToneDetector_SetEnable(_ss, h, v)

def ToneDetector_GetEnable(h):
    return _get1_uint32(h, _libhpi.HPI_ToneDetector_GetEnable)

def ToneDetector_SetEventEnable(h, v):
    _libhpi.HPI_ToneDetector_SetEventEnable.restype = err_t
    return _libhpi.HPI_ToneDetector_SetEventEnable(_ss, h, v)

def ToneDetector_GetEventEnable(h):
    return _get1_uint32(h, _libhpi.HPI_ToneDetector_GetEventEnable)

def ToneDetector_SetDelay(h, v):
    _libhpi.HPI_ToneDetector_SetDelay.restype = err_t
    return _libhpi.HPI_ToneDetector_SetDelay(_ss, h, v)

def ToneDetector_GetDelay(h):
    return _get1_uint32(h, _libhpi.HPI_ToneDetector_GetDelay)

def ToneDetector_SetThreshold(h, v):
    _libhpi.HPI_ToneDetector_SetThreshold.restype = err_t
    return _libhpi.HPI_ToneDetector_SetThreshold(_ss, h, v)

def ToneDetector_GetThreshold(h):
    r1 = c_int32()
    _libhpi.HPI_ToneDetector_GetThreshold.restype = err_t
    e = _libhpi.HPI_ToneDetector_GetThreshold(_ss, h, byref(r1))
    return e, r1.value

def ToneDetector_GetFrequency(h, i):
    _libhpi.HPI_ToneDetector_GetFrequency.restype = err_t
    e = _libhpi.HPI_ToneDetector_GetFrequency(_ss, h, i, byref(r1))
    return e, r1.value

## TUNER
def Tuner_QueryBand(h, i):
    return _query_1_uint32(h, i, _libhpi.HPI_Tuner_QueryBand)

def Tuner_SetBand(h, v):
    _libhpi.HPI_Tuner_SetBand.restype = err_t
    return _libhpi.HPI_Tuner_SetBand(_ss, h, v)

def Tuner_GetBand(h):
    r = c_uint16()
    _libhpi.HPI_Tuner_GetBand.restype = err_t
    e = _libhpi.HPI_Tuner_GetBand(_ss, h, byref(r))
    return e, r.value

def Tuner_QueryFrequency(h, i, b):
    r = c_uint32()
    _libhpi.HPI_Tuner_QueryFrequency.restype = err_t
    e = _libhpi.HPI_Tuner_QueryFrequency(_ss, h, i, b, byref(r))
    return e, r.value

def Tuner_SetFrequency(h, v):
    _libhpi.HPI_Tuner_SetFrequency.restype = err_t
    return _libhpi.HPI_Tuner_SetFrequency(_ss, h, v)

def Tuner_GetFrequency(h):
    return _get1_uint32(h, _libhpi.HPI_Tuner_GetFrequency)

def Tuner_QueryDeemphasis(h, i, b):
    r = c_uint32()
    _libhpi.HPI_Tuner_QueryDeemphasis.restype = err_t
    e = _libhpi.HPI_Tuner_QueryDeemphasis(_ss, h, i, b, byref(r))
    return e, r.value

def Tuner_GetRFLevel(h):
    return _get1_short(h, _libhpi.HPI_Tuner_GetRFLevel)

def Tuner_GetRawRFLevel(h):
    return _get1_short(h, _libhpi.HPI_Tuner_GetRawRFLevel)

def Tuner_QueryGain(h, i):
    return _query_1_uint16(h, _libhpi.HPI_Tuner_QueryGain)

def Tuner_SetGain(h, g):
    _libhpi.HPI_Tuner_SetGain.restype = err_t
    return _libhpi.HPI_Tuner_SetGain(_ss, h, g)

def Tuner_GetGain(h):
    return _get1_short(h, _libhpi.HPI_Tuner_GetGain)

def Tuner_GetStatus(h):
    return _get2_uint16(h, _libhpi.HPI_Tuner_GetStatus)

def Tuner_SetMode(h, m, v):
    _libhpi.HPI_Tuner_SetMode.restype = err_t
    return _libhpi.HPI_Tuner_SetMode(_ss, h, m, v)

def Tuner_GetMode(h, mode):
    r1 = c_uint32()
    _libhpi.HPI_Tuner_GetMode.restype = err_t
    e = _libhpi.HPI_Tuner_GetMode(_ss, h, mode, byref(r1))
    return e, r1.value

def Tuner_GetRDS(h):
    d = create_string_buffer(12)
    _libhpi.HPI_Tuner_GetRDS.restype = err_t
    e = _libhpi.HPI_Tuner_GetRDS(_ss, h, d)
    return e, d.raw

def Tuner_SetDeemphasis(h, v):
    _libhpi.HPI_Tuner_SetDeemphasis.restype = err_t
    return _libhpi.HPI_Tuner_SetDeemphasis(_ss, h, v)

def Tuner_GetDeemphasis(h):
    return _get1_uint32(h, _libhpi.HPI_Tuner_GetDeemphasis)

def Tuner_QueryProgram(h):
    return _get1_uint32(h, _libhpi.HPI_Tuner_QueryProgram)

def Tuner_SetProgram(h, p):
    _libhpi.HPI_Tuner_SetProgram.restype = err_t
    return _libhpi.HPI_Tuner_SetProgram(_ss, h, p)

def Tuner_GetProgram(h):
    return _get1_uint32(h, _libhpi.HPI_Tuner_GetProgram)

def Tuner_GetHdRadioDspVersion(h):
    s = create_string_buffer(256)
    _libhpi.HPI_Tuner_GetHdRadioDspVersion.restype = err_t
    e = _libhpi.HPI_Tuner_GetHdRadioDspVersion(_ss, h, s, 256)
    return e, s.value

def Tuner_GetFirmwareVersion(h):
    s = create_string_buffer(256)
    _libhpi.HPI_Tuner_GetHdRadioSdkVersion.restype = err_t
    e = _libhpi.HPI_Tuner_GetFirmwareVersion(_ss, h, s, 256)
    return e, s.value

Tuner_GetHdRadioSdkVersion = Tuner_GetFirmwareVersion


def Tuner_GetHdRadioSignalQuality(h):
    return _get1_uint32(h, _libhpi.HPI_Tuner_GetHdRadioSignalQuality)

def Tuner_GetHdRadioSignalBlend(h):
	return _get1_uint32(h, _libhpi.HPI_Tuner_GetHdRadioSignalBlend)

def Tuner_SetHdRadioSignalBlend(h, b):
    _libhpi.HPI_Tuner_SetHdRadioSignalBlend.restype = err_t
    return _libhpi.HPI_Tuner_SetHdRadioSignalBlend(_ss, h, b)

def Tuner_GetDabAudioServiceCount(h):
	return _get2_uint32(h, _libhpi.HPI_Tuner_GetDabAudioServiceCount)

def Tuner_SetDabAudioService(h, s):
    _libhpi.HPI_Tuner_SetDabAudioService.restype = err_t
    return _libhpi.HPI_Tuner_SetDabAudioService(_ss, h, s)

def Tuner_GetDabAudioServiceName(h, i):
    s = create_string_buffer(256)
    _libhpi.HPI_Tuner_GetDabAudioServiceName.restype = err_t
    e = _libhpi.HPI_Tuner_GetDabAudioServiceName(_ss, h, s, 256, i)
    return e, s.value

def Tuner_GetDabMultiplexName(h):
    s = create_string_buffer(256)
    _libhpi.HPI_Tuner_GetDabMultiplexName.restype = err_t
    e = _libhpi.HPI_Tuner_GetDabMultiplexName(_ss, h, s, 256)
    return e, s.value

def Tuner_GetDabAudioInfo(h):
    s = create_string_buffer(256)
    _libhpi.HPI_Tuner_GetDabAudioInfo.restype = err_t
    e = _libhpi.HPI_Tuner_GetDabAudioInfo(_ss, h, s, 256)
    return e, s.value

def Tuner_GetDabServiceInfo(h, index=0):
    """Get full service info data
    index can range from 0 to Tuner_GetDabAudioServiceCount() - 1
    """
    _libhpi.HPI_Tuner_GetDabServiceInfo.restype = err_t
    buf = create_string_buffer(84)  # sizeof struct hpi_dab_service_info = 84
    e = _libhpi.HPI_Tuner_GetDabServiceInfo(h, index, buf)

    return e, buf[:]


def Tuner_GetDabComponentInfo(h, serv_idx=0, comp_idx=0):
    """Get DAB component info.
    Uses HPI deferred processing, i.e. may return hpi.ERROR_CONTROL_NOT_READY
    Wrap with Control_WaitReady()
    """
    _libhpi.HPI_Tuner_GetDabComponentInfo.restype = err_t
    buf = create_string_buffer(278)  # sizeof struct hpi_dab_component_info = 278
    e = _libhpi.HPI_Tuner_GetDabComponentInfo(h, serv_idx, comp_idx, buf)

    return e, buf[:]


def Tuner_GetDabDataPacket(h, max_len=8192):
    _libhpi.HPI_Tuner_GetDabDataPacket.restype = err_t
    data_len = c_uint32()
    next_poll_interval_ms = c_int()
    buf = create_string_buffer(max_len)
    e = _libhpi.HPI_Tuner_GetDabDataPacket(h, buf, max_len, byref(data_len), byref(next_poll_interval_ms))
    if e:
        return e, data_len.value, next_poll_interval_ms.value # return required minimum buffer size

    return e, buf[:data_len.value], next_poll_interval_ms.value


def Tuner_SetDabService(h, service_index, component_index, start=True):
    """Start or stop a DAB data or audio service.
    Uses HPI deferred processing, i.e. may return hpi.ERROR_CONTROL_NOT_READY
    Wrap with Control_WaitReady()
    """
    if start:
        start = 1
    else:
        start = 0
    _libhpi.HPI_Tuner_SetDabService.restype = err_t
    return _libhpi.HPI_Tuner_SetDabService(h, service_index, component_index, start)


def Tuner_GetDabService(h):
    """Get current DAB audio service.
    """
    service_index = c_uint32()
    component_index = c_uint16()
    _libhpi.HPI_Tuner_GetDabService.restype = err_t
    e = _libhpi.HPI_Tuner_GetDabService(h, byref(service_index), byref(component_index))
    return e, service_index.value, component_index.value


## VOLUME
def Volume_GetGain(h):
    return _geta2_int16(h, _libhpi.HPI_VolumeGetGain)

def Volume_SetGain(h, v):
    p = int16_array2_t(*v)
    _libhpi.HPI_VolumeSetGain.restype = err_t
    e = _libhpi.HPI_VolumeSetGain(_ss, h, p)
    return e

def Volume_GetMute(h):
    return _get1_uint32(h, _libhpi.HPI_VolumeGetMute)

def Volume_SetMute(h, m):
    _libhpi.HPI_VolumeSetMute.restype = err_t
    return _libhpi.HPI_VolumeSetMute(_ss, h, m)

def Volume_QueryRange(h):
    return _query_range(h, _libhpi.HPI_VolumeQueryRange)

def Volume_QueryChannels(h):
    return _query_channels(h, _libhpi.HPI_Volume_QueryChannels)

def Volume_AutoFadeProfile(h, stopgain, duration, profile):
    sg = int16_array2_t(*stopgain)
    _libhpi.HPI_VolumeAutoFadeProfile.restype = err_t
    e = _libhpi.HPI_VolumeAutoFadeProfile(_ss, h, byref(sg), duration, profile)
    return e

def Volume_QueryAutoFadeProfile(h, i):
    v = c_uint16()
    _libhpi.HPI_Volume_QueryAutoFadeProfile.restype = err_t
    e = _libhpi.HPI_Volume_QueryAutoFadeProfile(_ss, h, i, byref(v))
    return e, v.value

## VOX
def Vox_SetThreshold(h, t):
    _libhpi.HPI_VoxSetThreshold.restype = err_t
    return _libhpi.HPI_VoxSetThreshold(_ss, h, t)

def Vox_GetThreshold(h):
    return _get1_short(h, _libhpi.HPI_VoxGetThreshold)

VoxSetThreshold = Vox_SetThreshold
VoxGetThreshold = Vox_GetThreshold

## UNIVERSAL

def Universal_Info(h):
    'allocates entity internally, must follow with Entity_Free'
    ie = entity()
    _libhpi.HPI_Universal_Info.restype = err_t
    e = _libhpi.HPI_Universal_Info(_ss, h, byref(ie))
    return e, ie

def Universal_Get(h):
    'allocates entity internally, must follow with Entity_Free'
    ge = entity()
    _libhpi.HPI_Universal_Get.restype = err_t
    e = _libhpi.HPI_Universal_Get(_ss, h, byref(ge))
    return e, ge

def Universal_Set(h, se):
    _libhpi.HPI_Universal_Set.restype = err_t
    e = _libhpi.HPI_Universal_Set(_ss, h, se)
    return e


# GPIO
def Gpio_Open(ai):
    h = handle_t()
    ni = c_uint16()
    no = c_uint16()
    _libhpi.HPI_GpioOpen.restype = err_t
    e = _libhpi.HPI_GpioOpen(_ss, ai, byref(h), byref(ni), byref(no))
    return e, h.value, ni.value, no.value

def Gpio_ReadBit(h, bit):
    r = c_uint16()
    _libhpi.HPI_GpioReadBit.restype = err_t
    e = _libhpi.HPI_GpioReadBit(_ss, h, bit, byref(r))
    return e, r.value

allbitdata = c_uint16 * 4

def Gpio_ReadAllBits(h):
    r = allbitdata()
    _libhpi.HPI_GpioReadAllBits.restype = err_t
    e = _libhpi.HPI_GpioReadAllBits(_ss, h, byref(bt))
    return e, r[0] + (r[1] << 16) + (r[2] << 32) + (r[3] << 48)

def Gpio_WriteStatus(h):
    r = allbitdata()
    _libhpi.HPI_GpioWriteStatus.restype = err_t
    e = _libhpi.HPI_GpioWriteStatus(_ss, h, byref(bt))
    return e, r[0] + (r[1] << 16) + (r[2] << 32) + (r[3] << 48)


# PROFILE
def Profile_OpenAll(ai, pi):
    h = handle_t()
    mp = c_uint16()
    _libhpi.HPI_ProfileOpenAll.restype = err_t
    e = _libhpi.HPI_ProfileOpenAll(_ss, ai, pi, byref(h), byref(mp))
    return e, h.value, mp.value

def Profile_Get(h, i):
    sec = c_uint16()
    us = c_uint32()
    cc = c_uint32()
    maxus = c_uint32()
    minus = c_uint32()
    _libhpi.HPI_ProfileGet.restype = err_t
    e = _libhpi.HPI_ProfileGet(_ss, h, i, byref(sec), byref(us), byref(cc),
                              byref(maxus), byref(minus))
    return e, sec.value, us.value, cc.value, maxus.value, minus.value

def Profile_GetName(h, i):
    name = create_string_buffer(33)
    nl = c_uint16()
    _libhpi.HPI_ProfileGetName.restype = err_t
    e = _libhpi.HPI_ProfileGetName(_ss, h, i, name, 32)
    name[32] = '\0'
    return e, name.value

def Profile_GetUtilization(h):
    r = c_uint32()
    _libhpi.HPI_ProfileGetUtilization.restype = err_t
    e = _libhpi.HPI_ProfileGetUtilization(_ss, h, byref(r))
    return e, r.value

def Profile_StartAll(h):
    _libhpi.HPI_ProfileStartAll.restype = err_t
    return _libhpi.HPI_ProfileStartAll(_ss, h)

def Profile_StopAll(h):
    _libhpi.HPI_ProfileStopAll.restype = err_t
    return _libhpi.HPI_ProfileStopAll(_ss, h)


def TestNotImplemented():
    _libhpi.NotImplemented()

# TEST FUNCTION
def _test_local():
    try:
        TestNotImplemented()
    except AttributeError:
        print('TestNotImplemented() not in hpi library')

    print('GetErrorText %d "%s"' % (0, GetErrorText(0)))
    for e in range(99,105):
        print('GetErrorText %d "%s"' %(e, GetErrorText(e)))

    _test_entity()
    _test_obj()
    _test_obj2()

def _test_adapter(ai = 0):
    import time

    e = Adapter_Open(ai)
    print('Adapter_Open 0', e)
    if e:
        raise ValueError('Could not open adapter#0')

    e, hm = Mixer_Open(ai)
    print('Mixer_Open', e, hm)
    for i in range(5):
        r = Mixer_GetControlByIndex(hm,i)
        if r[0]: break
        print('Mixer_GetControlByIndex',i,r)
        print('Mixer_GetControl', Mixer_GetControl(hm, *r[1:6]))

    e, fmt = Format_Create(2, FORMAT_PCM16_SIGNED, 44100, 0, 0)
    print('Format_Create', e, fmt)

    e, hs = OutStream_Open(ai, 0)
    print('OutStream_Open(0, 0)', e, hs)

    print('OutStream_QueryFormat', OutStream_QueryFormat(hs, fmt))
    e = OutStream_WriteBuf(hs, "test ostream write buf", fmt)
    print('OutStream_WriteBuf', e)
    print('OutStream_GetInfoEx', OutStream_GetInfoEx(hs))

    e, his = InStream_Open(ai, 0)
    print('InStream_Open(0, 0)', e, his)
    e = InStream_SetFormat(his, fmt)
    print('InStream_SetFormat', e)
    InStream_Start(his)
    time.sleep(0.5)
    print('InStream_GetInfoEx', InStream_GetInfoEx(hs))
    r = InStream_ReadBuf(his, 100)
    print('InStream_ReadBuf', r, len(r[1]))

if __name__ == '__main__':
    setup()
    _test_local()
    for ai in [0, 102]:
        try:
            print('Test adapter %d' % ai)
            setup(ai)
            _test_adapter(ai)
        except Exception as e:
            print(e)

#####################################################################
# BELOW HERE, hpi.h prototypes not yet implemented above

#~ /****************************/
#~ /* AES/EBU Receiver control */
#~ /****************************/
#~ HPI_API (HPI_ERR) HPI_AESEBU_Receiver_QueryFormat(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ const HPI_HCONTROL hAesRx,
	#~ const HW32 dwIndex,
	#~ HW16 *pwFormat
#~ );

#~ HPI_API (HPI_ERR) HPI_AESEBU_Receiver_SetFormat(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wSource
#~ );

#~ HPI_API (HPI_ERR) HPI_AESEBU_Receiver_GetUserData(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wIndex,
	#~ HW16 *pwData
#~ );

#~ HPI_API (HPI_ERR) HPI_AESEBU_Receiver_GetChannelStatus(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wIndex,
	#~ HW16 *pwData
#~ );

#~ /*******************************/
#~ /* AES/EBU Transmitter control */
#~ /*******************************/
#~ HPI_API (HPI_ERR) HPI_AESEBU_Transmitter_SetSampleRate(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW32 dwSampleRate
#~ );

#~ HPI_API (HPI_ERR) HPI_AESEBU_Transmitter_SetUserData(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wIndex,
	#~ HW16 wData
#~ );

#~ HPI_API (HPI_ERR) HPI_AESEBU_Transmitter_SetChannelStatus(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wIndex,
	#~ HW16 wData
#~ );

#~ HPI_API (HPI_ERR) HPI_AESEBU_Transmitter_GetChannelStatus(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wIndex,
	#~ HW16 *pwData
#~ );

#~ HPI_API (HPI_ERR) HPI_AESEBU_Transmitter_QueryFormat(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ const HPI_HCONTROL hAesTx,
	#~ const HW32 dwIndex,
	#~ HW16 *pwFormat
#~ );

#~ HPI_API (HPI_ERR) HPI_AESEBU_Transmitter_SetFormat(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wOutputFormat
#~ );


#~ /*******************************
  #~ Parametric Equalizer control
#~ *******************************/
#~ HPI_API (HPI_ERR) HPI_ParametricEQ_GetInfo(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 *pwNumberOfBands,
	#~ HW16 *pwEnabled
#~ );

#~ HPI_API (HPI_ERR) HPI_ParametricEQ_SetState(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wOnOff
#~ );

#~ HPI_API (HPI_ERR) HPI_ParametricEQ_SetBand(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wIndex,
	#~ HW16 nType,
	#~ HW32 dwFrequencyHz,
	#~ short nQ100,
	#~ short nGain0_01dB
#~ );

#~ HPI_API (HPI_ERR) HPI_ParametricEQ_GetBand(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wIndex,
	#~ HW16 *pnType,
	#~ HW32 *pdwFrequencyHz,
	#~ short *pnQ100,
	#~ short *pnGain0_01dB
#~ );

#~ HPI_API (HPI_ERR) HPI_ParametricEQ_GetCoeffs(
	#~ const HPI_HSUBSYS *phSubSys,
	#~ HPI_HCONTROL hControl,
	#~ HW16 wIndex,
	#~ short coeffs[5]
#~ );

#####################################################################
# Below here, unlikely to implement, unless someone wants them

#~ HPI_API (HPI_ERR) HPI_SubSysGetVersion - use Ex version
#~ HPI_API (HPI_ERR) HPI_SubSysGetInfo(

#~ HPI_API (HPI_ERR) HPI_AdapterSelfTest - no implementers
#~ HPI_API (HPI_ERR) HPI_AdapterGetAssert - use Ex version
#~ HPI_API (HPI_ERR) HPI_AdapterEnableCapability - no remaining implementers
#~ HPI_API (HPI_ERR) HPI_AdapterSetMode - use Ex version

#~ HPI_API (HPI_ERR) HPI_OutStreamSetPunchInOut(
#~ HPI_API (HPI_ERR) HPI_OutStreamSinegen(

#~ HPI_API (HPI_ERR) HPI_VolumeAutoFade - use Profile version

#~ HPI_API (HPI_ERR) HPI_ClockOpen(
#~ HPI_API (HPI_ERR) HPI_ClockSetTime(
#~ HPI_API (HPI_ERR) HPI_ClockGetTime(

#~ HPI_API (HPI_ERR) HPI_Cobranet_GetIPaddress - use generic read/write instead.
#~ HPI_API (HPI_ERR) HPI_Cobranet_SetIPaddress
#~ HPI_API (HPI_ERR) HPI_Cobranet_GetStaticIPaddress
#~ HPI_API (HPI_ERR) HPI_Cobranet_SetStaticIPaddress
#~ HPI_API (HPI_ERR) HPI_Cobranet_GetMACaddress

#~ HPI_API (HPI_ERR) HPI_Bitstream_SetClockEdge - no remaining implementers of bitstream
#~ HPI_API (HPI_ERR) HPI_Bitstream_SetDataPolarity
#~ HPI_API (HPI_ERR) HPI_Bitstream_GetActivity

#~ HPI_API (HPI_ERR) HPI_WatchdogOpen(
#~ HPI_API (HPI_ERR) HPI_WatchdogSetTime(
#~ HPI_API (HPI_ERR) HPI_WatchdogPing(

# Not until there is an adapter that supports them
#~ HPI_API (HPI_ERR) HPI_AsyncEventOpen(
#~ HPI_API (HPI_ERR) HPI_AsyncEventClose(
#~ HPI_API (HPI_ERR) HPI_AsyncEventWait(
#~ HPI_API (HPI_ERR) HPI_AsyncEventGetCount(
#~ HPI_API (HPI_ERR) HPI_AsyncEventGet(
