K8061 class with events

Because their is a lack of events in the k8061 i wrote a class (for VB) which makes de k8061 card event driven.

It has the following features:
-Throw events when changing digital inputs
-Throw events when a trigger has been reached for analog inputs
-Throw event when power is lost
-Throw event when disconnected
-SetDigitalChannelK(Channel) accepts channels higher than 8 and automatically set the first analog channel to the highest setting. SetDigitalChannelK(9) will set analog channel 0 to the highest setting
-Automaticcaly reconnect after disconnect

An analogIn threshold has the settings:
-thresholdName
-repeatCount =number of times events should be triggered
-repeatInterval = millisecs between repeat of events
-direction = Should event be triggerd if value rises above ‘thresholdValue’ then enter ‘HIGHER’. Should event be triggered if value drops ‘thresholdValue’ then enter ‘LOWER’. Or should event be triggered when it passes ‘thresholdValue’, then enter ‘LOWERHIGHER’
-passDuration = Time in msecs the threshold must be reached before an event is fired.

The class itself

Imports System.Timers
Public Class k8061
    '**************************************************************************************************************************************
    '**********************************************************************************
    '**
    '**     This class is only tested with 1 card. Closedevice will close every device, 
    '**     i think it will raise disconnect events in other cards.
    '**
    '**     The class will scan the various inputs and will fire an event when a change
    '**     has been detected. Every analogIn port will fire 'on_AnalogInUpdate' events
    '**     to update e.g. an digitaldisplay. Every port can have thresholds which will 
    '**     fire their own events.
    '**     
    '**     To have more digital outputs:
    '**     SetDigitalChannelK(Channel) accepts channels higher than 8 and
    '**     automatically set the first analog channel to the highest setting.
    '**     SetDigitalChannelK(9) will set analog channel 0 to the highest setting
    '**     
    '**     The class wil automatically reconnect after disconnecting.
    '** 
    '**     !!To use this class in your own application, you obviously have to remove
    '**     the 'Form1' links...!!
    '**
    '**     Credits: Lars Bosboom
    '**
    '**********************************************************************************
    '**********************************************************************************
    Const EVENTINTERVAL = 10        'change to whatever you like(in milliseconds, Recommended <50)
    Const RECONNECTINTERVAL = 1000  'in milliseconds
    Const RECONNECT = True          'Set to 'true' if you want to automatically reconnect after disconnection


    Public Event on_PowerChange()
    Public Event on_Disconnect()
    Public Event on_DigitalInChange(ByVal i As Short, ByVal state As Boolean)
    Public Event on_AnalogInThresholdReached(ByVal name As String, ByVal i As Short, ByVal value As Integer)
    Public Event on_AnalogInUpdate(ByVal i As Short, ByVal value As Integer)

    Private Declare Function timeGetTime Lib "winmm.dll" () As Long

    Private Declare Function OpenDevice Lib "k8061.dll" () As Integer
    Private Declare Sub CloseDevices Lib "k8061.dll" ()
    Private Declare Function ReadAnalogChannel Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Channel As Integer) As Integer
    Private Declare Function PowerGood Lib "k8061.dll" (ByVal CardAddress As Integer) As Boolean
    Private Declare Function Connected Lib "k8061.dll" (ByVal CardAddress As Integer) As Boolean
    Private Declare Sub ReadVersion Lib "k8061.dll" (ByVal CardAddress As Integer, ByRef Buffer As Integer)
    Private Declare Sub ReadAllAnalog Lib "k8061.dll" (ByVal CardAddress As Integer, ByRef Buffer As Integer)
    Private Declare Sub OutputAnalogChannel Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Channel As Integer, ByVal Data As Integer)
    Private Declare Sub OutputAllAnalog Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Buffer As Integer)
    Private Declare Sub ClearAnalogChannel Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Channel As Integer)
    Private Declare Sub SetAllAnalog Lib "k8061.dll" (ByVal CardAddress As Integer)
    Private Declare Sub ClearAllAnalog Lib "k8061.dll" (ByVal CardAddress As Integer)
    Private Declare Sub SetAnalogChannel Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Channel As Integer)
    Private Declare Sub OutputAllDigital Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Data As Integer)
    Private Declare Sub ClearDigitalChannel Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Channel As Integer)
    Private Declare Sub ClearAllDigital Lib "k8061.dll" (ByVal CardAddress As Integer)
    Private Declare Sub SetDigitalChannel Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Channel As Integer)
    Private Declare Sub SetAllDigital Lib "k8061.dll" (ByVal CardAddress As Integer)
    Private Declare Function ReadDigitalChannel Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Channel As Integer) As Boolean
    Private Declare Function ReadAllDigital Lib "k8061.dll" (ByVal CardAddress As Integer) As Integer
    Private Declare Sub OutputPWM Lib "k8061.dll" (ByVal CardAddress As Integer, ByVal Data As Integer)

    Private Shared tickTimer As New System.Windows.Forms.Timer()
    Private Shared reconnectTimer As New System.Windows.Forms.Timer()

    Dim CardAddress As Integer = -4
    Dim Power As Boolean
    Dim AllDigital As Integer
    Const LOWER = 2
    Const HIGHER = 3
    Const LOWERHIGHER = 1

    Public AnalogIn(7) As AnalogInChannelClass
    'Dim AnalogIn() As Collection

    Dim firstPower As Boolean 'When connected without power, this will prevent triggering events for all ports


    Structure AnalogInThreshold
        Public thresholdValue As Integer
        Public thresholdName As String
        Public repeatCount As Integer 'number of times events should be triggered
        Public repeatInterval As Integer 'millisecs between repeat of events
        Public direction As Short 'Should event be triggerd if value rises above 'thresholdValue' then enter 'HIGHER'. Should
        'event be triggered if value drops below 'thresholdValue' then enter 'LOWER'. Or should
        'event be triggered when it passes 'thresholdValue', then enter 'LOWERHIGHER'
        Public passDuration As Integer 'Time in msecs the threshold must be reached before an event is fired.

        Public timeThresholdPassed As Integer
        Public RepeatCountDone As Integer
    End Structure

    Public Class AnalogInChannelClass
        Public value As Integer
        Public rawValue As Integer
        Public maximum As Integer = 1023
        Public minimum As Integer
        Public Thresholds(9) As AnalogInThreshold       'maximum of thresholds per port, change if you need to

    End Class




    Public Sub New()
        tickTimer.Interval = EVENTINTERVAL
        reconnectTimer.Interval = RECONNECTINTERVAL
        AddHandler tickTimer.Tick, AddressOf tik
        AddHandler reconnectTimer.Tick, AddressOf tryReconnect
        'MsgBox("test" + Me.CardAddress.ToString)

        Dim J As Integer
        For J = 0 To 7
            AnalogIn(J) = New AnalogInChannelClass
        Next J

        '-----------------------------------------------------------------------------------------------------------
        ' ----------------Example Definition for port 3---------------------------------------------------------------------
        '-----------------------------------------------------------------------------------------------------------
        Me.AnalogIn(3).minimum = 0              'change to whatever 0 volts would represent as a value
        Me.AnalogIn(3).maximum = 100            'change to whatever 5-10 volts would represent as a value 

        Dim Thres As AnalogInThreshold          'LEAVE - One time needed for all thresholds
        'ReDim Me.AnalogIn(3).Thresholds(2)      'number of total thresholds

        '------Add a new threshold-------
        Thres = New AnalogInThreshold()
        Thres.thresholdValue = 10
        Thres.thresholdName = "eerste threshold"
        Thres.direction = LOWER                 'See --> 'Structure AnalogInThreshold'
        Thres.passDuration = 100                'Time in msecs the threshold must be reached before an event is fired.
        Thres.repeatCount = 7                   'number of times events should be triggered
        Thres.repeatInterval = 600              'millisecs between repeat of events
        Me.AnalogIn(3).Thresholds(0) = Thres   'change to appropriate port and increase Thressholds position
        '--------------------------------
        '------Add a new threshold-------
        Thres = New AnalogInThreshold()
        Thres.thresholdValue = 60
        Thres.thresholdName = "de tweede threshold"
        Thres.direction = HIGHER
        Thres.passDuration = 4000
        Thres.repeatCount = 3
        Thres.repeatInterval = 1500
        Me.AnalogIn(3).Thresholds(1) = Thres   'change to appropriate port and increase Thressholds position
        '--------------------------------
        '-----------------------------------------------------------------------------------------------------------
        ' ----------------End of definition for port 3-----------------------------------------------------------------
        '-----------------------------------------------------------------------------------------------------------
    End Sub

    Private Sub tryReconnect(ByVal myObject As Object, ByVal myEventArgs As EventArgs)
        If Me.Connect() > -1 Then       'succesfully reconnected
            Form1.TextBox1.Text += "SUCCESFULLY RECONNECTED" + vbNewLine
            reconnectTimer.Stop()
        End If
    End Sub

    Private Function checkConnection() As Boolean
        Dim ret As Boolean
        ret = Connected(Me.CardAddress)
        If (ret = False) Then
            Form1.TextBox1.Text += "Connection lost. stop monitoring" + vbNewLine
            Disconnect(True)
            RaiseEvent on_Disconnect()
            If (RECONNECT) Then
                Form1.TextBox1.Text += "Try to reconnect" + vbNewLine
                reconnectTimer.Start()          'start reconnecting
            End If
            Return False
        End If
        Return True
    End Function

    Public Function Connect() As Integer        'the dll will return -1(all cards connected) when not plugged in!!
        Dim retaddress

        If (Me.CardAddress > -1) Then     'already connected, after reconnect powergood is for a few milliseconds false, so dont retry
            Return -1
        End If
        retaddress = OpenDevice()

        If (retaddress > -1) Then

            Me.CardAddress = retaddress
            Me.Power = PowerGood(Me.CardAddress)
            Me.AllDigital = ReadAllDigital(Me.CardAddress)

            tickTimer.Start()
            If (Me.Power = False) Then
                Me.firstPower = True
                Return -3
            End If
        End If

        Return retaddress

    End Function

    Private Sub checkAnalogIn()
        Dim Buffer(7) As Integer

        ReadAllAnalog(Me.CardAddress, Buffer(0))

        Dim port, I, x, y, convertedValue As Integer
        Dim thrReached As Boolean

        For port = 0 To 7
            For I = 0 To Me.AnalogIn(port).Thresholds.Length - 1
                thrReached = False
                convertedValue = Me.AnalogIn(port).minimum + (Me.AnalogIn(port).maximum * Buffer(port) / 1023)
                With Me.AnalogIn(port).Thresholds(I)
                    Select Case .direction
                        Case 3  'HIGHER
                            If (convertedValue > .thresholdValue) Then
                                'MsgBox("boven threshold")
                                thrReached = True
                            Else
                                .timeThresholdPassed = 0
                            End If
                        Case 2  'LOWER
                            If (convertedValue < .thresholdValue) Then
                                'MsgBox("onder threshold" + timeGetTime.ToString)
                                thrReached = True
                            Else
                                .timeThresholdPassed = 0
                            End If
                        Case 1  'LOWERHIGHER
                            x = convertedValue - .thresholdValue
                            y = Me.AnalogIn(port).value - .thresholdValue
                            thrReached = True
                            If ((x > 0 And y < 0) Or (x < 0 And y > 0)) Then
                                .timeThresholdPassed = 0
                                Form1.TextBox1.Text += "passed x = " + x.ToString + " y = " + y.ToString + vbNewLine
                            End If
                    End Select

                    If thrReached Then
                        If .timeThresholdPassed > 0 Then
                            If ((timeGetTime - .timeThresholdPassed) > .passDuration) Then 'duration before first event

                                If (.repeatCount > .RepeatCountDone) Then
                                    If ((timeGetTime - .timeThresholdPassed - .passDuration) > (.repeatInterval * .RepeatCountDone)) Then

                                        .RepeatCountDone = .RepeatCountDone + 1
                                        RaiseEvent on_AnalogInThresholdReached(.thresholdName, port, convertedValue)
                                    End If
                                End If

                            End If
                        Else
                            .timeThresholdPassed = timeGetTime
                            .RepeatCountDone = 0
                            If (.passDuration = 0) Then
                                RaiseEvent on_AnalogInThresholdReached(.thresholdName, port, convertedValue)
                            End If
                        End If
                    End If

                End With
            Next I
            Me.AnalogIn(port).value = convertedValue
            Me.AnalogIn(port).rawValue = Buffer(port)

            RaiseEvent on_AnalogInUpdate(port, convertedValue)
        Next port

    End Sub


    Private Function checkPower() As Boolean
        Dim ret As Boolean
        ret = PowerGood(Me.CardAddress)


        If Not (ret = Me.Power) Then
            If (checkConnection()) Then
                Form1.TextBox1.Text += "checkpower" + Me.CardAddress.ToString + " ret= " + ret.ToString + " me.power= " + Me.Power.ToString + " connection=" + Connected(Me.CardAddress).ToString + vbNewLine
                Me.Power = ret
                If (Me.firstPower = True) Then     'if true this will prevent triggering events for all ports
                    Me.AllDigital = ReadAllDigital(Me.CardAddress)
                    'MsgBox(Me.AllDigital)
                    Me.firstPower = False
                End If
                RaiseEvent on_PowerChange()
            End If
        End If

        Return ret
    End Function

   

    Private Sub checkDigitalIn()
        Dim ret As Integer
        ' Dim dif As Integer
        Dim nu As Short
        Dim i As Short = 0
        Dim state As Boolean
        Dim dum As Integer
        ret = ReadAllDigital(Me.CardAddress)

        If (checkConnection()) Then             'hmm, seems double but checkConnection sometime wont trigger earlier on

            If Not (ret = Me.AllDigital And (ret < 256 Or ret > -1)) Then
                dum = Me.AllDigital
                Me.AllDigital = ret

                Form1.TextBox1.Text += (Me.AllDigital And 1).ToString
                Form1.TextBox1.Text += (CShort(Me.AllDigital And 2) / 2).ToString
                Form1.TextBox1.Text += (CShort(Me.AllDigital And 4) / 4).ToString
                Form1.TextBox1.Text += (CShort(Me.AllDigital And 8) / 8).ToString
                Form1.TextBox1.Text += (CShort(Me.AllDigital And 16) / 16).ToString
                Form1.TextBox1.Text += (CShort(Me.AllDigital And 32) / 32).ToString
                Form1.TextBox1.Text += (CShort(Me.AllDigital And 64) / 64).ToString
                Form1.TextBox1.Text += (CShort(Me.AllDigital And 128) / 128).ToString + vbNewLine


                While i < 8
                    nu = CShort(ret And (2 ^ i))
                    If (nu Xor (CShort(dum And (2 ^ i)))) Then
                        state = nu
                        RaiseEvent on_DigitalInChange(i + 1, state) 'returns number of port and state
                    End If

                    i = i + 1
                End While

            End If
        End If
    End Sub



    Private Sub tik(ByVal myObject As Object, ByVal myEventArgs As EventArgs)

        If (checkPower()) Then
            checkDigitalIn()
            checkAnalogIn()
        End If

    End Sub



    Public Function Disconnect(ByVal clearAll As Boolean) As Boolean
        If (Me.CardAddress < 0) Then
            Return True
        End If


        tickTimer.Stop()

        If (clearAll) Then
            Me.ClearAllDigitalK()
            Me.OutputPWMK(0)
            Me.ClearAllAnalogK()
        End If

        CloseDevices()                              'ALL devices will close!

        If (Connected(Me.CardAddress) = True) Then
            Return False
        End If
        Me.CardAddress = -4
        Return True 'succesfull disconnect

    End Function

    Public Sub SetAllDigitalK()
        SetAllDigital(Me.CardAddress)
    End Sub
    Public Sub ClearAllDigitalK()
        ClearAllDigital(Me.CardAddress)
    End Sub
    Public Sub SetDigitalChannelK(ByVal i As Short)
        If (i > 8) Then
            Me.SetAnalogChannelK((i - 8))
        End If
        SetDigitalChannel(Me.CardAddress, i)
    End Sub
    Public Sub clearDigitalChannelK(ByVal i As Short)
        ClearDigitalChannel(Me.CardAddress, i)
    End Sub
    Public Sub OutputPWMK(ByVal value As Integer)
        OutputPWM(Me.CardAddress, value)
    End Sub
    Public Function ReadDigitalChannelK(ByVal i As Short) As Boolean
        Return ReadDigitalChannel(Me.CardAddress, i)
    End Function
    Public Function ReadAnalogChannelK(ByVal i As Short) As Integer
        Return ReadAnalogChannel(Me.CardAddress, i)
    End Function
    Public Function ConnectedK() As Integer
        Return Connected(Me.CardAddress)
    End Function
    Public Sub OutputAllDigitalK(ByVal data As Integer)
        OutputAllDigital(Me.CardAddress, data)
    End Sub
    Public Sub SetAnalogChannelK(ByVal i As Short)
        SetAnalogChannel(Me.CardAddress, i)
    End Sub
    Public Sub ClearAllAnalogK()
        ClearAllAnalog(Me.CardAddress)
    End Sub
    Public Sub SetAllAnalogK()
        SetAllAnalog(Me.CardAddress)
    End Sub
    Public Sub ClearAnalogChannelK(ByVal i As Short)
        ClearAnalogChannel(Me.CardAddress, i)
    End Sub
    Public Sub OutputAllAnalogK(ByVal buffer As Integer)
        OutputAllAnalog(Me.CardAddress, buffer)
    End Sub
    Public Sub OutputAnalogChannelK(ByVal i As Short, ByVal Data As Integer)
        OutputAnalogChannel(Me.CardAddress, i, Data)
    End Sub

End Class

I only tested it on one card, to use it with more cards the code has to be changed.

Please let me know what you think of this code.

I made a little test program which uses the class above.

I will show the events thrown and will display the analogIn port 3. Their also two thresholds made which can be adjusted at runtime with two slide bars. Play with it to see how it works…

http://files-upload.com/files/645680/k8061events.zip

Thank you for posting this listing and the link to your test program.
I hope this helps other K8061 users too.
I’ll test your code a.s.a.p.