VM8090 Query_Relais_Status in Autoit

I have written a script in Autoit to control the Relay card. The intended use it to react on mails send from 6 different robot systems that run into an error. The idea is to turn on a signal (lamp or sound) in another room of our laboratory.
After many hours of reading all the topics about the card, trial and error I succeeded in getting the SendCommand to work.
At the moment I can switch on and off relays on the the card.
I am unable to get the status of the card or better the parameters Mask, Param1 and Param2 from the DllCall
I tried several methods but I never get the status back with the SendCommand $CMD_QUERY_RELAY_STATUS (= 24) or $CMD_RELAY_STATUS (= 81)
The result of: $res = DllCall(“K8090D.dll”, “none”, “SendCommand”, “HANDLE”, $dll, “BYTE”, $CMD_QUERY_RELAY_STATUS,“BYTE”, 255, “BYTE”, 0,“BYTE”, 0 ) gives back in $res the parameter of the call I have sent.
As you can see I tried that also with sending struct’s and pointers (NB ; means /* = comment in autoit ) in the hope the SendCommand could change these values in return values

Below part of the script. The Activate/ Deactivate and Toggle functions work

Any idea how to get the parameters Mask, Param1 and Param2 back from the DllCall?


Func Activate_RelaisNr_Velleman_K8090D_card($IntRelaisNr)
$HexRelaisNr = BitRotate(1, $IntRelaisNr - 1)
$result = DllCall(“K8090D.dll”, “none”, “SendCommand”, “HANDLE”, $dll, “BYTE”, $CMD_SWITCH_RELAY_ON,“BYTE”, $HexRelaisNr , “BYTE”, 0,“BYTE”, 0 )
Return $result
EndFunc

Func Deactivate_RelaisNr_Velleman_K8090D_card($IntRelaisNr)
$HexRelaisNr = BitRotate(1, $IntRelaisNr - 1)
$result = DllCall(“K8090D.dll”, “none”, “SendCommand”, “HANDLE”, $dll, “BYTE”, $CMD_SWITCH_RELAY_OFF,“BYTE”, $HexRelaisNr , “BYTE”, 0,“BYTE”, 0 )
Return $result
EndFunc

Func Toggle_RelaisNr_Velleman_K8090D_card($IntRelaisNr)
$HexRelaisNr = BitRotate(1, $IntRelaisNr - 1)
$result = DllCall(“K8090D.dll”, “none”, “SendCommand”, “HANDLE”, $dll, “BYTE”, $CMD_TOGGLE_RELAY,“BYTE”, $HexRelaisNr, “BYTE”, 0,“BYTE”, 0 )
Return $result
EndFunc

Func Query_Relais_Status($IntRelaisNr)
; Local $Mask = DllStructCreate(“byte”)
; Local $Param1 = DllStructCreate(“byte”)
; local $Param2 = DllStructCreate(“byte”)

;Local $tagCALL = DllStructCreate(“byte Mask; byte Param1; byte Param2”)
; DllStructSetData($tagCALL, ‘Mask’, 16) ; zet de grootte van de struct in $Mask als test
;MsgBox(4096,“query0”, DllStructGetData($tagCALL,“Mask”),2)
; function does not work
$HexRelaisNr = BitRotate(1, $IntRelaisNr - 1)
Activate_RelaisNr_Velleman_K8090D_card(4)
MsgBox(4096,“query1”, "Relaynr: " & $HexRelaisNr,2 )
$res = DllCall(“K8090D.dll”, “none”, “SendCommand”, “HANDLE”, $dll, “BYTE”, $CMD_QUERY_RELAY_STATUS,“BYTE”, 255, “BYTE”, 0,“BYTE”, 0 )
;$res = DllCall(“K8090D.dll”, “none”, “SendCommand”, “HANDLE”, $dll, “BYTE”, $CMD_QUERY_RELAY_STATUS ,“ptr”, DllStructGetPtr($Mask), “ptr”, DllStructGetPtr($Param1),“ptr”, DllStructGetPtr($Param2) )
; $res = DllCall(“K8090D.dll”, “none”, “SendCommand”, “HANDLE”, $dll, “BYTE”, $CMD_QUERY_RELAY_STATUS ,“struct*”, $tagCALL )

; MsgBox(4096,“query1”, DllStructGetData($tagCALL,“Mask”),2)
$temp = " (0): " & $res[0] & " (1) " & $res[1] & " (2) " & $res[2] & " (3) " & $res[3] & " (4) " & $res[4] & " (5) " & $res[5]
; $temp = " (0): " & $res[0] & " (1) " & $res[1] & " (2) " & $res[2] & " (3) " & DllStructGetData($Mask,1) & " (4) " & DllStructGetData($Param1,1) & " (5) " & DllStructGetData($Param2,1)
; $temp = "(3) " & DllStructGetData($tagCALL, “Mask”) & " (4) " & DllStructGetData($tagCALL,“Param1”) & " (5) " & DllStructGetData($tagCALL,“Param2”)

MsgBox(4096,“query2”, $temp)
$result = BitXOR($res[4], $res[5]) And $res[5]
Return $result
EndFunc

[quote]SendCommand
Sends an asynchronous command packet to the K8090 device.

Return value:
If the function succeeds, the return value is TRUE. If the function fails the return value is
FALSE. To get extended information, call GetLastError.[/quote]SendCommand only reports if sending the command succeeded or not.

I’m afraid there is no straightforward way to retrieve the status in this case.

AutoIt example project for the K8090:
velleman.eu/downloads/files/ … autoit.zip

Thanks!
Now I know see to register a function.
I will experiment with it

Dear Vel448

Thanks for the excellent support in this forum. All the answers of your team are of high quality and to the point.

I attached an Autoit script that works with the VM8090 board. The original script receives an Outlook mail and compares the text in the subject of the mail with the text associated with the relay number. I stripped this code from the attached script because it is not relevant for this forum.

Regards,
Ed


; #AutoIt3Wrapper_Au3Check_Parameters= -q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#AutoIt3Wrapper_Au3Check_Stop_OnWarning=N

; #INDEX# =======================================================================================================================
; Title .........: Relais
; AutoIt Version : 3
; Language ......: English
; Description ...: Connects to Velleman 8090 8-channel USB Relay card and reacts on Outlook received message.
; Author(s) .....: Ed Nieuwenhuys
; Version........: 0.15
; Version 1.0....: 29131220 (YYYYMMDD)
; Modified.......:
; Changes........:
; Resources .....: Velleman K8090D_DLL.pdf, K8090_PROTOCOLMANUAL.pdf
; ===============================================================================================================================

;~ Func TestCardFunctions()
;~ Func oOApp_NewMailEx($sOL_EntryId)
;~ Func _Exit()
;~ Func Activate_RelaisNr_Velleman_K8090D_card($IntRelaisNr)
;~ Func Deactivate_RelaisNr_Velleman_K8090D_card($IntRelaisNr)
;~ Func Toggle_RelaisNr_Velleman_K8090D_card($IntRelaisNr)
;~ Func Query_Relais_Status_Velleman_K8090D_card()
;~ Func TimeInSec_RelaisNr_Velleman_K8090D_card($IntRelaisNr, $Seconds)
;~ Func Set_Relay_Timer_Delay_Velleman_K8090D_card($IntRelaisNr, $Seconds)
;~ Func Reset_Velleman_K8090D_card()
;~ Func Connect_Velleman_K8090D_card()
;~ Func USB_DLLOpen()
;~ Func Close_Velleman_K8090D_card()
;~ Func StartApp()
;~ Func ActOnOutlookMessage()
;~ Func SetRelayText($nr)
;~ Func TurnOnCheckbox($nr)
;~ Func TurnOffCheckbox($nr)
;~ Func ToggleCheckbox($nr)
;~ Func ActOnCheckbox($nr)
;~ Func WriteRelayTextToFile()
;~ Func ReadRelayTextFromFile()
;~ Func CommandReceived($cmd, $mask, $param1, $param2)
;~ Func StatusReceived($hWnd, $iMsg, $wParam, $lParam)
; ===============================================================================================================================

#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <WinAPI.au3>
#include <File.au3>


Global Const  $CMD_SWITCH_RELAY_ON = 17
Global Const  $CMD_SWITCH_RELAY_OFF = 18
Global Const  $CMD_TOGGLE_RELAY = 20
Global Const  $CMD_QUERY_RELAY_STATUS = 24
Global Const  $CMD_SET_MANUAL_OPERATION_MODE = 33
Global Const  $CMD_QUERY_MANUAL_OPERATION_MODE = 34
Global Const  $CMD_START_RELAY_TIMER = 65
Global Const  $CMD_SET_RELAY_TIMER_DELAY = 66
Global Const  $CMD_QUERY_TIMER_DELAY = 68
Global Const  $CMD_BUTTON_STATUS = 80
Global Const  $CMD_RELAY_STATUS = 81
Global Const  $CMD_RESET_FACTORY_DEFAULTS = 102
Global Const  $CMD_GET_JUMPER_STATUS = 112
Global Const  $CMD_FIRMWARE_VERSION = 113
Global Const $WM_K8090_STATUS = $WM_USER + 1

; *****************************************************************************
; This script loops until Shift-Alt-E is pressed to exit.
; *****************************************************************************
HotKeySet("+!e", "_Exit") ;Shift-Alt-E to Exit the script
;HotKeySet("{Esc}", "_Exit") ;Shift-Alt-E to Exit the script

Global $dll
Global $dllOpen
Global $HLabel
Global $Compoort = "COM3"
Global $EmailMessage = "Erreur"
Global $FileName = @ScriptDir & "\RelayText.txt"
Global $AlarmTimeSec = 60 ; turn on alarm for .. seconds

Global $Relaytext[9]
Global $input[9]
Global $Button[9]
Global $Checkbox[9]

; *****************************************************************************
; Initialise card and gets handle to card ($dll)
$dll = Connect_Velleman_K8090D_card()  ; Make the connection
Reset_Velleman_K8090D_card()		   ; Reset all relays
; *****************************************************************************

;##################################################################################<<<<<
StartApp()
_Exit()
;###################################################################################>>>>>

;****************************
; test card functions`
Func TestCardFunctions()

   Activate_RelaisNr_Velleman_K8090D_card(4)
   MsgBox(4096,"Card test", "Turn relay 4 on and off after this message disappears",2)
   Deactivate_RelaisNr_Velleman_K8090D_card(4)
   TimeInSec_RelaisNr_Velleman_K8090D_card(8, 2)
   MsgBox(4096,"Card test", "Turn relay 2 on and off after with timer dealy func after 2 sec",2)
   For $m = 1 to 2
	  For $n = 6 to 8
		 Toggle_RelaisNr_Velleman_K8090D_card($n)
		 TimeInSec_RelaisNr_Velleman_K8090D_card($n, 1)
		 Sleep(1100)
	  Next
   Next

EndFunc
;****************************

; <<<<<<<<<<<<<<<<<<<<<<<<<<======================================================
Func _Exit()
   MsgBox(4096,"Program ended", "Program ended",2)
   Reset_Velleman_K8090D_card()
   Close_Velleman_K8090D_card()
	Exit
EndFunc   ;==>_Exit;
; <<<<<<<<<<<<<<<<<<<<<<<<<<======================================================

; ********************************************************************************
; *******************Velleman card K8090D Functions ******************************
; ********************************************************************************

Func Activate_RelaisNr_Velleman_K8090D_card($IntRelaisNr)
   $HexRelaisNr = BitRotate(1, $IntRelaisNr - 1)
   $result = DllCall("K8090D.dll", "none", "SendCommand", "HANDLE", $dll, "BYTE", $CMD_SWITCH_RELAY_ON,"BYTE", $HexRelaisNr , "BYTE", 0,"BYTE", 0 )
   Return $result
EndFunc

Func Deactivate_RelaisNr_Velleman_K8090D_card($IntRelaisNr)
   $HexRelaisNr = BitRotate(1, $IntRelaisNr - 1)
   $result = DllCall("K8090D.dll", "none", "SendCommand", "HANDLE", $dll, "BYTE", $CMD_SWITCH_RELAY_OFF,"BYTE", $HexRelaisNr , "BYTE", 0,"BYTE", 0 )
   Return $result
EndFunc

Func Toggle_RelaisNr_Velleman_K8090D_card($IntRelaisNr)
   $HexRelaisNr = BitRotate(1, $IntRelaisNr - 1)
   $result = DllCall("K8090D.dll", "none", "SendCommand", "HANDLE", $dll, "BYTE", $CMD_TOGGLE_RELAY,"BYTE", $HexRelaisNr, "BYTE", 0,"BYTE", 0 )
   Return $result
EndFunc

Func Query_Relais_Status_Velleman_K8090D_card()
   ; The board will respond with a 'Relay status (51h)' packet.
  $result = DllCall("K8090D.dll", "none", "SendCommand", "HANDLE", $dll, "BYTE", $CMD_QUERY_RELAY_STATUS,"BYTE", 0, "BYTE", 0,"BYTE", 0 )
   Return $result
EndFunc

Func TimeInSec_RelaisNr_Velleman_K8090D_card($IntRelaisNr, $Seconds)
   $HexRelaisNr = BitRotate(1, $IntRelaisNr - 1)
   $ISec = int($Seconds)
   If ($ISec >32767) Then $ISec =32767
   $HiByteSeconds = Int($ISec / 255)
   $LowByteSeconds = Mod($ISec, 255)
;    MsgBox(4096,"Seconden ", $ISec & " : " & $LowByteSeconds & " : " & $HiByteSeconds)
   $result = DllCall("K8090D.dll", "none", "SendCommand", "HANDLE", $dll, "BYTE", $CMD_START_RELAY_TIMER,"BYTE", $HexRelaisNr, "BYTE", $HiByteSeconds,"BYTE", $LowByteSeconds )
   Return $result
EndFunc

Func Set_Relay_Timer_Delay_Velleman_K8090D_card($IntRelaisNr, $Seconds)
   $HexRelaisNr = BitRotate(1, $IntRelaisNr - 1)
   $ISec = int($Seconds)
   If ($ISec >32767) Then $ISec =32767
   $HiByteSeconds = Int($ISec / 255)
   $LowByteSeconds = Mod($ISec, 255)
   $result = DllCall("K8090D.dll", "none", "SendCommand", "HANDLE", $dll, "BYTE", $CMD_SET_RELAY_TIMER_DELAY,"BYTE", $HexRelaisNr, "BYTE", $HiByteSeconds,"BYTE", $LowByteSeconds )
   Return $result
EndFunc

Func Reset_Velleman_K8090D_card()
   $result = DllCall("K8090D.dll", "none", "SendCommand", "HANDLE", $dll, "BYTE", $CMD_RESET_FACTORY_DEFAULTS,"BYTE", 0, "BYTE", 0,"BYTE", 0 )
   Return $result
EndFunc

; ********************************************************************************
; Basic Velleman card K8090D Functions
; ********************************************************************************

Func Connect_Velleman_K8090D_card()
   USB_DLLOpen()
   $n=1
   Do   ; check if a card between COM1 and COM128 is connected
	  $Compoort = "COM"& $n
	  $Result = DllCall("K8090D.dll", "long", "OpenDevice", "str", $Compoort)
;  MsgBox(4096,"Connect Velleman",$Result[0] & "   " & @error )
	  $dll=$result[0]
	  $n=$n+1
   Until $dll >0 or $n > 128
 If $n > 128 Then
	 MsgBox(4096,"Connect Velleman", "No COM1-128 connection found" )
	 _Exit()
 EndIf
Return $result[0]
EndFunc

Func USB_DLLOpen()
	$dllOpen=DllOpen("K8090D.dll") ; openenen DLL
	$dll = $dllOpen
EndFunc   ;==>USB_DLLOpen

Func Close_Velleman_K8090D_card()
   Local $Result = DllCall("K8090D.dll", "long", "CloseDevice","HANDLE", $dll)
   DllClose($dll)
    Return
EndFunc


;************************ StartApp ===================================================>
Func StartApp()

; Dimensions of the window
   $x =  48
   $y =  10
   $b = 200
   $h =  21
   $d =  20
; Create the window
   Global $Form = GUICreate("Outlook mail <-> Vellerman 8090 board control", 405, 350, 302, 218)
; Tell the DLL that we want to receive WM_K8090_STATUS messages
   DllCall($dllOpen, "BOOLEAN", "RegisterListener", "HANDLE",$dll, "HWND",$Form)
; Also tell the GUI that we want to receive those messages
   GUIRegisterMsg($WM_K8090_STATUS, "StatusReceived")

   For $i = 1 to 8
	  $Input[$i] = GUICtrlCreateInput("Message" & $i, $x,     $y + ($i * 30), $b, $h)
	  $Checkbox[$i] = GUICtrlCreateCheckbox($i, $x+245, $y+1 + ($i * 30), $d+10, $d)
	  GUICtrlSetState(-1, $GUI_UNCHECKED)
	  $Button[$i]= GUICtrlCreateLabel(" "     , $x+220, $y+1 + ($i * 30), $d, $d)
	  GUICtrlSetBkColor($Button[$i], 0x00FF00)
	  $Relaytext[$i] = "Message #" & $i
   Next
   $HLabel = GUICtrlCreateLabel("Last message will be shown here", $x, ($i+1) * 30)
   GUISetState(@SW_SHOW) ; show the created window
   ReadRelayTextFromFile() ;read the 8 texts from File and place thge in the input fields of the Window

  TestCardFunctions()

   While 1
   $nMsg = GUIGetMsg()
	  Switch $nMsg
   Case $GUI_EVENT_CLOSE
	  For $n = 1 to 8
		 Deactivate_RelaisNr_Velleman_K8090D_card($n)
	  Next
            Exit
	  Case $Input[1]
		 SetRelayText(1)
	  Case $Input[2]
		 SetRelayText(2)
	  Case $Input[3]
		 SetRelayText(3)
	  Case $Input[4]
		 SetRelayText(4)
	  Case $Input[5]
		 SetRelayText(5)
	  Case $Input[6]
		 SetRelayText(6)
	  Case $Input[7]
		 SetRelayText(7)
	  Case $Input[8]
		 SetRelayText(8)

	  Case $Checkbox[1]
		 ActOnCheckbox(1)
	  Case $Checkbox[2]
		 ActOnCheckbox(2)
	  Case $Checkbox[3]
		 ActOnCheckbox(3)
	  Case $Checkbox[4]
		 ActOnCheckbox(4)
	  Case $Checkbox[5]
		 ActOnCheckbox(5)
	  Case $Checkbox[6]
		 ActOnCheckbox(6)
	  Case $Checkbox[7]
		 ActOnCheckbox(7)
	  Case $Checkbox[8]
		 ActOnCheckbox(8)
	  Case $HLabel
		 MsgBox(4096,"Outlook mail","Hlabel",2 )
		 ActOnMessage()

	  EndSwitch
   WEnd
EndFunc
; ************************** ==> End startApp

; Checks the received subject mail message with the eight texts in the RelayText fields and turn on the checkbox for ($AlarmTimeSec) seconds
Func ActOnMessage()
Local $Relaynr
   For $n = 1 to 8
	  If StringUpper($Relaytext[$n]) =  StringUpper($EmailMessage) Then
		 TimeInSec_RelaisNr_Velleman_K8090D_card($n, $AlarmTimeSec)
		 $Relaynr=$n
	  EndIf
   Next
MsgBox(4096,"Received message", StringUpper($EmailMessage),2 )
Return $Relaynr
EndFunc


; Place the text from the input field in the SetRelayText array
Func SetRelayText($nr)
   $Relaytext[$nr] = GUICtrlRead($Input[$nr])
   WriteRelayTextToFile()
EndFunc

;Turn on the checkbox and color
Func TurnOnCheckbox($nr)
   GUICtrlSetState($Checkbox[$nr],$GUI_CHECKED)
   GUICtrlSetBkColor($Button[$nr], 0xFF0000)
EndFunc

;Turn off the checkbox and color
Func TurnOffCheckbox($nr)
   GUICtrlSetState($Checkbox[$nr], $GUI_UNCHECKED)
   GUICtrlSetBkColor($Button[$nr], 0x00FF00)
EndFunc

Func ToggleCheckbox($nr)
   If GUICtrlRead($Checkbox[$nr]) = $GUI_UNCHECKED	  Then
	  TurnOnCheckbox($nr)
   Else
	  TurnOffCheckbox($nr)
   EndIf
EndFunc

Func ActOnCheckbox($nr)
   If GUICtrlRead($Checkbox[$nr]) = $GUI_CHECKED	  Then
	  GUICtrlSetBkColor($Button[$nr], 0xFF0000)
	  Activate_RelaisNr_Velleman_K8090D_card($nr)
   EndIf
   If GUICtrlRead($Checkbox[$nr]) = $GUI_UNCHECKED  Then
	  GUICtrlSetBkColor($Button[$nr], 0x00FF00)
	  Deactivate_RelaisNr_Velleman_K8090D_card($nr)
   EndIf
EndFunc

Func WriteRelayTextToFile()
   Local $hFile = FileOpen($FileName, 2) ; 2 = Write mode (erase previous contents)
   For $n = 1 to 8
	  FileWriteLine($hFile, $Relaytext[$n])
   Next
   FileClose($hFile)
EndFunc

Func ReadRelayTextFromFile()
; Open file and append second array
Local $hFile = FileOpen($FileName, 0) ;  0 = Read mode
If $hFile = -1 Then
    MsgBox(0, "Error", "Unable to open file." & $hFile & "- "& $FileName,10)
	FileClose($hFile)
	WriteRelayTextToFile() ; write default text
	Return
 EndIf

For $n = 1 to 8
   $Relaytext[$n] = FileReadLine($hFile)
   GUICtrlSetData($Input[$n],$Relaytext[$n])
Next
FileClose($hFile)
   EndFunc


; This function is called every time the K8090 sends
; a command to the computer. In this example, we catch
; both the button status and relay status commands.

Func CommandReceived($cmd, $mask, $param1, $param2)
   Switch $cmd
   Case 0x50
;	  MsgBox(4096, "Button status", Hex($mask, 2),1) ; show which buttons are pressed
   Query_Relais_Status_Velleman_K8090D_card()
   Case 0x51
;	  MsgBox(4096, "Relay status", Hex($param1, 2),1) ; show which relays are switched on
	  For $n = 0 to 7
	;  MsgBox(4096, "Relay status", $n +1 & ": "& BitAND(2 ^ $n, $param1) & " - " & Hex($param1, 2),1) ; show which relays are switched on
		 If BitAND(2 ^ $n, $param1) = True	Then
			TurnOnCheckbox($n+1)
		 Else
			TurnOffCheckbox($n+1)
		 EndIf
	  Next
   EndSwitch
EndFunc

; This function is called every time the DLL sends
; a WM_K8090_STATUS message to our GUI window. The message
; can be broken down into a K8090 Command message.

Func StatusReceived($hWnd, $iMsg, $wParam, $lParam)
   Local $cmd, $mask, $param1, $param2

   ; Filter out the information relevant to us
   $cmd    = BitAND(BitShift($lParam, 24), 0xff)
   $mask   = BitAND(BitShift($lParam, 16), 0xff)
   $param1 = BitAND(BitShift($lParam,  8), 0xff)
   $param2 = BitAND(BitShift($lParam,  0), 0xff)
;MsgBox(4096, "Status received",  Hex($cmd,2 ) & " - "& Hex($mask, 2) & "- "& Hex($param1, 2) & " - "&Hex($param2, 2),10) ; show which relays are switched on
   CommandReceived($cmd, $mask, $param1, $param2)
EndFunc