;~ https://www.autoitscript.com/forum/topic/189190-serial-port-udf-com-port-udf/ #TODO CME ERROR (GSM Equipment Related errors) ;~ https://www.micromedia-int.com/en/gsm-2/73-gsm/669-cme-error-gsm-equipment-related-errors ;~ https://m2msupport.net/m2msupport/download-at-command-tester/ #AutoIt3Wrapper_Run_AU3Check=Y #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #cs UDF cfx.au3 by TABALtd September 12, 2008 Serial Communication using kernel32.dll https://www.autoitscript.com/forum/topic/80344-serial-communication-using-kernel32dll V1.0 Uwe Lahni 2008 V2.0 Andrew Calcutt 05/16/2009 Started converting to UDF V2.1 Mikko Keski-Heroja 02/23/2011 UDF is now compatible with Opt("MustDeclareVars",1) and Date.au3. V2.2 Veronesi 04/26/2011 Changed some cosmetics and documentation Add Function to set RTS and to get DCD Status V2.90 Maze 07/01/2017 https://www.autoitscript.com/forum/topic/189190-serial-port-udf-com-port-udf Renamed to: ComUDF.au3 Deleted functions to set RTS and to get DCD Status Only one global variable: $__g_hCOMUDF_Kernel32 (kernel32.dll) Changed COM port format ("COM" plus number, e.g. "COM1") Changed all function names to start with '_COM_' Changed function _COM_OpenPort to accept only one argument $sDefinitions It gives full flexibility while keeping the amount of parameters small Modified and corrected the parameters for DLLCall Each structure and pointer to that structure is manually defined, according to the names provided in the MSDN reference. Each DllCall uses these names. ( While this looks much longer and more complex, it is easier to write new functions in this format and it is also easier to read and check existing functions. It avoids shortcuts therefore can access all data directly from the provided struct. Using shortcuts doesn't allow this and requires access to the correct index of the returned array. (Look for example at the _WinAPI_WriteFile() which has a statement that says "$iWritten = $aResult[4]". It takes a while to verify the "4" is indeed the correct index.) There is only one exception regarding the naming, namely the handle to the serial port named "hComPort" and used instead of "hFile". ) Added a bunch of new functions, removed obsolete functions Added/modified comments and made a few cosmetic changes V2.91 21/09/2020 * refactoring + AU3Check compiliance - mLipok V2.92 23/09/2020 * small changes - mLipok * better error/extended reporting - mLipok * better example - mLipok V2.93 23/09/2020 * Change variables naming to fit AutoIt convention - Danyfirex * Fixed DllCall return check - Danyfirex * changed function name __PurgeComm >> __COM_Purge - Danyfirex * fixed many function to start it works - Danyfirex V2.94 Danyfirex 25/09/2020 * small fixes - Danyfirex V2.95 28/09/2020 * modified function _COM_SendString - now it use _COM_SendBinary instead _COM_SendCharArray - Danyfirex V2.96 28/09/2020 * small refactoring/cleaning - mLipok V2.97 29/09/2020 * fixed function _COM_OpenPort() - open port above 9 (the same problem which @Chuckero posted to the forum in 30/09/2020 as V2.93) - Danyfirex V2.98 01/10/2020 * added function _COM_ListPortDevices - List Port Devices 2DArray - Danyfirex V2.99 17/04/2021 * added global variable $__g_iCOMUDF_HCOMPortCount - Filipp_G $__g_iCOMUDF_HCOMPortCount is the counter of opened serial ports handles is (was) used in _COM_OpenPort() and _COM_ClosePort() functions (comments added to corresponding functions code). The reason: Previously, if multiple serial port were open and in use at the same time in one application, the subsequent operation of closing one port (which were cause the termination of $__g_hCOMUDF_Kernel32 opened dll handle) rendered the other opened ports unusable (receive/send data and close ports operations were unavailable). * modified comments in _COM_SendString() function description ("Note" section deleted as inappropriate) - Filipp_G V3.01 04/10/2023 * headers / descriptions / comments - CleanUp - mLipok * _COM_ListPortDevices() refactored - mLipok * _COM_ListPortDevices() better COM port findings - mLipok #ce ; #INDEX# ======================================================================================================================= ; Title .........: Serial communication UDF ; AutoIt Version : 3.3.14.2 ; Description ...: Serial communication using kernel32.dll (no custom dll needed) ; Authors........: Uwe Lahni, Andrew Calcutt, Mikko Keski-Heroja, Veronesi, Maze, Danyfirex, mLipok, Filipp_G ; Dll ...........: kernel32.dll ; =============================================================================================================================== ; #VARIABLES# =================================================================================================================== Global $__g_hCOMUDF_Kernel32, $__g_iCOMUDF_HCOMPortCount = 0 ; =============================================================================================================================== ; #CURRENT# ===================================================================================================================== ; _COM_ListPorts ; _COM_OpenPort ; _COM_SetTimeouts ; _COM_ClosePort ; ; _COM_SetBreak ; _COM_ClearBreak ; _COM_GetInputcount ; _COM_GetOutputcount ; _COM_ClearOutputBuffer ; _COM_ClearInputBuffer ; ; _COM_SendByte ; _COM_ReadByte ; _COM_SendBinary ; _COM_ReadBinary ; ; _COM_SendChar ; _COM_ReadChar ; _COM_SendCharArray ; _COM_ReadCharArray ; _COM_SendString ; _COM_ReadString ; ; __COM_ClearCommError ; __COM_Purge ; =============================================================================================================================== ; =============================================================================================================================== ; Function Name: _COM_ListPorts() ; Description: Creates a list of the existing COM ports ; Parameters: (none) ; Returns: on success: an array of strings ; on error: -1 (no com ports existing) ; Note: The array contains e.g. "COM1", "COM2", up to "COM256" ; =============================================================================================================================== Func _COM_ListPorts() Local Const $sRegKey = 'HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM' Local $sValue = '' Local $sData = '' Local $aCOMPorts[0] For $i = 1 To 256 $sValue = RegEnumVal($sRegKey, $i) If @error Then ExitLoop $sData = RegRead($sRegKey, $sValue) If @error Then ExitLoop ReDim $aCOMPorts[$i] $aCOMPorts[$i - 1] = $sData Next If UBound($aCOMPorts) = 0 Then Return SetError(0, 1, -1) Return SetError(0, 2, $aCOMPorts) EndFunc ;==>_COM_ListPorts ; #FUNCTION# ==================================================================================================================== ; Name ..........: _COM_ListPortDevices ; Description ...: Get COM Devices list 2DArray DevicesName|COMPort ; Syntax ........: _COM_ListPortDevices([$bIsAvailable = False]) ; Parameters ....: $bIsAvailable - [optional] a boolean value. Default is False. list only device that can be open ; Return values .: Success - 2DArray DevicesName|COMPort ; Failure - 0 ; Author ........: Danyfirex ; Modified ......: mLipok ; Remarks .......: ; Related .......: _COM_ListPorts ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _COM_ListPortDevices($bIsAvailable = False) Local $aCOMPorts = _COM_ListPorts() If Not IsArray($aCOMPorts) Then Return SetError(1, 0, 0) Local Const $sKeyUSB = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB" Local $iIndex = 1 Local $iSubIndex = 1 Local $sSubKey = "" Local $sSubKeyChild = "" Local $sFriendlyName = "" Local $sDriver = "" Local $bFoundAll = False Local $sCOMPort = "" Local $hCOMPort = "" Local $aCOMDevices[256][3] Local $iIndexDevices = 0 While True $sSubKey = RegEnumKey($sKeyUSB, $iIndex) If @error Then ExitLoop $iIndex += 1 $sSubKey = $sKeyUSB & "\" & $sSubKey $iSubIndex = 1 While True $sSubKeyChild = RegEnumKey($sSubKey, $iSubIndex) If @error Then ExitLoop $iSubIndex += 1 $sFriendlyName = RegRead($sSubKey & "\" & $sSubKeyChild, "FriendlyName") If $sFriendlyName = "" Then ContinueLoop ; no friendly name $sDriver = RegRead($sSubKey & "\" & $sSubKeyChild, "Driver") $sCOMPort = RegRead($sSubKey & "\" & $sSubKeyChild & "\Device Parameters", "PortName") ; mLipok If $sCOMPort = "" Then $sCOMPort = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\" & $sDriver, "AttachedTo") If $sCOMPort = "" Then $sCOMPort = RegRead("HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\" & $sDriver, "AssignedPortForQCDevice") If $sCOMPort = "" Then ContinueLoop ; not Attached ; check if exist in $aCOMPorts and remove it For $x = 0 To UBound($aCOMPorts) - 1 If $aCOMPorts[$x] <> $sCOMPort Then ContinueLoop $aCOMDevices[$iIndexDevices][0] = $sFriendlyName $aCOMDevices[$iIndexDevices][1] = $sCOMPort $aCOMDevices[$iIndexDevices][2] = False If $bIsAvailable Then $hCOMPort = _COM_OpenPort($sCOMPort) $aCOMDevices[$iIndexDevices][2] = $hCOMPort <> -1 If $hCOMPort <> -1 Then _COM_ClosePort($hCOMPort) EndIf $iIndexDevices += 1 ExitLoop Next If UBound($aCOMPorts) = 0 Then $bFoundAll = True If $bFoundAll Then ExitLoop WEnd If $bFoundAll Then ExitLoop WEnd ReDim $aCOMDevices[$iIndexDevices][3] If $iIndexDevices Then Return SetError(0, $iIndexDevices, $aCOMDevices) Return SetError(2, 0, 0) EndFunc ;==>_COM_ListPortDevices ; =============================================================================================================================== ; Function Name: _COM_OpenPort($sDefinitions) ; Description: Opens a serial port ; Parameters: $sDefinitions - (string) See the notes for the format and default settings ; Returns: on success: a serial port handle ; on error: -1 and sets @error to 1 ; Note: ; Defs is a string containing com port and many parameters. Default setting: ; COM1 baud=9600 parity=n data=8 stop=1 to=off xon=off odsr=off octs=off dtr=off rts=off idsr=off ; Usually the user would provide at least the COM port and baud settings, e.g. "COM1 baud=9600". ; All possible values are explained at https://technet.microsoft.com/en-us/library/cc732236.aspx ; ; To test the $sDefinitions sting you can simply open a command prompt and use it with the "mode" command. ; To try e.g. "COM1 baud=9600 parity=N data=8 stop=1" just type "mode COM1 baud=9600 parity=N data=8 stop=1". ; ; The following settings aren't supported by many chipsets. If you intend to use them it is strongly recommended to test them with the mode command: ; data=5, data=6, parity=m, parity=s and stop=1.5 ; ; References: Open the com port: ; CreateFile https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx ; ; References: Prepare the parameters: ; BuildCommDCB https://msdn.microsoft.com/en-us/library/windows/desktop/aa363143(v=vs.85).aspx ; Mode https://technet.microsoft.com/en-us/library/cc732236.aspx ; DCB https://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx ; COMMTIMEOUTS https://msdn.microsoft.com/en-us/library/windows/desktop/aa363190(v=vs.85).aspx ; ; References: Set the parameters: ; SetCommState https://msdn.microsoft.com/en-us/library/windows/desktop/aa363436(v=vs.85).aspx ; SetCommTimeouts https://msdn.microsoft.com/en-us/library/windows/desktop/aa363437(v=vs.85).aspx ; =============================================================================================================================== Func _COM_OpenPort($sDefinition) ; The format of $sDefinition is defined here: ; https://msdn.microsoft.com/en-us/library/windows/desktop/aa363145(v=vs.85).aspx ; https://technet.microsoft.com/en-us/library/cc732236.aspx ; To test the $sDefinition open a command prompt windows and use it with the "mode" command Local Const $GENERIC_READ_WRITE = 0xC0000000 Local Const $OPEN_EXISTING = 3 Local Const $FILE_ATTRIBUTE_NORMAL = 0x80 ; REMARK: ; When you open serial port for the first time since your application started, the opened dll handle is created. ; In case of using more than one serial port, the subsequent port opening calls will just use this handle without recreation If $__g_iCOMUDF_HCOMPortCount = 0 Then $__g_hCOMUDF_Kernel32 = DllOpen('kernel32.dll') If @error Then Return SetError(1, 1, -1) ; parse $sDefinition and set default values $sDefinition = StringStripWS($sDefinition, 3) ; remove leading and trailing whitespaces #Tidy_ILC_Pos=70 ; default value, options If StringInStr($sDefinition, 'COM') < 1 Then $sDefinition = 'COM1 ' & $sDefinition ; COM1...COM256 If StringInStr($sDefinition, 'baud=') < 1 Then $sDefinition &= ' baud=9600' ; 110...115200 If StringInStr($sDefinition, 'parity=') < 1 Then $sDefinition &= ' parity=n' ; {n|e|o|m|s} (n=none,e=even,o=odd,m=mark,s=space) If StringInStr($sDefinition, 'data=') < 1 Then $sDefinition &= ' data=8' ; {5|6|7|8} If StringInStr($sDefinition, 'stop=') < 1 Then $sDefinition &= ' stop=1' ; {1|1.5|2} If StringInStr($sDefinition, 'to=') < 1 Then $sDefinition &= ' to=off' ; {on|off} If StringInStr($sDefinition, 'xon=') < 1 Then $sDefinition &= ' xon=off' ; {on|off} If StringInStr($sDefinition, 'odsr=') < 1 Then $sDefinition &= ' odsr=off' ; {on|off} If StringInStr($sDefinition, 'octs=') < 1 Then $sDefinition &= ' octs=off' ; {on|off} If StringInStr($sDefinition, 'dtr=') < 1 Then $sDefinition &= ' dtr=off' ; {on|off|hs} (hs=handshake) If StringInStr($sDefinition, 'rts=') < 1 Then $sDefinition &= ' rts=off' ; {on|off|hs|tg} (tg=toggle) If StringInStr($sDefinition, 'idsr=') < 1 Then $sDefinition &= ' idsr=off' ; {on|off} #Tidy_ILC_Pos=70 ; extract $sCOMPort from $sDefinitions Local $sCOMPort = "" Local $iCOMPort = 0 Local $aReg = StringRegExp($sDefinition, 'COM\d{1,3}', 3) If IsArray($aReg) Then $sCOMPort = $aReg[0] Local $aRegNumber = StringRegExp($sCOMPort, '\d{1,3}', 3) If IsArray($aRegNumber) Then $iCOMPort = Number($aRegNumber[0]) $sCOMPort = ($iCOMPort > 9 ? "\\.\" & $sCOMPort : $sCOMPort) ; open the com port Local $tFileName = DllStructCreate('char COMPort[' & StringLen($sCOMPort) + 1 & ']') Local $pFileName = DllStructGetPtr($tFileName, 'COMPort') DllStructSetData($tFileName, 'COMPort', $sCOMPort) ;~ ConsoleWrite('! ---> '& @ScriptLineNumber & ' @error=' & @error & ' @extended=' & @extended & ' : ' & @CRLF) #Tidy_ILC_Pos=50 Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'handle', 'CreateFile', _ 'long_ptr', $pFileName, _ 'dword', $GENERIC_READ_WRITE, _ ; DesiredAccess 'dword', 0, _ ; ShareMode 'long_ptr', 0, _ ; SecurityAttributes 'dword', $OPEN_EXISTING, _ ; CreationDisposition 'dword', $FILE_ATTRIBUTE_NORMAL, _ ; FlagsAndAttributes 'handle', 0) ; TemplateFile ;~ ConsoleWrite('! ---> '& @ScriptLineNumber & ' @error=' & @error & ' @extended=' & @extended & ' : ' & @CRLF) If @error Then Return SetError(1, 2, -1) Local $hCOMPort = $aCall[0] If $hCOMPort = Ptr(-1) Then _ ; $INVALID_HANDLE_VALUE Return SetError(1, 3, -1) ; prepare structs and pointer Local $tDefinition = DllStructCreate('char Data[255]') Local $pDefinition = DllStructGetPtr($tDefinition) DllStructSetData($tDefinition, 'Data', $sDefinition) Local $tDCB = DllStructCreate( _ 'long DCBlength;' & _ ; DWORD DCBlength; 'long BaudRate;' & _ ; DWORD BaudRate 'long fBitFields;' & _ ; DWORD fBitFields 'short wReserved;' & _ ; WORD wReserved 'short XonLim;' & _ ; WORD XonLim 'short XoffLim;' & _ ; WORD XoffLim 'byte Bytesize;' & _ ; BYTE ByteSize 'byte parity;' & _ ; BYTE Parity 'byte StopBits;' & _ ; BYTE StopBits 'byte XonChar;' & _ ; char XonChar 'byte XoffChar;' & _ ; char XoffChar 'byte ErrorChar;' & _ ; char ErrorChar 'byte EofChar;' & _ ; char EofChar 'byte EvtChar;' & _ ; char EvtChar 'short wReserved1') ; WORD wReserved Local $pDCB = DllStructGetPtr($tDCB) ; parse $sDefinition and fill the parameters in the prepared DCB struct $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'bool', 'BuildCommDCB', _ 'long_ptr', $pDefinition, _ 'long_ptr', $pDCB) ;~ ConsoleWrite('! ---> '& @ScriptLineNumber & ' @error=' & @error & ' @extended=' & @extended & ' : ' & @CRLF) If @error Then Return SetError(1, 4, -1) ;~ ConsoleWrite('! ---> '& @ScriptLineNumber & ' @error=' & @error & ' @extended=' & @extended & ' : ' & @CRLF) ;~ ConsoleWrite('! $aCall[0] = ' & $aCall[0] & @CRLF) ;~ ConsoleWrite('! VarGetType($aCall[0]) = ' & VarGetType($aCall[0]) & @CRLF) If Not $aCall[0] Then Return SetError(1, 5, -1) ; set the parameters $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'bool', 'SetCommState', _ 'handle', $hCOMPort, _ 'long_ptr', $pDCB) ;~ ConsoleWrite('! ---> '& @ScriptLineNumber & ' @error=' & @error & ' @extended=' & @extended & ' : ' & @CRLF) If @error Then Return SetError(1, 6, -1) ;~ ConsoleWrite('! ---> '& @ScriptLineNumber & ' @error=' & @error & ' @extended=' & @extended & ' : ' & @CRLF) ;~ ConsoleWrite('! $aCall[0] = ' & $aCall[0] & @CRLF) ;~ ConsoleWrite('! VarGetType($aCall[0]) = ' & VarGetType($aCall[0]) & @CRLF) If Not $aCall[0] Then Return SetError(1, 7, -1) ;~ ConsoleWrite('! ---> '& @ScriptLineNumber & ' @error=' & @error & ' @extended=' & @extended & ' : ' & @CRLF) ; set timeouts _COM_SetTimeouts($hCOMPort) ; default=no timeout, return immediately ; return the handle to the serial port and add +1 to opened handles counter $__g_iCOMUDF_HCOMPortCount += 1 Return SetError(0, 8, $hCOMPort) EndFunc ;==>_COM_OpenPort ; =============================================================================================================================== ; Function Name: _COM_SetTimeouts($hComPort, ; $iReadIntervalTimeout = -1, $iReadTotalTimeoutMultiplier = 0, $iReadTotalTimeoutConstant = 0, ; $iWriteTotalTimeoutMultiplier = 0, $iWriteTotalTimeoutConstant = 0) ; Description: Could set the timeouts on the serial port. ; It fails if non-standard values are provided, for this reason: ; If called with non-default settings it would break the functions to read and send data. ; Be warned, you don't want your program to wait forever on a missing serial port input, as the user will think the program crashed or failed. ; To have a stable UDF this cannot be allowed. ; For a background program without GUI you might want to wait for data, instead of running the idle loop/GUI loop. ; In this case I would recommend creating a new UDF. ; ; Parameters: $hCOMPort - serial port handle (as returned by _COM_OpenPort) ; $iReadIntervalTimeout - ReadIntervalTimeout ; $iReadTotalTimeoutMultiplier - ReadTotalTimeoutMultiplier ; $iReadTotalTimeoutConstant - ReadTotalTimeoutConstant ; $iWriteTotalTimeoutMultiplier - WriteTotalTimeoutMultiplier ; $iWriteTotalTimeoutConstant - WriteTotalTimeoutConstant ; Returns: on success: 0 ; on error: -1 and sets @error to 1 ; Note: Default setting: Return immediately from reads without waiting. ; =============================================================================================================================== Func _COM_SetTimeouts($hCOMPort, $iReadIntervalTimeout = -1, $iReadTotalTimeoutMultiplier = 0, $iReadTotalTimeoutConstant = 0, $iWriteTotalTimeoutMultiplier = 0, $iWriteTotalTimeoutConstant = 0) ; SetCommTimeouts: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363437(v=vs.85).aspx ; COMMTIMEOUTS: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363190(v=vs.85).aspx ; Return with an error message if non-standard parameters are provided ; Reasoning: Instant return is expected by all functions in this UDF If $iReadIntervalTimeout <> -1 Then Return SetError(1, 1, -1) If $iReadTotalTimeoutMultiplier <> 0 Then Return SetError(1, 2, -1) If $iReadTotalTimeoutConstant <> 0 Then Return SetError(1, 3, -1) If $iWriteTotalTimeoutMultiplier <> 0 Then Return SetError(1, 4, -1) If $iWriteTotalTimeoutConstant <> 0 Then Return SetError(1, 5, -1) ; Return with an error message if non-standard parameters are provided ; Reasoning: Instant return is expected by all functions in this UDF Local $tCOMMTIMEOUTS = DllStructCreate( _ 'DWORD ReadIntervalTimeout;' & _ 'DWORD ReadTotalTimeoutMultiplier;' & _ 'DWORD ReadTotalTimeoutConstant;' & _ 'DWORD WriteTotalTimeoutMultiplier;' & _ 'DWORD WriteTotalTimeoutConstant') Local $pCOMMTIMEOUTS = DllStructGetPtr($tCOMMTIMEOUTS) DllStructSetData($tCOMMTIMEOUTS, 'ReadIntervalTimeout', $iReadIntervalTimeout) DllStructSetData($tCOMMTIMEOUTS, 'ReadTotalTimeoutMultiplier', $iReadTotalTimeoutMultiplier) DllStructSetData($tCOMMTIMEOUTS, 'ReadTotalTimeoutConstant', $iReadTotalTimeoutConstant) DllStructSetData($tCOMMTIMEOUTS, 'WriteTotalTimeoutMultiplier', $iWriteTotalTimeoutMultiplier) DllStructSetData($tCOMMTIMEOUTS, 'WriteTotalTimeoutConstant', $iWriteTotalTimeoutConstant) Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'bool', 'SetCommTimeouts', _ 'handle', $hCOMPort, _ 'long_ptr', $pCOMMTIMEOUTS) If @error Then Return SetError(1, 6, -1) If Not $aCall[0] Then Return SetError(1, 7, -1) Return SetError(0, 8, 0) EndFunc ;==>_COM_SetTimeouts ; =============================================================================================================================== ; Function Name: _COM_ClosePort($hComPort) ; Description: Closes serial port ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; Returns: on success: 1 ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_ClosePort($hCOMPort) ; CloseHandle: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724211(v=vs.85).aspx Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ "bool", "CloseHandle", _ "handle", $hCOMPort) If @error Then Return SetError(1, 1, -1) If Not $aCall[0] Then Return SetError(1, 2, -1) ; close dll ; in case of using more than one opened serial ports, only call of closing the last opened port will terminate the opened dll handle $__g_iCOMUDF_HCOMPortCount -= 1 If $__g_iCOMUDF_HCOMPortCount = 0 Then DllClose($__g_hCOMUDF_Kernel32) Return SetError(0, 3, 1) EndFunc ;==>_COM_ClosePort ; =============================================================================================================================== ; Function Name: _COM_GetInputcount($hComPort) ; Description: Retrieves information about the amount of available bytes in the input buffer ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; Returns: on success: the amount of available bytes ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_GetInputcount($hCOMPort) Local $iRet = __COM_ClearCommError($hCOMPort, 'cbInQue') Return SetError(@error, @extended, $iRet) EndFunc ;==>_COM_GetInputcount ; =============================================================================================================================== ; Function Name: _COM_GetOutputcount($hComPort) ; Description: Retrieves information about the amount of bytes in the output buffer (not yet written to the line) ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; Returns: on success: the amount of bytes ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_GetOutputcount($hCOMPort) Local $iRet = __COM_ClearCommError($hCOMPort, 'cbOutQue') Return SetError(@error, @extended, $iRet) EndFunc ;==>_COM_GetOutputcount ; =============================================================================================================================== ; Function Name: _COM_ClearOutputBuffer($hComPort) ; Description: Discards all characters from the output buffer. ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; Returns: on success: 1 ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_ClearOutputBuffer($hCOMPort) Local $iRet = __COM_Purge($hCOMPort, 0x0004) Return SetError(@error, @extended, $iRet) EndFunc ;==>_COM_ClearOutputBuffer ; =============================================================================================================================== ; Function Name: _COM_ClearInputBuffer($hComPort) ; Description: Discards all characters from the input buffer. ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; Returns: on success: 1 ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_ClearInputBuffer($hCOMPort) Local $iRet = __COM_Purge($hCOMPort, 0x0008) Return SetError(@error, @extended, $iRet) EndFunc ;==>_COM_ClearInputBuffer ; =============================================================================================================================== ; Function Name: _COM_SetBreak($hComPort) ; Description: Suspends character transmission for a specified communications device and places the transmission line in a break state until the _COM_ClearBreak function is called. ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; Returns: on success: 1 ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_SetBreak($hCOMPort) ; https://msdn.microsoft.com/en-us/library/windows/desktop/aa363433(v=vs.85).aspx Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ "bool", "SetCommBreak", _ "handle", $hCOMPort) If @error Then Return SetError(1, 1, -1) If Not $aCall[0] Then Return SetError(1, 2, -1) Return SetError(0, 3, 1) EndFunc ;==>_COM_SetBreak ; =============================================================================================================================== ; Function Name: _COM_ClearBreak($hComPort) ; Description: Restores character transmission for a specified communications device and places the transmission line in a nonbreak state. ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; Returns: on success: 1 ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_ClearBreak($hCOMPort) ; https://msdn.microsoft.com/en-us/library/windows/desktop/aa363179(v=vs.85).aspx Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ "bool", "ClearCommBreak", _ "handle", $hCOMPort) If @error Then Return SetError(1, 1, -1) If Not $aCall[0] Then Return SetError(1, 2, -1) Return SetError(0, 3, 1) EndFunc ;==>_COM_ClearBreak ; =============================================================================================================================== ; Function Name: _COM_SendByte($hComPort, $bSendByte) ; Description: Send a single byte ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $sSendChar - char to send ; Returns: on success: the amout of bytes written ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_SendByte($hCOMPort, $bSendByte) ; WriteFile: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx Local $tBuffer = DllStructCreate('byte b') Local $lBuffer = DllStructGetPtr($tBuffer, 'b') DllStructSetData($tBuffer, 'b', $bSendByte) Local $iNumberOfBytesToWrite = 1 Local $tNumberOfBytesWritten = DllStructCreate('dword n') Local $pNumberOfBytesWritten = DllStructGetPtr($tNumberOfBytesWritten) Local $pOverlapped = 0 ;null pointer Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'bool', 'WriteFile', _ 'handle', $hCOMPort, _ 'long_ptr', $lBuffer, _ 'dword', $iNumberOfBytesToWrite, _ 'long_ptr', $pNumberOfBytesWritten, _ 'long_ptr', $pOverlapped) If @error Then Return SetError(1, 1, -1) If Not $aCall[0] Then Return SetError(1, 2, -1) Return SetError(0, 3, Number(DllStructGetData($tNumberOfBytesWritten, 'n'))) EndFunc ;==>_COM_SendByte ; =============================================================================================================================== ; Function Name: _COM_ReadByte($hComPort) ; Description: Read a single byte from the com port ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; Returns: on success: a byte (0 to 255) ; on failure: -1 (empty buffer) ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_ReadByte($hCOMPort) ; ReadFile: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx #Tidy_ILC_Pos=70 Local $bByte ; received byte Local $tBuffer = DllStructCreate('bool b') ; will contain the data read Local $pBuffer = DllStructGetPtr($tBuffer, 'b') Local $iNumberOfBytesToRead = 1 ; number of chars to read Local $tNumberOfBytesRead = DllStructCreate('dword n') ; will contain the number of bytes read Local $pNumberOfBytesRead = DllStructGetPtr($tNumberOfBytesRead) Local $pOverlapped = 0 Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'bool', 'ReadFile', _ 'handle', $hCOMPort, _ 'long_ptr', $pBuffer, _ 'dword', $iNumberOfBytesToRead, _ 'long_ptr', $pNumberOfBytesRead, _ 'long_ptr', $pOverlapped) If @error Then Return SetError(1, 1, -1) If Not $aCall[0] Then Return SetError(1, 2, -1) Local $iNumberOfBytesRead = Number(DllStructGetData($tNumberOfBytesRead, "n")) If $iNumberOfBytesRead = 1 Then $bByte = DllStructGetData($tBuffer, "b") Return SetError(0, 3, $bByte) EndIf Return SetError(0, 4, -1) ; no error, no char read EndFunc ;==>_COM_ReadByte ; =============================================================================================================================== ; Function Name: _COM_SendBinary($hComPort, $dBinary) ; Description: Send binary data ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $dBinary - Binary data (e.g. Binary('0xFF00FF00') ; Returns: on success: the number of bytes written ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_SendBinary($hCOMPort, $dBinary) ; WriteFile: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747(v=vs.85).aspx Local $iNumberOfBytesToWrite = BinaryLen($dBinary) Local $tBuffer = DllStructCreate('byte Data[' & $iNumberOfBytesToWrite & ']') Local $pBuffer = DllStructGetPtr($tBuffer, 'Data') DllStructSetData($tBuffer, 'Data', $dBinary) Local $tNumberOfBytesWritten = DllStructCreate('dword n') Local $pNumberOfBytesWritten = DllStructGetPtr($tNumberOfBytesWritten) #Tidy_ILC_Pos=40 Local $pOverlapped = 0 ;null pointer Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'bool', 'WriteFile', _ 'handle', $hCOMPort, _ 'long_ptr', $pBuffer, _ 'dword', $iNumberOfBytesToWrite, _ 'long_ptr', $pNumberOfBytesWritten, _ 'long_ptr', $pOverlapped) If @error Then Return SetError(1, 1, -1) If Not $aCall[0] Then Return SetError(1, 2, -1) Return SetError(0, 3, Number(DllStructGetData($tNumberOfBytesWritten, 'n'))) EndFunc ;==>_COM_SendBinary ; =============================================================================================================================== ; Function Name: _COM_ReadBinary($hComPort, ByRef $binary, $iBytesToRead) ; Description: Receives binary data ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $dBinary - will contain the read data ; $iBytesToRead - exact number of bytes to read ; Returns: on success: 1 ($dBinary contains $iBytesToRead bytes) ; on failure: 0 ($dBinary is undefined) ; on error: -1 and sets @error to 1 ; Note: ; If there are less bytes than requested in the input buffer it returns 0 ; =============================================================================================================================== Func _COM_ReadBinary($hCOMPort, ByRef $dBinary, $iBytesToRead) If $iBytesToRead > _COM_GetInputcount($hCOMPort) Then Return SetError(0, 1, 0) #Tidy_ILC_Pos=30 ; ReadFile: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365467(v=vs.85).aspx ;~ Local $byte ; received byte ;not used ;~ #forceref $byte #Tidy_ILC_Pos=80 Local $tBuffer = DllStructCreate('byte Data[' & $iBytesToRead & ']') ; will contain the data read Local $pBuffer = DllStructGetPtr($tBuffer, 'Data') Local $iNumberOfBytesToRead = $iBytesToRead ; number of chars to read Local $tNumberOfBytesRead = DllStructCreate('dword n') ; will contain the number of bytes read Local $pNumberOfBytesRead = DllStructGetPtr($tNumberOfBytesRead) Local $pOverlapped = 0 Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'bool', 'ReadFile', _ 'handle', $hCOMPort, _ 'long_ptr', $pBuffer, _ 'dword', $iNumberOfBytesToRead, _ 'long_ptr', $pNumberOfBytesRead, _ 'long_ptr', $pOverlapped) If @error Then Return SetError(1, 2, -1) If Not $aCall[0] Then Return SetError(1, 3, -1) Local Const $iNumberOfBytesRead = Number(DllStructGetData($tNumberOfBytesRead, "n")) If $iNumberOfBytesRead = 0 Then Return SetError(1, 4, -1) If $iNumberOfBytesRead <> $iNumberOfBytesToRead Then Return SetError(1, 5, -1) $dBinary = DllStructGetData($tBuffer, "Data") If @error Then Return SetError(@error, 6, $dBinary) Return SetError(0, 7, 1) EndFunc ;==>_COM_ReadBinary ; =============================================================================================================================== ; Function Name: _COM_SendChar($hComPort, $cChar) ; Description: Sends an ASCII char ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $cChar - a char ; Returns: on success: the number of bytes written ; on error: -1 and sets @error ; Note: ; =============================================================================================================================== Func _COM_SendChar($hCOMPort, $sChar) Local $iRet = _COM_SendByte($hCOMPort, Asc($sChar)) Return SetError(@error, @extended, $iRet) EndFunc ;==>_COM_SendChar ; =============================================================================================================================== ; Function Name: _COM_ReadChar($hComPort, $cChar) ; Description: Reads an ASCII char ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $cChar - a char ; Returns: on success: a char if was read ; on failure: -1 (no char to read) ; on error: -1 and sets @error ; Note: ; =============================================================================================================================== Func _COM_ReadChar($hCOMPort) Local $bByte = _COM_ReadByte($hCOMPort) If @error Then Return SetError(1, 1, -1) If $bByte = -1 Then Return SetError(0, 2, -1) Return SetError(0, 3, Chr($bByte)) EndFunc ;==>_COM_ReadChar ; =============================================================================================================================== ; Function Name: _COM_SendCharArray($hComPort, $charArray) ; Description: Sends data ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $charArray - the data to write, ; Returns: on success: the number of bytes written ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_SendCharArray($hCOMPort, $aChar) Local $iCount = 0 For $i = 0 To UBound($aChar) - 1 $iCount += _COM_SendByte($hCOMPort, $aChar[$i]) If @error Then Return SetError(1, 1, -1) Next Return SetError(0, 2, $iCount) EndFunc ;==>_COM_SendCharArray ; =============================================================================================================================== ; Function Name: _COM_ReadCharArray($hComPort, ByRef $charArray, $charsToRead) ; Description: Reads data into an array ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $charArray - will contain the read data ; $charsToRead - exact number of chars (bytes) to read ; Returns: on success: 1 ($charArray contains $charsToRead bytes) ; on failure: 0 ($charArray is undefined) ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func _COM_ReadCharArray($hCOMPort, ByRef $aChar, $charsToRead) Local $dBinary Local $iRet = _COM_ReadBinary($hCOMPort, $dBinary, $charsToRead) If @error Then Return SetError(1, 1, -1) EndIf If $iRet = 1 Then ReDim $aChar[$charsToRead] For $i = 0 To BinaryLen($dBinary) - 1 $aChar[$i] = BinaryMid($dBinary, $i + 1, 1) Next Return SetError(0, 2, 1) EndIf Return SetError(0, 3, 0) EndFunc ;==>_COM_ReadCharArray ; =============================================================================================================================== ; Function Name: _COM_SendString($hComPort, $string, $encoding=1) ; Description: Sends data ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $string - the string to write ; $encoding - 1=ANSI (default), 2=UTF-8 ; Returns: on success: the number of bytes written ; on error: -1 and sets @error to 1 ; =============================================================================================================================== Func _COM_SendString($hCOMPort, $sString, $iEncoding = 1) If $iEncoding < 1 Or $iEncoding > 2 Then Return SetError(1, 1, -1) Local $iRet = _COM_SendBinary($hCOMPort, StringToBinary($sString, ($iEncoding = 1 ? 1 : 4))) Return SetError(@error, @extended, $iRet) EndFunc ;==>_COM_SendString Func _COM_SendString___OLD_VERSION($hCOMPort, $sString, $iEncoding = 1) # REMARK: THIS OLD VERSION SHOULD BE REVIEWED AND EVENTUALLY DELETED FROM THIS UDF If $iEncoding < 1 Or $iEncoding > 2 Then Return SetError(1, 1, -1) Local $aChar = StringToASCIIArray($sString, 0, StringLen($sString), $iEncoding) Local $iRet = _COM_SendCharArray($hCOMPort, $aChar) Return SetError(@error, @extended, $iRet) EndFunc ;==>_COM_SendString___OLD_VERSION ; =============================================================================================================================== ; Function Name: _COM_ReadString($hComPort, $iByteLength, $encoding=1) ; Description: Reads a string ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $iByteLength - exact amount of bytes to read Unicode uses more than one byte per character ; $encoding - 1=ANSI (default), 2=UTF-8 ; Returns: on success: a string ; on failure: 0 ; on error: -1 and sets @error to 1 ; Note: ; If there are less bytes than requested in the input buffer it returns 0 ; =============================================================================================================================== Func _COM_ReadString($hCOMPort, $iByteLength, $iEncoding = 1) Local $aChar[0] If $iEncoding < 1 Or $iEncoding > 2 Then Return SetError(1, 1, -1) Local $iRet = _COM_ReadCharArray($hCOMPort, $aChar, $iByteLength) If @error Then Return SetError(1, 2, -1) EndIf If $iRet = 1 Then Return SetError(0, 3, StringFromASCIIArray($aChar, 0, UBound($aChar), $iEncoding)) EndIf Return SetError(0, 4, 0) EndFunc ;==>_COM_ReadString ; =============================================================================================================================== ; Function Name: __COM_ClearCommError($hComPort, $sInfo = 'cbInQue') ; Description: Retrieves information about commincation errors and state ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $sInfo - a string describing the info to return, possible values: ; 'Errors' - Errors that occured (see notes) ; 'Flags' - Flags set or unset ; 'cbInQue' - The number of bytes in the input buffer (net yet read) ; 'cbOutQue' - The number of bytes in the output buffer (not yet send) ; Returns: on success: 0 (false), 1 (true) or a positive number ; on error: -1 and sets @error to 1 ; Note: ; Possible error values: ; CE_BREAK (0x0010) - The hardware detected a break condition ; CE_FRAME (0x0008) - The hardware detected a framing error ; CE_OVERRUN (0x0002) - A character-buffer overrun has occurred, the next character is lost ; CE_RXOVER (0x0001) - An input buffer overflow has occurred. There is either no room in the input buffer, or a character was received after the end-of-file (EOF) character ; CE_RXPARITY (0x0004) - The hardware detected a parity error ; Call _ClearCommBreak to resolve errors ; ; Possible FLAG values: ; fCtsHold (1bit) - Transmission is waiting for the CTS signal to be sent ; fDsrHold (1bit) - Transmission is waiting for the DSR signal to be sent ; fRlsdHold (1bit) - Transmission is waiting for the RLSD signal to be sent ; fXoffHold (1bit) - Transmission is waiting because the XOFF character was received ; fXoffSent (1bit) - Transmission is waiting because the XOFF character was transmitted ; fEof (1bit) - The end-of-file (EOF) character has been received ; fTxim (1bit) - There is a character queued for transmission that has come to ; the communications device by way of the TransmitCommChar function ; Reserved (25bits) ; =============================================================================================================================== Func __COM_ClearCommError($hCOMPort, $sInfo = 'cbInQue') ; https://msdn.microsoft.com/en-us/library/windows/desktop/aa363180(v=vs.85).aspx #Tidy_ILC_Pos=60 ; prepare structs Local $tErrors = DllStructCreate('dword Errors') Local $pErrors = DllStructGetPtr($tErrors) Local $tStat = DllStructCreate( _ 'dword Flags;' & _ ; DWORD flags 'dword cbInQue;' & _ ; DWORD cbInQue 'dword cbOutQue;') ; DWORD cbOutQue Local $pStat = DllStructGetPtr($tStat) ; read the status Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'bool', 'ClearCommError', _ 'handle', $hCOMPort, _ 'long_ptr', $pErrors, _ 'long_ptr', $pStat) If @error Then Return SetError(1, 1, -1) If Not $aCall[0] Then Return SetError(1, 2, -1) ; return requested information Local $iStat If $sInfo = 'cbInQue' Then ; probably most often called, checked first $iStat = DllStructGetData($tStat, $sInfo) Return SetError(0, 3, $iStat) ElseIf $sInfo = 'cbOutQue' Then $iStat = DllStructGetData($tStat, $sInfo) Return SetError(0, 4, $iStat) ElseIf $sInfo = 'Flags' Then $iStat = DllStructGetData($tStat, $sInfo) Return SetError(0, 5, $iStat) ElseIf $sInfo = 'Errors' Then $iStat = DllStructGetData($tErrors, $sInfo) Return SetError(0, 6, $iStat) EndIf Return SetError(1, 7, -1) ; nothing matched EndFunc ;==>__COM_ClearCommError ; =============================================================================================================================== ; Function Name: __COM_Purge($hComPort, $sFlags = 0x0000) ; Description: Discards all characters from the output or input buffer. It can also terminate pending read or write operations. ; Parameters: $hComPort - serial port handle (as returned by _COM_OpenPort) ; $sFlage - a combination of any of these numbers: ; 0x0001 - Terminates all outstanding write operations ; 0x0002 - Terminates all outstanding read operations ; 0x0004 - Clears the output buffer ; 0x0008 - Clears the input buffer ; Returns: on success: 1 ; on error: -1 and sets @error to 1 ; Note: ; =============================================================================================================================== Func __COM_Purge($hCOMPort, $iFlags = 0x0000) ; https://msdn.microsoft.com/en-us/library/windows/desktop/aa363428(v=vs.85).aspx Local $aCall = DllCall($__g_hCOMUDF_Kernel32, _ 'bool', 'PurgeComm', _ 'handle', $hCOMPort, _ 'dword', $iFlags) If @error Then Return SetError(1, 1, -1) If Not $aCall[0] Then Return SetError(1, 2, -1) Return SetError(0, 3, 1) EndFunc ;==>__COM_Purge