frank10 Posted November 28, 2011 Share Posted November 28, 2011 I made a script that runs 24/24 on a home server. With a pc with XP all works well, but now I must switch to a pc with W7pro (i7 4 core) and here the script sometimes blocks itself and it's impossible to kill the process also from TaskManager (both the autoit and the wrapper)! I must reboot. I use it to control from USB a series of Temperature sensors and relè (this, making Run from an exeternal exe in C), and from another USB board some other inputs. I use also some includes: WinInet, sqlite, winapi and CommMg for the serial port. Finally I use also PacketX with WinPCAP to sniff a port. I launch it from Scite because I want to see a lot of ConsoleWrite, the status of some sensors and relè. I tried to run Scite in WinXPSp3 mode and in admin mode. It seems to be more stable, but sometimes it blocks anyway... I tried also to put #AutoIt3Wrapper_UseX64=N at the beginning so I run Scite and autoit in 32 bit. It can work 1-2days or only 1-2hours. I really need to solve this as I need it to work well 24/24 and from XP it worked well, but now I really need W7. What should I do? Link to comment Share on other sites More sharing options...
Bert Posted November 29, 2011 Share Posted November 29, 2011 What should I do?post your code. We are not mind readers when it comes to debugging code. The Vollatran project My blog: http://www.vollysinterestingshit.com/ Link to comment Share on other sites More sharing options...
frank10 Posted November 29, 2011 Author Share Posted November 29, 2011 Well, it's very long code and difficult to follow. It's also a bit difficult to report because I must wait also 1-2days to see if it crashes or not. I thought there can be general issues about XP-W7 that I don't know, so I asked. For example, is it sufficient the XP compatibility mode in the properties of Scite.exe to emulate XP? Is it sufficient to emulate 32bit with Autoit32 like it's executed in XP? Some includes listed above or activeX like PacketX, could not work well in W7? The fact it can't be killed the process with TaskManager, maybe is something hardware related, not SW. I interrogate a board every 300ms through CommMG, maybe in some circustances it doesn't respond anymore and blocks the port and the process? I use this code for that part: expandcollapse popupFunc _SX16($comando,$releNum, $releStato) if $comando = "rele" Then AdlibUnRegister("_ControlloManuale1") $bBinData = Binary( "0x66010301" & $releNum & $releStato ) elseif $comando = "uscite" Then AdlibUnRegister("_ControlloManuale1") $bBinData = Binary("0x660104010000") ; read 6 output Else $bBinData = Binary("0x660101010000") ; read 24 input EndIf $iNumbytes = BinaryLen($bBinData) $tBinData = DllStructCreate("byte[" & $iNumbytes & "]") DllStructSetData($tBinData, 1, $bBinData) local $bit = '', $instr = '' local $i = 1 While $i < 10 If $i = 1 Then $iRet = _CommSendByteArray(DllStructGetPtr($tBinData), $iNumbytes, 1) If @error Or $iRet = -1 Then AdlibUnRegister("_ControlloManuale1") ConsoleWrite("!Error: " & @error & @CRLF) _Commcloseport() Sleep(2000) _CommSetPort($CMPort, $sportSetError, $CmBoBaud, $CmboDataBits, $CmBoParity, $CmBoStop, $setflow, $RTSMode, $DTRMode) AdlibRegister("_ControlloManuale1", 300) EndIf EndIf $instr &= Hex(_CommReadByte(),2) Sleep(20) $i += 1 WEnd $instr = "0x" & StringMid($instr,StringInStr($instr,"55"),16) if $instr <> '' and ($comando = "rele" or $comando = "uscite" ) Then $num = BinaryMid($instr,5,1) For $i = 0 To 7 $hex = BitShift($num, $i) $b = BitAND($hex, 1) Select Case $i = 0 ......rest of script........... EndSelect $bit &= $b Next else ;if $instr <> '' and $comando = "input" For $j = 0 To 2 $num = BinaryMid($instr,4 +$j,1) For $i = 0 To 7 $hex = BitShift($num, $i) $b = BitAND($hex, 1) $bit &= $b if $i = 7 Then $bit &= "-" Next Next $bit = StringLeft($bit,StringLen($bit)-1) For $i = 0 to 25 if $i <> 9 or $i <> 18 Then Select Case $i = 0 ......rest of script...... Case $i = 25 EndSelect EndIf Next EndIf $bit = '' if ($comando = "rele" or $comando = "uscite" ) Then AdlibRegister("_ControlloManuale1", 300) EndFunc ; end _SX16 Every 300ms I call this Func and eventually stop the func with adlib _ControlloManuale1 because it has other call to the board and it could conflict. In the check _CommSendByteArray, I tried to reinitialize the board in case of error, but it doesn't work. Some rare times, when it blocks, I see the error message after the call to _CommSendByteArray, but it should set @error to 1, instead it is @error=0, but it hangs all. From CommMG include: ; Returns: on success returns 1 ; on failure returns -1 and sets @error to 1 ; ;;NB could hang if byte cannot be sent and $iWaitComplete <> 0 ; could lose data if you send more bytes than the size of the outbuffer. ; the output buffer size is 2048 Link to comment Share on other sites More sharing options...
Valik Posted November 29, 2011 Share Posted November 29, 2011 Use Opt("TrayIconDebug", 1) and hover over the icon when it's blocked to see what line it is hanging on. You may need to run the script non-compiled for this to work or to provide a useful line number. Link to comment Share on other sites More sharing options...
frank10 Posted November 29, 2011 Author Share Posted November 29, 2011 Thank you. Tomorrow I will try that option running the script from Scite. Link to comment Share on other sites More sharing options...
Zedna Posted November 29, 2011 Share Posted November 29, 2011 (edited) You may also try: 1) Add logging to file especially suspicious parts of your code. After block/crash just look at last lines in your LOG file (to see what happen). 2) Use eliminating method: temporary remove some (suspicious) parts of code and see if it still blocks or no. Edited November 29, 2011 by Zedna Resources UDF ResourcesEx UDF AutoIt Forum Search Link to comment Share on other sites More sharing options...
frank10 Posted November 30, 2011 Author Share Posted November 30, 2011 I launched Scite without compatibility mode nor Admin to provoke a faster block: in fact it was. I made more ConsoleWrite in the func posted before, the suspected one called every 300ms: ConsoleWrite("---SX-i:"&$i & "--") While $i < 10 If $i = 1 Then $iRet = _CommSendByteArray(DllStructGetPtr($tBinData), $iNumbytes, 1) ConsoleWrite("- iret:"&$iRet & " --") If @error = 1 Or $iRet = -1 Then AdlibUnRegister("_ControlloManuale1") ConsoleWrite("!Error: " & @error & " iRet:" & $iRet & @CRLF) $ErrLog &= _NowCalc() & " " & "ERR SX16 SendByteArray" & @CRLF _Commcloseport() Sleep(2000) _CommSetPort($CMPort, $sportSetError, $CmBoBaud, $CmboDataBits, $CmBoParity, $CmBoStop, $setflow, $RTSMode, $DTRMode) AdlibRegister("_ControlloManuale1", 300) EndIf EndIf $instr &= Hex(_CommReadByte(),2) ConsoleWrite("----instr:"& $instr & " i:" &$i& @CRLF) Sleep(20) $i += 1 WEnd the last log before crash: ---SX-i:1--- iret:1 ------instr:00 i:1 ----instr:0055 i:2 ----instr:005501 i:3 ----instr:00550101 i:4 ----instr:0055010120 i:5 ----instr:005501012000 i:6 ----instr:00550101200024 i:7 ----instr:0055010120002400 i:8 ----instr:005501012000240000 i:9 ---SX-i:1--- iret:1 ------instr:00 i:1 ----instr:0055 i:2 ----instr:005501 i:3 ----instr:00550104 i:4 ----instr:0055010401 i:5 ----instr:005501040100 i:6 ----instr:00550104010000 i:7 ----instr:0055010401000000 i:8 ----instr:005501040100000000 i:9 ---SX-i:1-- and IconTray says the block at line Sleep(20) instead in Scite it hasn't displayed 2*ConsoleWrite before the sleep because has printed only ---SX-i:1-- that it's outside while loop ... So the block should be at line $iRet = _CommSendByteArray like suspected before. Why this func doesn't work well without admin privileges and compatibility mode in W7? Another time I found another block in this func: Func _io($comando) $console = '' $foo = Run('E:\___1-Wire\Domotica\io_ok.exe ' & $comando, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) While 1 $line = StdoutRead($foo) If @error Then ExitLoop EndIf $console = $console & $line WEnd While 1 $line = StderrRead($foo) If @error Then ExitLoop EndIf WEnd Sleep(1000) EndFunc ;==> end _io It calls an exe in C that returns a string. It blocks getting an infinite loop in the 2 while... Again only in W7 especially without admin and XP compatibility mode. Link to comment Share on other sites More sharing options...
Valik Posted November 30, 2011 Share Posted November 30, 2011 (edited) You did several things wrong in your testing. First, never write output when testing a deadlock. Adding I/O can serialize your program on the I/O which may remove or change the location of the problem. Second, your enthusiasm for inserting ConsoleWrite() all over breaks your If @error test. Run the script without all the stupid ConsoleWrite() statements and report which line it is hanging on. Edited November 30, 2011 by Valik Clarity. Link to comment Share on other sites More sharing options...
frank10 Posted November 30, 2011 Author Share Posted November 30, 2011 Ok, another block without any Consolewrite, in the second code of my previous post: ... $line = StdoutRead($foo) If @error Then ... TrayIcon says at this @error Now I'll repeat to see if blocks again at the SX16 func. Link to comment Share on other sites More sharing options...
frank10 Posted December 1, 2011 Author Share Posted December 1, 2011 It blocked again at the Sleep(20) of the other SX16 code I posted. So there are only these two block points. Link to comment Share on other sites More sharing options...
frank10 Posted December 2, 2011 Author Share Posted December 2, 2011 Now, it blocks often also with Scite in compatibility mode... One time the func with stdOutRead didn't returned the string from the external exe, but the script continued anyway. Anyway when the script blocks, the external exe executed from Win console, works well. So it seems not to be a problem of the exe, but of the autoit script not getting stdout from an external Run. Maybe some problem with COM or IO? The fact that trayDebug says it blocks at a Sleep() point what does it mean? What do you think about these breaking points? Link to comment Share on other sites More sharing options...
Valik Posted December 2, 2011 Share Posted December 2, 2011 Your code has a deadlock somewhere due to filling an I/O buffer. What version of AutoIt are you using? A couple of years ago stdout and stderr redirection was re-written so that it shouldn't deadlock even if you never read from the streams (assuming you have tons of memory available). It is still possible for stdin to deadlock. You have not provided all of your code as far as I can tell. Also, as mentioned, you haven't told us what version of AutoIt you are using. Both are very important pieces of information. Link to comment Share on other sites More sharing options...
frank10 Posted December 2, 2011 Author Share Posted December 2, 2011 (edited) I use autoit 3.3.6.1 but I tried also the 3.3.5.6.I tried also the beta 3.3.7.21 but it fails with PacketX call, like I posted here:I made a huge simplification of my script, keeping the main parts and all the IO and COM calls:expandcollapse popup;~ #AutoIt3Wrapper_UseX64=n ;~ #AutoIt3Wrapper_Run_Debug_Mode= Y #include <StaticConstants.au3> #include <ProgressConstants.au3> #include <GUIConstantsEx.au3> #include <INet.au3> #include <Date.au3> #include <ftp.au3> #include <misc.au3> #include <Array.au3> #include <Constants.au3> #include <SQLite.au3> #include <SQLite.dll.au3> #include <IE.au3> #include <string.au3> #include <WinINet.au3> #include <WinAPI.au3> ; per processCalc #include 'CommMG.au3' ;Include the Serial UDF: Opt("TrayIconDebug", 1) Global $Sx16Port = 4, $1_wireSeriale = "8s" ;Internal for the Serial UDF Global $sportSetError = '' ;COM Vars Global $CMPort = $Sx16Port ; Port Global $CmBoBaud = 19200 ; Baud Global $CmboDataBits = 8 ; Data Bits Global $CmBoParity = "none" ; Paritys Global $CmBoStop = 1 ; Stop Global $setflow = 2 ; Flow Global $RTSMode = 1 Global $DTRMode = 1 Global $iWait = 0 ;Start up COM communication local $a = _CommSetPort($CMPort, $sportSetError, $CmBoBaud, $CmboDataBits, $CmBoParity, $CmBoStop, $setflow, $RTSMode, $DTRMode) ;############################################# PacketX ---------- Const $PktXPacketTypePromiscuous = 0x0020 Const $PktXModeCapture = 1 ; # CREATE PACKETX OBJECT # Global $oPktX = ObjCreate("PktX.PacketX") If Not IsObj($oPktX) Then MsgBox(48, "Error", "PacketX could not load the object, reinstall!") $ErrLog &= _NowCalc() & " " & "PacketX could not load the object, reinstall!" & @CRLF Else $EventObject = ObjEvent($oPktX, "PacketX_") EndIf ; # GET THE DEVICE NUMBERS # $deviceno = "" $deviceitem = "" For $i = 1 To $oPktX.Adapters.Count If $oPktX.Adapters($i).IsGood Then $deviceitem = $i $deviceno = $deviceitem & "|" & $deviceno Else MsgBox(48, "Error", "No Valid Network Adaptors was found!") EndIf Next $interno = '' ; Start packet capture _start() AdlibRegister("_ControlloManuale1", 300) ; every 300ms do ; main loop: While 1 If TimerDiff($CounterTimer) > $intervallo Then ; every 5 sec do: _SX16('uscite','','') _LeggiCounter() $CounterTimer = TimerInit() EndIf If Mod(@MIN, 5) = 0 Then ; every 5' do: ; there's another check to avoid more than one call at Mod(@MIN, 5): _io8() _LeggiTemp() ....... _PHP_server("/public/Files/PHP/content.php", $JSONdata,0) EndIf Sleep(300) WEnd Func _io8() $ioA = 0 While (Not IsArray($ioA)) _io($1_wireSeriale & ' a') $ioA = StringSplit($console, ",") While Not (UBound($ioA) = 4) Sleep(100) _io($1_wireSeriale & ' a') $ioA = StringSplit($console, ",") WEnd if Not IsArray($ioA) Then Sleep(1000) WEnd Sleep(1000) $ioB = 0 While (Not IsArray($ioB)) _io($1_wireSeriale & ' b') $ioB = StringSplit($console, ",") While Not (UBound($ioB) = 4) Sleep(100) _io($1_wireSeriale & ' b') $ioB = StringSplit($console, ",") WEnd if Not IsArray($ioB) Then Sleep(1000) WEnd ......... EndFunc ;==>_io8 Func _LeggiCounter() While (Not IsArray($count)) _counter($1_wireSeriale & ' a') $count = StringSplit($console, ",") While Not (UBound($count) = 5) _counter($1_wireSeriale & ' a') $count = StringSplit($console, ",") WEnd WEnd ........... _PHP_server("/public/Files/PHP/content.php", $JSONdata,0) EndFunc ;==>_LeggiCounter Func _LeggiTemp() _temperature($1_wireSeriale & " s f o n c i p x l t m") ; ........... EndFunc ;==>_LeggiTemp Func _temperature($stanze) $console = '' $foo = Run('E:___1-WireDomoticatemperature.exe ' & $stanze, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) While 1 $line = StdoutRead($foo) If @error Then ExitLoop EndIf $console = $console & $line WEnd While 1 $line = StderrRead($foo) If @error Then ExitLoop EndIf WEnd EndFunc ;==>_temperature Func _counter($version) $console = '' $foo = Run('E:___1-WireDomoticacounter.exe ' & $version, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) While 1 $line = StdoutRead($foo) If @error Then ExitLoop EndIf $console = $console & $line WEnd While 1 $line = StderrRead($foo) If @error Then ExitLoop EndIf WEnd EndFunc Func _io($comando) $console = '' $foo = Run('E:___1-WireDomoticaio.exe ' & $comando, @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) While 1 $line = StdoutRead($foo) If @error Then ExitLoop EndIf $console = $console & $line WEnd While 1 $line = StderrRead($foo) If @error Then ExitLoop EndIf WEnd EndFunc Func _ControlloManuale1() _SX16('','','') _ControlloManuale("") EndFunc Func _ControlloManuale($manual) ........ ; check battery status in XP laptop: $structSystemPowerStatus = DllStructCreate("byte ACLineStatus; byte BatteryFlag; byte BatteryLifePercent; byte Reserved1; dword BatteryLifeTime; dword BatteryFullLifeTime") $ret = DllCall("kernel32.dll", "int", "GetSystemPowerStatus", "ptr", DllStructGetPtr($structSystemPowerStatus)) If @error Then Consolewrite("Errore rilevamento gruppo continuità") If $ret <> 0 Then $nOnBattery = DllStructGetData($structSystemPowerStatus, "ACLineStatus") $nBatteryLife = DllStructGetData($structSystemPowerStatus, "BatteryLifePercent") If $nOnBattery == 0 Then if Mod($conteggio, 10) = 0 Then Consolewrite("Il portatile va a batteria, la percentuale Batt=" & $nBatteryLife & @CRLF) Else ;~ MsgBox(48, @ScriptName, "Running on AC-power") EndIf EndIf .............. if (@SEC = 30 or @sec = 0) Then ; async call to server: _PHP_server("/public/Files/PHP/loopOff.php", "" ,1) Sleep(2000) _PHP_server("/public/Files/PHP/contentLoop.php", "" , 1) EndIf EndFunc ;==>_ControlloManuale Func _SX16($comando,$releNum, $releStato) if $comando = "rele" Then AdlibUnRegister("_ControlloManuale1") $bBinData = Binary( "0x66010301" & $releNum & $releStato ) elseif $comando = "uscite" Then AdlibUnRegister("_ControlloManuale1") $bBinData = Binary("0x660104010000") ; leggi 6 uscite Else $bBinData = Binary("0x660101010000") ; leggi 24 ingressi EndIf $iNumbytes = BinaryLen($bBinData) $tBinData = DllStructCreate("byte[" & $iNumbytes & "]") DllStructSetData($tBinData, 1, $bBinData) local $bit = '', $instr = '' local $i = 1 While $i < 10 If $i = 1 Then $iRet = _CommSendByteArray(DllStructGetPtr($tBinData), $iNumbytes, 1) If @error = 1 Or $iRet = -1 Then AdlibUnRegister("_ControlloManuale1") $ErrLog &= _NowCalc() & " " & "ERR SX16 SendByteArray" & @CRLF _Commcloseport() Sleep(2000) _CommSetPort($CMPort, $sportSetError, $CmBoBaud, $CmboDataBits, $CmBoParity, $CmBoStop, $setflow, $RTSMode, $DTRMode) AdlibRegister("_ControlloManuale1", 300) EndIf EndIf $instr &= Hex(_CommReadByte(),2) Sleep(20) $i += 1 WEnd $instr = "0x" & StringMid($instr,StringInStr($instr,"55"),16) ......... if ($comando = "rele" or $comando = "uscite" ) Then AdlibRegister("_ControlloManuale1", 300) EndFunc ;------------------PacketX ---------- Func _start() ; Select network adapter $oPktX.Adapter = $oPktX.Adapters(2) ; W7 Broadcom10/100 $oPktX.Adapters (GUICtrlRead($Combo1)) ; Set the Port to filter $oPktX.Adapter.BPFilter = 'port 5060' ; Capture buffer parameters $oPktX.Adapter.BuffSize = 256 * 1024 ; 256 KB $oPktX.Adapter.BuffMinToCopy = 0 ; Hardware filter and capture mode $oPktX.Adapter.HWFilter = $PktXPacketTypePromiscuous $oPktX.Adapter.Mode = $PktXModeCapture $oPktX.Start EndFunc ;==>_start Func PacketX_OnPacket($oPacket) Dim $sline = '' Local $tline = '' For $bByte In $oPacket.Data If StringLen($sline) >= 48 Then $sline = "" EndIf If $bByte <= Chr(4) Then $tline = $tline & "0" EndIf $sline = $sline & Hex($bByte, 2) & " " $tline = $tline & Hex($bByte, 2) & " " Next If StringLen($sline) > 0 Then Local $wLine = '' Local $hesadecimale = StringSplit($tline, ' ') For $i = 1 To $hesadecimale[0] $wLine &= _HexToString($hesadecimale[$i]) Next .............. EndIf EndFunc ;==>PacketX_OnPacket Func _PHP_server($url,$JSONdata, $async) Local $hInternetOpen, $hInternetConnect, $hHttpOpenRequest, $hHttpSendRequest _WinINet_Startup() If _WinINet_InternetAttemptConnect() Then $hInternetOpen = _WinINet_InternetOpen("Mozilla/5.0 Firefox/3.0.1", $INTERNET_OPEN_TYPE_DIRECT, 0, Default, Default) $hInternetConnect = _WinINet_InternetConnect($hInternetOpen, $INTERNET_SERVICE_HTTP, "www.myServer.com", 0, 0, Default, Default, 0) $type = "Content-Type: application/x-www-form-urlencoded" & @CRLF $agent = "User-Agent: Mozilla/5.0b" & @CRLF $toSend = $type & $agent Local $hHttpOpenRequest = _WinINet_HttpOpenRequest($hInternetConnect, "POST", $url) $toSend &= 'Content-Length: ' & StringLen($JSONdata) if $async = 0 then local $hHttpSendRequest= _WinINet_HttpSendRequest($hHttpOpenRequest, $toSend, StringToBinary($JSONdata) ) Else local $hHttpSendRequest= _WinINet_HttpSendRequestEx($hHttpOpenRequest, $toSend, StringToBinary($JSONdata) ) EndIf $manual = '' $vReceived = Binary("") Do $vReceived &= _WinINet_InternetReadFile($hHttpOpenRequest, 1024) Until @error <> 0 Or Not @extended $vReceived = BinaryToString($vReceived) ........... EndIf _WinINet_InternetCloseHandle($hInternetOpen) EndFunc ;==>_PHP_serverI have COM calls to a serial port with CommMG through an USB adapter every 300ms,I call an external exe that check sensors through a 1-wire network through an USB-serial-1-wire adapter every 5sec using stdOutRead to get a returning string,finally some similar call to exe every 5min.I send some little data every 5sec to a PHP server, too with Wininet.I used AdLibRegister to make independent cycle on a board every 300ms, while the other board is called from the main while loop.I made a func in adLibRegister that calls two other funcs, I don't know if it's possible to call them directly in a adLibRegister line...In every case, if there is this filling buffer, why doesn't block on old laptop with XP?EDIT: I never saw Autoit and Scite growing more than 90MB in TaskManager, with all testing Consolewrites, I have 6GB RAM, anyway. Edited December 2, 2011 by frank10 Link to comment Share on other sites More sharing options...
Valik Posted December 2, 2011 Share Posted December 2, 2011 I made a huge simplification of my script, keeping the main parts and all the IO and COM calls:It's still not very simple. I wonder how many times you must write the same Run()-StdoutRead()-StdErrRead() sequence before you think to factor that logic out into a function, for example.I have COM calls to a serial port with CommMG through an USB adapter every 300ms,The CommMG code is not present. To me that seems the most likely place for an error to be.In every case, if there is this filling buffer, why doesn't block on old laptop with XP?The are numerous reasons. A few are the OS may have a different buffer size or may not buffer at all. The hardware is different. The drivers are different. Link to comment Share on other sites More sharing options...
frank10 Posted December 3, 2011 Author Share Posted December 3, 2011 (edited) CommMG:expandcollapse popup#include-once Opt("mustdeclarevars", 1) ;testing only #cs UDF for commg.dll V1.0 Replaces mgcomm.au3 #ce Const $sUDFVersion = 'CommMG.au3 V2.85' Global $mgdebug = False #cs Version 2.1.1 Added missing declarations which caused problems in scripts using Opt("MustDeclareVars",1) - thanks to Hannes Version 2.1 Thanks to jps1x2 for the read/send bte array incentive and testing. Version 2.0.2 beta changed readbytearray so returns no of bytes read Version 2.0.1 beta added _CommSendByteArray and _CommReadByteArray Version 2.0 - added _CommSwitch. Can now use up to 4 ports. Version 2.2 - add rts, dtr to setport added option for flow control = NONE to _CommSetPort version 2.3 use commg.dll v2.3 which allows any baud rate up to 256000. Version 2.4 added setTimeouts, SetXonXoffProperties Version 2.5 add _CommsetTimeouts, _CommSetXonXoffProperties Version 2.6 added _CommSetRTS, _CommSetDTR change switch so up to 50 com ports can be open at a time Version 2.7 added _CommSetDllPath Version 2.8 17th April 2010 add GetLineStates for CTS, DSR, Ring Indicator and DCD Corrected return of functions _CommSetRTS and _CommSetDTR to be -1 on error Version 2.81 add sleep(20) in CommGetLine to reduce CPU usage. Thanks to jimg. Version 2.82 Correct error in _ComSetPort which could prevent _CommSetDllPath working. Version 2.83 add function _CommSetBufferSizes added ComGetPortNames around these versions but not sure when. Version 2.84 modify ReadByte to allow for error, probable cause is a timeout triggered by values set in _CommSetTimeouts Removed CloseDll in _CommClosePort so one port can be closed and others still used. Version 2.85 Fix error in _CommClosePort AutoIt Version: 3.2.3++ Language: English Description: Functions for serial comms using commg2_4.dll or later Works with COM ports, USB to Serial converters, Serial to RS424 etc Functions available: _CommGetVersion _CommSetDllPath _CommListPorts _ComGetPortNames _CommSetPort _CommPortConnection _CommClearOutputBuffer _CommClearInputBuffer _CommGetInputcount _CommGetOutputcount _CommSendString _CommGetString _CommGetLine _CommReadByte _CommReadChar _CommSendByte _CommSendBreak; not tested!!!!!!!!!! _CommCloseport _CommSwitch _CommSendByteArray _CommReadByteArray _CommSetTimeouts _CommSetXonXoffProperties _CommSetRTS _CommSetDTR _CommGetLineStates _CommSetBufferSizes Author: Martin Gibson #ce #include-once Global $fPortOpen = False Global $hDll Global $DLLNAME = 'commg.dll' ;=============================================================================== ; ; Function Name: _CommSetDllPath($sFullPath) ; Description: Sets full path to th edll so that it can be in any location. ; ; Parameters: $sFullPath - Full path to the commg.dll e.g. "C:COMMScommg.dll" ; Returns; on success 1 ; on error -1 if full path does not exist ;=============================================================================== Func _CommSetDllPath($sFullPath) If Not FileExists($sFullPath) Then Return -1 $DLLNAME = $sFullPath Return 1 EndFunc ;==>_CommSetDllPath ;=============================================================================== ; ; Function Name: _CommListPorts($iReturnType=1) ; Description: Gets the list of available ports seperated by '|' or as an array ; ; Parameters: $iReturnType - integer:if $iReturnType = 1 then return a string with the list of COM ports seperated by '|' ; if $iReturnType <> 1 then return an array of strings, with element [0] holding the number of COM ports ; Returns; on success - a string eg 'COM1|COM8', or array eg ['2','COM1','COM2'] ; on failure - an empty string and @error set to 1 if dll could not list any ports ; @error set to 2 id dll not open and couldn't be opened ;=============================================================================== Func _CommListPorts($iReturnType = 1) Local $vDllAns, $lpres If Not $fPortOpen Then $hDll = DllOpen($DLLNAME) If $hDll = -1 Then SetError(2) ;$sErr = 'Failed to open commg2_2.dll' Return 0;failed EndIf $fPortOpen = True EndIf If $fPortOpen Then $vDllAns = DllCall($hDll, 'str', 'ListPorts') If @error = 1 Then SetError(1) Return '' Else ;mgdebugCW($vDllAns[0] & @CRLF) If $iReturnType = 1 Then Return $vDllAns[0] Else Return StringSplit($vDllAns[0], '|') EndIf EndIf Else SetError(1) Return '' EndIf EndFunc ;==>_CommListPorts ;=============================================================================== ; ; Function Name: _Commgetversion($iType = 1) ; Description: Gets the version of the dll if $iType = 1 ; Or the version of this UDF if $iType = 2 ; Parameters: $iType - integer: = 1 to reurn the commg2_2.dll version ; = 2 to return the UDF version ; Returns; on success - a string eg 'V1.3' ; on failure - an empty string and @error set to 1 ;=============================================================================== Func _CommGetVersion($iType = 1) Local $vDllAns If $iType = 2 Then Return $sUDFVersion If $fPortOpen Then $vDllAns = DllCall($hDll, 'str', 'Version') If @error = 1 Then SetError(1) mgdebugCW('error in get version' & @CRLF) Return '' Else ;mgdebugCW('length of version is ' & stringlen($vDllAns[0]) & @CRLF) Return $vDllAns[0] EndIf Else $vDllAns = DllCall($DLLNAME, 'str', 'Version') If @error = 1 Then SetError(1) mgdebugCW('error in get version' & @CRLF) Return '' Else ;mgdebugCW('length of version is ' & stringlen($vDllAns[0]) & @CRLF) Return $vDllAns[0] EndIf EndIf EndFunc ;==>_CommGetVersion ;=============================================================================== ; ; Function Name: _CommSwitch($channel) ;switches functions to operate on channel 1, 2, 3 to 50 ;returns on succes the channel switched to ie 1 or 2 ; on failure -1 ;Remarks on start up of script channel 1 is selected, so if you only need one COM port ; you don't need to use _CommSwitch ; each channel needs to be set up with _CommSetPort ; The same COM port cannot be used on more than one channel. ;When switch is used the first time on a channel number that port will be inactive ; and the port name will be '' (an empty string) until it is set with _CommSetport. ;The exception is that on creation channel 1 is always created and used as the ;port so switch is not needed unless more than one port is used. ; The channel number is not related to the COM port number, so channel 1 can ; be set to use COM2 and channel 4 can be set to use COM1 or any available port. ;Any channel number in the range 1 - 50 can be used, so it is possible to use ; the same channel number as the port number, ie switch(21) switches to COM21 ;====================================================================================== Func _CommSwitch($channel) Local $vDllAns #cs remove section after fixing? comclose in dll If Not $fPortOpen Then SetError(1) Return 0 EndIf #ce If $channel > 50 Then Return -1 $vDllAns = DllCall($hDll, 'int', 'switch', 'int', $channel) If @error <> 0 Then SetError(1) Return -1 Else mgdebugCW("COM port selected now is " & _CommPortConnection() & @CRLF) Return $vDllAns[0] EndIf EndFunc ;==>_CommSwitch ;=========================================================================================================== ; ; Function Name: _CommSetport($iPort,ByRef $sErr,$iBaud=9600,$iBits=8,$ipar=0,$iStop=1,$iFlow=0,$RTSMode = 0,$DTRMode = 0) ; Description: Initialises the port and sets the parameters ; Parameters: $iPort - integer = the port or COM number to set. Allowed values are 1 or higher. ; NB WIndows refers To COM10 Or higher`as .com10 but only use the number 10, 11 etc ; $sErr - string: the string to hold an error message if func fails. ; $iBaud - integer: the baud rate required. With commg.dll v2.3 and later any value allowed up to 256000. ; With v2.4 any value?? ; If using commg.dll before V2.3 then only allowed values are one of ; 50, 75, 110, 150, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600, 10400, ; 14400, 15625, 19200, 28800, 38400, 56000, 57600, 115200, 128000, 256000 ; $iBits - integer: number of bits in code to be transmitted ; $iParity - integer: 0=None,1=Odd,2=Even,3=Mark,4=Space ; $iStop - integer: number of stop bits, 1=1 stop bit 2 = 2 stop bits, 15 = 1.5 stop bits ; $iFlow - integer: 0 sets hardware flow control, ; 1 sets XON XOFF control, ; 2 sets NONE i.e. no flow control. ; $RTSMode 0= turns on the RTS line when the device is opened and leaves it on ; 1= RTS handshaking. The driver raises the RTS line when the "type-ahead" (input) buffer is less than one-half full and lowers the RTS line when the buffer is more than three-quarters full. ; 2 = the RTS line will be high if bytes are available for transmission. After all buffered bytes have been sent, the RTS line will be low. ; 3 = turns off the RTS line when the port is opened and leaves it off ; $DTRMode 0 = turns on the DTR line when the port is opened and leaves it on ; 1 = enables DTR handshaking ; 2 = disables the DTR line when the device is opened and leaves it disabled. ; Returns; on success - returns 1 and sets $sErr to '' ; on failure - returns 0 and with the error message in $sErr, and sets @error as follows ; @error meaning error with ; 1 dll call failed ; 2 dll was not open and could not be opened ; -1 $iBaud ; -2 $iStop ; -4 $iBits ; -8 $iPort = 0 not allowed ; -16 $iPort not found ; -32 $iPort access denied (in use?) ; -64 unknown error ;Remarks You cannot set the same COM port on more than one channel ;=========================================================================================================== Func _CommSetPort($iPort, ByRef $sErr, $iBaud = 9600, $iBits = 8, $iPar = 0, $iStop = 1, $iFlow = 0, $RTSMode = 0, $DTRMode = 0) Local $vDllAns $sErr = '' mgdebugCW("$fPortOpen = " & $fPortOpen & @CRLF) If Not $fPortOpen Then $hDll = DllOpen($DLLNAME) If $hDll = -1 Then SetError(2) $sErr = 'Failed to open commg.dll' Return 0;failed EndIf $fPortOpen = True EndIf mgdebugCW('port = ' & $iPort & ', baud = ' & $iBaud & ', bits = ' & $iBits & ', par = ' & $iPar & ', stop = ' & $iStop & ', flow = ' & $iFlow & @CRLF) $vDllAns = DllCall($hDll, 'int', 'SetPort', 'int', $iPort, 'int', $iBaud, 'int', $iBits, 'int', $iPar, 'int', $iStop, 'int', $iFlow, 'int', $RTSMode, 'int', $DTRMode) If @error <> 0 Then $sErr = 'dll SetPort call failed' SetError(1) Return 0 EndIf If $vDllAns[0] < 0 Then SetError($vDllAns[0]) Switch $vDllAns[0] Case -1 $sErr = 'undefined baud rate' Case -2 $sErr = 'undefined stop bit number' Case -4 $sErr = 'undefined data size' Case -8 $sErr = 'port 0 not allowed' Case -16 $sErr = 'port does not exist' Case -32 $sErr = 'access denied, maybe port already in use' Case -64 $sErr = 'unknown error accessing port' EndSwitch Return 0 Else Return 1 EndIf EndFunc ;==>_CommSetPort ;=================================================================================== ; ; Function Name: _CommPortConnection() ; Description: Gets the port connected to the selected channel - see _CommSwitch ; Parameters: None ; Returns; on success - a string eg 'COM5' ; on failure - an empty string and @error set to the rerror set by DllCall ; Remarks - Can be used to verify the port is connected ;==================================================================================== Func _CommPortConnection() Local $vDllAns If Not $fPortOpen Then SetError(1) Return 0 EndIf $vDllAns = DllCall($hDll, 'str', 'Connection');reply is port eg COM8 If @error <> 0 Then SetError(@error) Return '' Else Return $vDllAns[0] EndIf EndFunc ;==>_CommPortConnection ;===================================================================================== ; ; Function Name: _CommSendString($sMGString,$iWaitComplete=0) ; Description: Sends a string to the connected port on the currently selected channel ; Parameters: $sMGString: the string to send sent without any extra CR or LF added. ; $iWaitComplete- integer:0 = do not wait till string sent ; 1 = wait till sent ; Returns: always 1 ; on success- @error set to 0 ; on failure - @error set to the error returned from DllCall ;====================================================================================== Func _CommSendString($sMGString, $iWaitComplete = 0) ;sends $sMGString on the currently open port ;returns 1 if ok, returns 0 if port not open/active Local $vDllAns If Not $fPortOpen Then SetError(1) Return 0 EndIf If $sMGString = '' Then Return mgdebugCW("pre sendstring " & @CRLF) $vDllAns = DllCall($hDll, 'int', 'SendString', 'str', $sMGString, 'int', $iWaitComplete) If @error <> 0 Then mgdebugCW("past sendstring(1)" & @CRLF) SetError(@error) Return '' Else mgdebugCW("past sendstring(2)" & @CRLF) Return $vDllAns[0] EndIf EndFunc ;==>_CommSendString ;================================================================================ ; ; Function Name: _CommGetstring() ; Description: Get whatever characters are available received by the port for the selected channel ; Parameters: none ; Returns: on success the string and @error is 0 ; if input buffer empty then empty string returned ; on failure an empty string and @error set to the error set by DllCall ; Notes: Use _CommGetLine to get a whole line treminated by @CR or a defined character. ;================================================================================= Func _Commgetstring() ;get a string NB could be part of a line depending on what is in buffer Local $vDllAns If Not $fPortOpen Then SetError(1) Return 0 EndIf ;$sStr1 = '' ;$vDllAns = DllCall($hDll,'str','GetByte') $vDllAns = DllCall($hDll, 'str', 'GetString') If @error <> 0 Then SetError(1) mgdebugCW('error in _commgetstring' & @CRLF) Return '' EndIf Return $vDllAns[0] EndFunc ;==>_Commgetstring ;==================================================================================== ; ; Function Name: _CommGetLine($EndChar = @CR,$maxlen = 10000, $maxtime = 10000) ; Description: Get a string ending in $EndChar ; Parameters: $EndChar the character to indicate the end of the string to return. ; The $EndChar character is included in the return string. ; $MaxLen - integer: the maximum length of a string before ; returning even if $linEnd not received ; If $maxlen is 0 then there is no max number of characters ; $maxtime - integer:the maximum time in mS to wait for the $EndChar before ; returning even if $linEnd not received. ; If $maxtime is 0 then there is no max time to wait ; ; Returns: on success the string and @error is 0 ; If $maxlen characters received without the $lineEnd character, then these ; characters are returned and @error is set To -1. ; If $maxtime passes without receiving the $lineEnd character, then the characters ; received so far are returned and @error is set To -2. ; on failure returns any characters received and sets @error to 1 ;====================================================================================== Func _CommGetLine($sEndChar = @CR, $maxlen = 0, $maxtime = 0) Local $vDllAns, $sLineRet, $sStr1, $waited, $sNextChar, $iSaveErr If Not $fPortOpen Then SetError(1) Return 0 EndIf $sStr1 = '' $waited = TimerInit() While 1;stringinstr($sStr1,$EndChar) = 0 If TimerDiff($waited) > $maxtime And $maxtime > 0 Then SetError(-2) Return $sStr1 EndIf If StringLen($sStr1) >= $maxlen And $maxlen > 0 Then SetError(-1) Return $sStr1 EndIf ;$ic = _CommGetInputCount() $sNextChar = _CommReadChar() $iSaveErr = @error If $iSaveErr = 0 And $sNextChar <> '' Then $sStr1 = $sStr1 & $sNextChar ;mgdebugCW($sStr1 & @CRLF) If $sNextChar = $sEndChar Then ExitLoop EndIf If $iSaveErr <> 0 And $iSaveErr <> 3 Then SetError(1) Return $sStr1 EndIf WEnd Return $sStr1 EndFunc ;==>_CommGetLine ;============================================================================ ; ; Function Name: _CommGetInputCount() ; Description: Get the number of characters available to be read from the port. ; Parameters: none ; Returns: on success a string conversion of the number of characters.(eg '0', '26') ; on failure returns an empty string and sets @error to 1 ;=============================================================================== Func _CommGetInputCount() Local $vDllAns If Not $fPortOpen Then SetError(1) Return 0 EndIf $vDllAns = DllCall($hDll, 'str', 'GetInputCount') If @error <> 0 Then SetError(1) Return 0 Else Return $vDllAns[0] EndIf EndFunc ;==>_CommGetInputCount ;============================================================================ ; ; Function Name: _CommGetOutputCount() ; Description: Get the number of characters waiting to be sent from the port. ; Parameters: none ; Returns: on success a string conversion of the number of characters.(eg '0', '26') ; on failure returns an empty string and sets @error to 1 ;=============================================================================== Func _CommGetOutputCount() Local $vDllAns If Not $fPortOpen Then SetError(1) Return 0 EndIf $vDllAns = DllCall($hDll, 'str', 'GetOutputCount') If @error <> 0 Then SetError(1) Return '' Else Return $vDllAns[0] EndIf EndFunc ;==>_CommGetOutputCount ;================================================================================================ ; ; Function Name: _CommReadByte($wait = 0) ; Description: Reads the byte as a string ; Parameters: $wait:integer if 0 then if no data to read then return -1 and set @error to 1 ; if <> 0 then does not return until a byte has been read ; Returns: on success a string conversion of the value of the byte read.(eg '0', '20') ; on failure ; if $wait is 0 returns an string and sets @error to 1 if no data to read ; if $wait is not 0 returns a string containing imnformation on the $error if know ; and sets @error to 1. ; Returns empty string and sets @error to 2 ifDllCall failed ; ;;NB could hang if nothing rec'd when wait is <> 0 ;================================================================================================== Func _CommReadByte($wait = 0) Local $iCount, $vDllAns If Not $fPortOpen Then SetError(1) Return 0 EndIf If Not $wait Then $iCount = _CommGetInputCount() If $iCount = 0 Then SetError(1) Return '' EndIf EndIf $vDllAns = DllCall($hDll, 'str', 'GetByte') If @error <> 0 Then SetError(2) Return '' EndIf If StringLen($vDllAns[0]) > 1 Then Return SetError(3, 0, $vDllAns[0]) EndIf Return $vDllAns[0] EndFunc ;==>_CommReadByte ;============================================================================ ; ; Function Name: _CommReadChar($wait = 0) ; Description: Reads the next Character as a string ; Parameters: $wait:integer if 0 then if no data to read then return -1 and set @error to 1 ; if <> 0 then does not return until a byte has been read ; Returns: on success a string of 1 character ; on failure returns empty string and sets @error to 1 ; ; ;;NB could hang if nothing rec'd when wait is <> 0 ;=============================================================================== Func _CommReadChar($wait = 0) Local $sChar, $iErr If Not $fPortOpen Then SetError(1) Return 0 EndIf $sChar = _CommReadByte($wait) $iErr = @error If $iErr > 2 Then SetError(1) Return '' EndIf If $iErr == 0 Then Return Chr(Execute($sChar)) EndFunc ;==>_CommReadChar ;============================================================================ ; Function Name: SendByte($byte,$iWaitComplete=0) ; Description: Sends the byte value of $byte. $byte must be in range 0 to 255 ; Parameters: $byte the byte to send. ; $iWaitComplete - integer: if 0 then functions returns without ; waiting for byte to be sent ; If <> 0 then waits till byte sent. ; Returns: on success returns 1 ; on failure returns -1 and sets @error to 1 ; ;;NB could hang if byte cannot be sent and $iWaitComplete <> 0 ;=============================================================================== Func _CommSendByte($byte, $iWaitComplete = 0) Local $vDllAns If Not $fPortOpen Then SetError(1) Return 0 EndIf $vDllAns = DllCall($hDll, 'int', 'SendByte', 'int', $byte, 'int', $iWaitComplete) If @error <> 0 Then SetError(1) Return -1 Else Return $vDllAns[0] EndIf EndFunc ;==>_CommSendByte ;=============================================================================== ; Function Name: _CommSendByteArray($pAddr,$iNum,$iWait) ; Description: Sends the bytes from address $pAddress ; Parameters: $iNum the number of bytes to send. ; $iWaitComplete - integer: if 0 then functions returns without ; waiting for bytes to be sent ; if <> 0 then waits until all bytes are sent. ; Returns: on success returns 1 ; on failure returns -1 and sets @error to 1 ; ;;NB could hang if byte cannot be sent and $iWaitComplete <> 0 ; could lose data if you send more bytes than the size of the outbuffer. ; the output buffer size is 2048 ;=============================================================================== Func _CommSendByteArray($pAddr, $iNum, $iWait) If Not $fPortOpen Then SetError(1) Return 0 EndIf Local $vDllAns = DllCall($hDll, 'int', 'SendByteArray', 'ptr', $pAddr, 'int', $iNum, 'int', $iWait) If @error <> 0 Or $vDllAns[0] = -1 Then SetError(1) Return -1 Else Return $vDllAns[0] EndIf EndFunc ;==>_CommSendByteArray ;==================================================================================== ; Function Name: _CommReadByteArray($pAddr,$iNum,$iWait) ; ; Description: Reads bytes and writes them to memory starting at address $pAddress ; Parameters: $iNum the number of bytes to read. ; $iWaitComplete - integer: if 0 then the functions returns ; with the available bytes up to $iNum. ; if 1 then waits until the $iNum bytes received. ; Returns: on success returns the Number of bytes read. ; on failure returns -1 and sets @error to 1 ; ;;NB could hang if bytes are not received and $iWaitComplete <> 0 ; the input buffer size is 4096 ;==================================================================================== Func _CommReadByteArray($pAddr, $iNum, $iWait) If Not $fPortOpen Then SetError(1) Return 0 EndIf Local $vDllAns = DllCall($hDll, 'int', 'ReadByteArray', 'ptr', $pAddr, 'int', $iNum, 'int', $iWait) If @error <> 0 Or $vDllAns[0] = -1 Then SetError(1) Return -1 Else Return $vDllAns[0] EndIf EndFunc ;==>_CommReadByteArray ;=============================================================================== ; Function Name: ClearOutputBuffer() ; Description: Clears any characters in the out put queue5 ; Parameters: none ; Returns: on success returns 1 ; on failure returns -1 and sets @error to 1 ; ;=============================================================================== Func _CommClearOutputBuffer() If Not $fPortOpen Then SetError(1) Return 0 EndIf Local $vDllAns = DllCall($hDll, 'int', 'ClearOutputBuffer') EndFunc ;==>_CommClearOutputBuffer Func _CommClearInputBuffer() If Not $fPortOpen Then SetError(1) Return 0 EndIf Local $vDllAns = DllCall($hDll, 'int', 'ClearInputBuffer') If @error <> 0 Then Return -1 Else Return 1 EndIf EndFunc ;==>_CommClearInputBuffer ;=============================================================================== ; Function Name: ClosePort()@@@@@@@@@to be improved or replaced. Should have parameter for channel to close and new fn for closedown ; Parameters ; TODO ?? $fAll if set to true or non zero then ; Description: closes currently selected port ; Remarks: ; ; Parameters: none ; Returns: no return value ;=============================================================================== Func _CommClosePort($fAll = false) mgdebugCW("Closing port" & @CRLF) If Not $fPortOpen Then SetError(1) Return 0 EndIf _CommClearOutputBuffer() _CommClearInputBuffer() DllCall($hDll, 'int', 'CloseDown') If @error <> 0 Then ConsoleWrite("Error closing dll" & @CRLF) If $fAll Then mgdebugCW("Closing port step 2" & @CRLF) DllClose($hDll) mgdebugCW("Closing port step 3" & @CRLF) $fPortOpen = False EndIf EndFunc ;==>_CommClosePort ;================================================================================================ ; Function Name: SendBreak($iDowTime,$iUpTime) ; NB Simulates the break signal used by some equipment to indicate the start of a sequence ; Not tested so might Not work. Any feedback welcome - PM martin on Autoit forum ; Description: sets the TX line low for $iDowTime, then sets it high for $iUpTime ; Parameters: $iDowTime - integer: the number of ms to hold the TX line down ; $iUpTime - integer: the number of ms to hold the line up for before returning ; if $iDowTime or $iUpTime is zero then does nothing and returns ; Returns: on success returns 1 ; on failure returns 0 and sets @error to ; = 1 if one of params is zero ; = 2 1 unable to use the DLL file, ; = 3 unknown "return type" from dll ; = 4 "function" not found in the DLL file. ; Notes : Not tested! ;================================================================================================ Func _CommSendBreak($iDowTime, $iUpTime);requirescommg2_2.dllv2.0 or later Local $vDllAns If $iDowTime = 0 Or $iUpTime = 0 Then SetError(1) Return 0 EndIf If Not $fPortOpen Then SetError(1) Return 0 EndIf $vDllAns = DllCall($hDll, 'int', 'SendBreak', 'int', $iDowTime, 'int', $iUpTime) If @error <> 0 Then SetError(@error + 1) Return 0 Else ;mgdebugCW('done setbreak' & @CRLF) Return 1;success EndIf EndFunc ;==>_CommSendBreak ;=========== _CommSetBufferSizes ======================================================================================================== ; Description: Sets the buffer sizes for the current channel ;Parameters - $InputLen - the maximum number of bytes which can be received and waiting to be read ; - $OutPutLen - the number of bytes which can be qued waiting to be transmitted; ;Return 1 on success ; 0 on failure ;============================================================================================================================================================= Func _CommSetBufferSizes($InPutLen, $OututLen = 2048) Local $vDllAns = DllCall($hDll, 'int', 'SetBufSizes', 'int', $InPutLen, 'int', $OututLen) If @error <> 0 Then SetError(@error + 1) Return 0 Else Return $vDllAns[0] EndIf EndFunc ;==>_CommSetBufferSizes ;=========== _CommSetTimeouts ======================================================================================================== ; Description: Sets the timeouts for the current channel ;Parameters - ReadInt - maximum time allowed to elapse between the arrival of two characters ; - ReadMult - multiplier used to calculate the total timeout period for read operations. ; For each read operation, this value is multiplied by the requested number of bytes to be read. ; - ReadConst - constant used to calculate the total timeout period for read operations. ; For each read operation, this value is added to the product of the ReadMultiplier member and the requested number of bytes. ; - WriteMult - multiplier used to calculate the total timeout period for write operations. ; For each write operation, this value is multiplied by the number of bytes to be written. ; - WriteConst - constant used to calculate the total time-out period for write operations. ; For each write operation, this value is added to the product of the WriteMultiplier member and the number of bytes to be written. ; if a parameter is set to 0 it means that timeout will not be used. All values are at zero when a port is opened. ; Return 1 on success ; 0 on failure ;============================================================================================================================================================= Func _CommSetTimeouts($ReadInt = 0, $ReadMult = 0, $ReadConst = 0, $WriteMult = 0, $WriteConst = 0) Local $vDllAns If Not $fPortOpen Then SetError(1) Return 0 EndIf $vDllAns = DllCall($hDll, 'int', 'SetTimeouts', 'int', $ReadInt, 'int', $ReadMult, 'int', $ReadConst, 'int', $WriteMult, 'int', $WriteConst) If @error <> 0 Then SetError(@error + 1) Return 0 Else Return $vDllAns[0] EndIf EndFunc ;==>_CommSetTimeouts ;====================== SetXonXoffProperties ======================================================================= ; Description: Set the values used for the XON and XOFF characters, and when these charactyers are to be transmitted ; Parameters - $XonChar - the ASCII code for the character to be sent to indicate the port is ready to receive ; - $XoffChar - the ASCII code fo rthe character to be sent to stop receiving ; - $XonStart - when the number of characters in the input buffer falls below this value the XonChar will be sent ; - $XoffStop - when the number of bytes free in the input buffer falls below this value the XoffChar will be sent ;When a port is opened the values are as the defaults for the function. ;Return - on success 1 ; - on error 0 if error making dllcall and @error set to 1 ; -1 illegal XonChar value ; -2 illegal XoffChar value ; Func _CommSetXonXoffProperties($XonChar = 0x11, $XoffChar = 0x13, $XonStart = 0, $XoffStop = 0) Local $vDllAns If $XonChar > 255 Or $XonChar < 0 Then Return -1 If $XoffChar > 255 Or $XoffChar < 0 Then Return -2 $vDllAns = DllCall($hDll, 'int', 'SetXonXoffProperties', 'byte', $XonChar, 'byte', $XoffChar, 'int', $XonStart, 'int', $XoffStop) If @error <> 0 Then SetError(@error + 1) Return 0 Else Return $vDllAns[0] EndIf EndFunc ;==>_CommSetXonXoffProperties Func mgdebugCW($sDB) If Not $mgdebug Then Return ConsoleWrite($sDB) EndFunc ;==>mgdebugCW ;=================================================================================== ; ; Function Name: _CommSetRTS() ; Description: Sets or restets the RTS signal for to the selected channel - see _CommSwitch ; Parameters: $iSet = 1 to set 0 to reset ; Returns; 1 on success ; on failure -1 and @error set to 1 ; Notes Only works if flow control is set to NONE or XON/XOFF. Ie not for hardware handshaking. ;==================================================================================== Func _CommSetRTS($iSet) Local $vDllAns If Not $fPortOpen Then SetError(1) Return -1 EndIf $vDllAns = DllCall($hDll, 'int', 'SetRTS', 'int', $iSet) If @error <> 0 Then SetError(1) Return -1 Else Return 1 EndIf EndFunc ;==>_CommSetRTS ;=================================================================================== ; ; Function Name: _CommSetDTR() ; Description: Sets or restets the DTR signal for to the selected channel - see _CommSwitch ; Parameters: $iSet = 1 to set 0 to reset ; Returns; 1 on success ; on failure -1 and @error set to 1 ; Notes Only works if flow control is set to NONE or XON/XOFF. Ie not for hardware handshaking. ;==================================================================================== Func _CommSetDTR($iSet) Local $vDllAns If Not $fPortOpen Then SetError(1) Return -1 EndIf $vDllAns = DllCall($hDll, 'int', 'SetDTR', 'int', $iSet) If @error <> 0 Then SetError(1) Return -1 Else Return 1 EndIf EndFunc ;==>_CommSetDTR ;=================================================================================== ; ; Function Name: _CommGetLIneStates() ; Description: Gets the states of 4 signals ; Parameters: none ; Returns; on success ; returns an array with 4 elements giving the state of the lines CTS, DSR, Ring Indicator and DCD ; in that order. Value True = ON, value False = OFF ; on failure ; returns -1 and @error set to 1 ;==================================================================================== Func _CommGetLineStates() Local $vDllAns Local $iL, $aStates[4] If Not $fPortOpen Then SetError(1) Return -1 EndIf $vDllAns = DllCall($hDll, 'int', 'GetLineStates') If @error <> 0 Then SetError(1) Return -1 EndIf ConsoleWrite($vDllAns[0] & @CRLF) For $iL = 0 To 3 $aStates[$iL] = BitAND($vDllAns[0], 2 ^ $iL) <> 0 Next Return $aStates EndFunc ;==>_CommGetLineStates ; ===================================================================================================================== ; Name........................: _ComGetPortNames ; Description ................: Lists all com ports or a single com port and the names to a 2D array ; Syntax......................: _GetComPorts($sComPort = 0) ; Parameters .................: $sComPort - Either 0 or "" for all ports or a number for a particular port, eg 12 or a string "COM12" ; Return on success ..........: an array (size depends on $sComPort) ; Return on Failure ..........: an empty string "" and sets @error to ; -1 incorrect parameter ; 1 no COM Ports found ; 2 specified COM port not found. ; Author .....................: funkey, 2010, Nov 29th ; Modified....................: by martin and renamed from _GetComPorts to _ComGetPortNames, 14th December 2010 ; Remarks ....................: ; Related ....................: ; Link to original function...: http://www.autoitscript.com/forum/topic/122663-getcomports/page__view__findpost__p__851620 ; Example ....................: Yes see below ; ; ======================================================================================================================== Func _ComGetPortNames($sComPort = "") Local $objWMIService, $colItems, $stempName, $aTemp, $sRet, $iCount If IsInt($sComPort) Then If $sComPort = 0 Then $sComPort = "" Else $sComPort = "COM" & $sComPort EndIf EndIf If $sComPort <> "" And Not StringIsInt(StringReplace($sComPort, "COM", "")) Then Return SetError(-1, 0, "") $objWMIService = ObjGet("winmgmts:localhostrootCIMV2") $colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_PnPEntity WHERE Name LIKE '%(COM%" & StringReplace($sComPort, "COM", "") & ")'", "WQL", 48) For $objItem In $colItems $sRet &= $objItem.Name & @CR Next If $sRet = "" Then Return SetError(1, 0, "") If $sComPort <> "" And Not StringInStr($sRet, "(" & $sComPort & ")") Then Return SetError(2, 0, "") $aTemp = StringSplit($sRet, @CR, 2) Dim $aRet[UBound($aTemp) - 1][2] $iCount = 0 For $i = 0 To UBound($aTemp) - 2 $stempName = StringTrimLeft($aTemp[$i], StringInStr($aTemp[$i], "(", 0, -1) - 1);StringTrimRight(, 1) If $sComPort = "" Or $stempName = "(" & $sComPort & ")" Then $aRet[$i][0] = StringTrimRight(StringTrimLeft($stempName, StringInStr($stempName, "(", 0, -1)), 1) $aRet[$i][1] = StringLeft($aTemp[$i], StringInStr($aTemp[$i], "(", 0, -1) - 2) $iCount += 1 EndIf Next ReDim $aRet[$iCount][2] Return $aRet EndFunc ;==>_ComGetPortNames ;======================================================================================================================= #cs =============_ComGetPortNames example start=============================== #include <array.au3> Local $aComPort = _ComGetPortNames() _ArrayDisplay($aComPort) Local $sComPort = _ComGetPortNames("COM1") If @error Then MsgBox(16, "Error " & @error, "No matching COM port found.") Else ConsoleWrite($sComPort & @CRLF) EndIf #ce =============_GetComPorts example end=============================== Opt("MustDeclareVars", 0) Edited December 3, 2011 by frank10 Link to comment Share on other sites More sharing options...
frank10 Posted December 3, 2011 Author Share Posted December 3, 2011 But if there is a filling buffer with the same code that receive always the same quantity of data, why is blocking randomly? It should block everytime after some precise hours, instead it can be within 1hour-1day. the only thing variable could be the StderrRead, due to communication errors in 1-wire network and this could happen randomly, I think. Or maybe the PacketX sniffing port. Link to comment Share on other sites More sharing options...
Valik Posted December 7, 2011 Share Posted December 7, 2011 All I can suggest is start removing pieces of code until the deadlock goes away. Once you isolate what you think is the deadlock then start with that bit of code and see if it locks. If it doesn't start adding code back in until it does. Link to comment Share on other sites More sharing options...
frank10 Posted December 7, 2011 Author Share Posted December 7, 2011 Thank you, I will try to see. At the moment I made a second script to check if the blocking script is blocked, to close the process and running it again. I made a counter variable exposed to the other script in the window title to detect the blocked script. Is there some simpler method to detect if a script is active but blocked? Link to comment Share on other sites More sharing options...
frank10 Posted December 17, 2011 Author Share Posted December 17, 2011 I think I found what is blocking: it's stdOutRead, like it was suspected. I made this test script: #RequireAdmin #include <Constants.au3> Opt("TrayIconDebug", 1) global $foo, $console, $line while 1 Sleep(1000) $console = '' $foo = Run('F:\testSTD.exe ', @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) _checkSTD() if Mod(@min , 1)= 0 and @sec = 0 Then ConsoleWrite(@hour & ":" &@min & @CRLF) WEnd Func _checkSTD() $line = '' While 1 $line = StdoutRead($foo) If @error Then ExitLoop EndIf $console = $console & $line Wend EndFunc my test C code (I attach also the exe): int main(short argc, char **argv) { printf("00111000;00111000;01000000"); } Resuming my rig: W7 64bit on two different pc i7 and i3 autoit 3.3.6.1 running autoit in 32bit with admin and compatibility mode XP SP3 but also without them. it blocks after about 30' . It remains blocked inside the while loop of _checkSTD() because it hasn't received the @error to exit but the external exe was closed. Also the CPU occupation rises at 25% while normally is at 1%. Another time it blocked at the Sleep(1000). the script RAM always grows up while script is running, but it doesn't block at the same amount. Why does the script Ram grow? The filling buffer? Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now