Jump to content

CommAPI - Serial and parallel communication with Windows API


therealhanuta
 Share

Recommended Posts

Hi TheReal,

You made a great job with the little indication I gave. Nice!

Everything seems to work, but :

- you changed, I mean removed, the _CommAPI_ReceiveLine() and _CommAPI_ReceiveData(). Some people using these functions should have a surprise when compiling older scripts with new UDF. At least, you should keep the older ones calling the new ones.

- in the same renamed function _CommAPI_ReceiveLine(), you changed the order of parameters and added one (however optional) :

       _CommAPI_ReceiveLine(Const $hFile, Const $sSeparator = @CRLF, Const $iTimeout = 1, Const $iMaxLen = 0)
       _CommAPI_ReceiveString(Const $hFile, Const $iTimeout = 1, Const $iMaxLength = 0, Const $sSeparator = "", Const $iFlag = 1)

- in both functions ReceiveLine and ReceiveString, you are returning the separator, which is not specially desired. ie for an empty line (0x0D0A), I've to use StringStripCR if I don't want a StringLen of 2 instead of 0, which it is indeed.

See http://msdn.microsoft.com/en-us/library/h7se9d4f%28v=vs.84%29.aspx : Reads an entire line (up to, but not including, the newline character)

Really sorry to bother you with these little details, but it's a way to keep the confidence in your GREAT UDF.

Untill i've to use other functions...

Thx,

Thoms


 

Link to comment
Share on other sites

Hello thoms, it seems you are havy on wire with this project.

Can you help me with my 2 questions? :

Subject:

_CommAPI_ReceiveString($hFile, 5000) while counterpart still sending after RX received $vSeparator

Important Question.

Let's say:
If $bSeparator = BinaryMid($vResult, 1 + $iResLength - $iSepLength) Then Return $vResult --> True

and Func Returns

1. What happen, if the the counterpart just send a new telegram just in the time of reading Buffer and returning?
Could it happen that the 2. telegram blows in nirvana?

2. Generall asked: what happens with the buffer after has been readed and func returns? Will buffer erased or ha to be separately purged by script?

THX for answering me.

Edited by adom

Thanks! :bye:

Greetings

Andrew

 

Link to comment
Share on other sites

- you changed, I mean removed, the _CommAPI_ReceiveLine() and _CommAPI_ReceiveData(). Some people using these functions should have a surprise when compiling older scripts with new UDF. At least, you should keep the older ones calling the new ones.

- in the same renamed function _CommAPI_ReceiveLine(), you changed the order of parameters and added one (however optional) :

       _CommAPI_ReceiveLine(Const $hFile, Const $sSeparator = @CRLF, Const $iTimeout = 1, Const $iMaxLen = 0)

       _CommAPI_ReceiveString(Const $hFile, Const $iTimeout = 1, Const $iMaxLength = 0, Const $sSeparator = "", Const $iFlag = 1)

- in both functions ReceiveLine and ReceiveString, you are returning the separator, which is not specially desired. ie for an empty line (0x0D0A), I've to use StringStripCR if I don't want a StringLen of 2 instead of 0, which it is indeed.

See http://msdn.microsoft.com/en-us/library/h7se9d4f%28v=vs.84%29.aspx : Reads an entire line (up to, but not including, the newline character)

Hi thoms,

you are right.

  • separator is no longer returned
  • CommObsolete.au3 is created for backward compatibility
Edited by therealhanuta
Link to comment
Share on other sites

Hi TheReal,

Thanks for your modifications. I'm going further now.

In the Func _CommAPI_OpenPort, you're refering to the http://msdn.microsoft.com/en-us/library/aa365430(v=vs.85).aspx which is about OpenFile, that says "Note  This function has limited capabilities and is not recommended. For new application development, use the CreateFile function." Actually, you're using CreateFile, which is referenced here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx

The later one says in "Communications Resources": The CreateFile function can create a handle to a communications resource, such as the serial port COM1. For communications resources, the dwCreationDisposition parameter must be OPEN_EXISTING, the dwShareMode parameter must be zero (exclusive access), and the hTemplateFile parameter must be NULL. Read, write, or read/write access can be specified, and the handle can be opened for overlapped I/O.
 

In your Func _CommAPI_OpenPort, you fix this $iCreation to 3 that is OPEN_ALWAYS (a file), when it should be 2 : OPEN_EXISTING(a file or device).

I made that modification _CommAPI_OpenPort_WinAPI_CreateFile($sFileName, 2, 6), and it seems to be working well for physical COM19 and USB COM20 ports, above COM9! Right now, I couldn't get virtual ports. I've to check further.

BTW, "COM1:" and "COM1", with/wo colon doesn't make any difference. It seem's that Kernel is dealing with that by itself.

Hope this helps you further.

I like when reading somewhere else: "But who needs serial port today?" . I think that some people (like M$) are very far away from industrial environment, where tough communication links are needed.

Thx,

Thom's

Edited by thoms
Link to comment
Share on other sites

@adom

Your questions are to be reviewed given the updated UDF from TheReal. It seems that separator doesn't have to be checked or removed anymore.

Anyway, if your asking for a string of xx Chars, you'll receive it in the $var that was waiting for it as soon as MaxLengh was received, or nothing or few chars in $var if nothing or few received at the end of timeout:

$var =  _CommAPI_ReceiveString(Const $hFile[, $iTimeout = 1[, $iMaxLength = 0[, $sSeparator = ""]]])

Then, it depends on what you intend to do with $var. But the receiving buffer will be emptied from the amount you were wating for, or the few chars that were received at timeout. The discarded receveided chars from counterpart depend on the size of the COM buffer and how fast you can manage the received $var before asking again a $var =  _CommAPI_ReceiveString(...).

Especially if you don't manage the flow control (XON/XOFF,  DSR, others)

TheReal, pls, am I right ?

Thoms

 

Link to comment
Share on other sites

@adom

Your questions are to be reviewed given the updated UDF from TheReal. It seems that separator doesn't have to be checked or removed anymore.

Anyway, if your asking for a string of xx Chars, you'll receive it in the $var that was waiting for it as soon as MaxLengh was received, or nothing or few chars in $var if nothing or few received at the end of timeout:

$var =  _CommAPI_ReceiveString(Const $hFile[, $iTimeout = 1[, $iMaxLength = 0[, $sSeparator = ""]]])

Then, it depends on what you intend to do with $var. But the receiving buffer will be emptied from the amount you were wating for, or the few chars that were received at timeout. The discarded receveided chars from counterpart depend on the size of the COM buffer and how fast you can manage the received $var before asking again a $var =  _CommAPI_ReceiveString(...).

Especially if you don't manage the flow control (XON/XOFF,  DSR, others)

TheReal, pls, am I right ?

Thoms

THX Thoms. Have to workout your infos.

Just to be shure: is XON a software flow control? Because often Devices in my case of AV-Systems have no HW-Flow-control.

Thanks! :bye:

Greetings

Andrew

 

Link to comment
Share on other sites

THX Thoms. Have to workout your infos.

Just to be shure: is XON a software flow control? Because often Devices in my case of AV-Systems have no HW-Flow-control.

Hi adom,

Your right, it's a SW control that can't be used for binary transfer as it uses ASCII control chars ^Q-Chr(17) for Xon and ^S-Chr(19) for Xoff.

Thoms

Link to comment
Share on other sites

Hi TheReal,

Actually, I've any kind of COM port opening : physical, virtual/USB and virtual/Com0com from COM1 to COM21. I didn't try above. Yes, COM99 works, COM126 doesn't. I think I'll be able to do something with 99 COM ports :)

And that only by changing the CreateFile in _CommAPI_OpenPort to "_WinAPI_CreateFile($sFileName, 2, 6).

Other thing: I noticed an ambiguity when creating the ModeString: concerning the StopBits, depending on the type of var your passing, ie "1" or 1, you have 1.5 or 1 stopbit. It's only an ambiguity that doesn't disturb me.

Thoms

Edit: maybe above COM99, I've to change my StringRegExp in GetPorts. No time now.

Edited by thoms
Link to comment
Share on other sites

Oops! :>

I don't know if I was dreaming or under influence, but anyway, the colon doesn't work. :naughty:

Now, depending on what computer I'm working with, sometimes I can get COM ports above COM9, sometimes nope. I have 2 other computers to check: XP SP3 in VM, W7/32, and then I'll try to see what's wrong and where.

Anyway, my app was working well and I could finish that one, but only on COM1 and USB/COM2 on that XP SP3.

I have other app's to do with COM ports, specially one that will surely need the WaitCommEvent. I should be able to give an example then.

Read you later,

Thoms
 

Link to comment
Share on other sites

  • 4 months later...
Hello,
 
I've got a problem with the commapi to a Arduino.
 
This program give's every 3 seconds a pulse to my arduino and the arduino knows that the pc is alive.
 
This program works fine but a lot of time when the pc has gone into standby and back he won't reconise the com port anymore.
I've I look into a terminal programm it said the "com already is in use" even if this program is shutdown.
It looks like it loose the handle to _CommAPI_OpenCOMPort
 
I've tryd to close the port and opened it before sending the pulse but the same thing keeps happening.
Strange thing about it that it not happend every time, 90% goes well.
 
I think it goes wrong when he tryd to send the pulse and the pc goes into standby exactly the same moment.
 
If he won't react anymore the only thing I can do is restart the pc.
 
Does someone know the solution to this.
 
Windows 7
Autoit V3.3.8.1
 
#include <include\CommInterface.au3>
#include <include\Services.au3>

Global $sServiceName = "Pc Tools (Nend Software)"; Service name
Global $hFile

If @Compiled = 1 Then
    If _Service_QueryType($sServiceName) = 0 Then
        InstallService()
        Exit
    EndIf
Else
    _code()
EndIf

If $cmdline[0] > 0 Then
    Switch $cmdline[1]
        Case "-i"
            InstallService()
        Case "-u"
            RemoveService()
        Case "-r"
            _Service_Stop($sServiceName)
            Sleep(2000)
            _Service_Stop($sServiceName)
            Sleep(2000)
            _Service_Start($sServiceName)
        Case Else
            Exit
    EndSwitch
Else
    _Service_init($sServiceName)
    Exit
EndIf

Func _main($iArg, $sArgs)
    If Not _Service_ReportStatus($SERVICE_RUNNING, $NO_ERROR, 0) Then
        _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError(), 0)
        Exit
    EndIf

    _code()

    _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 1000)
    DllCallbackFree($tServiceMain)
    DllCallbackFree($tServiceCtrl)

    _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0)
    DllClose($hAdvapi32_DLL)
    DllClose($hKernel32_DLL)
EndFunc   ;==>main

Func _code()
    local $timer, $timerdif
    $bServiceRunning = True ; REQUIRED

    OnAutoItExitRegister("_ExitPC")

    $port = _comm_start_port()
    $hFile = _CommAPI_OpenCOMPort($port, 9600, 0, 8, 0)
    _comm_arduino("Ÿ"); 159 send pulse

    $timer = TimerInit()

    While $bServiceRunning
        #region --> insert your running code here

        $timerdif = TimerDiff($timer)
        If $timerdif > 3000 Then ; 3 second
            $timer = TimerInit()

            _comm_arduino("Ÿ"); 159 send pulse
        EndIf
        _Sleep(20)
        #endregion  --> insert your running code here
    WEnd
EndFunc

Func _comm_arduino($sendstring)
    _CommAPI_TransmitData($hFile, $sendstring)
EndFunc

Func _ExitPC()
    _comm_arduino("ž"); 158
    _CommAPI_ClosePort($hFile)
    Exit
EndFunc

Func _comm_start_port()
    Local $oWMIService, $oItems, $port
    $oWMIService = ObjGet("winmgmts:\\localhost\root\CIMV2"); auto serial port select
    $oItems = $oWMIService.ExecQuery("SELECT * FROM Win32_PnPEntity WHERE Name LIKE 'USB Serial Port%'", "WQL", 48)
    For $oItem In $oItems
        $commsplit = StringSplit($oItem.Name, "(COM", 1)
        $port = StringReplace($commsplit[2], ")", "")
    Next

    ConsoleWrite($port & @CRLF)

    If $port = "" Then
        _ExitPC()
    EndIf
    Return $port
EndFunc

Func _Sleep($delay)
    Local $result = DllCall($hKernel32_DLL, "none", "Sleep", "dword", $delay)
EndFunc ;==>_Sleep

Func InstallService()
    #RequireAdmin
    _Service_Create($sServiceName, $sServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_AUTO_START, $SERVICE_ERROR_SEVERE, '"' & @ScriptFullPath & '"')
    If @error Then
        ConsoleWrite("InstallService(): Problem installing service, Error number is " & @error & @CRLF & " message : " & _WinAPI_GetLastErrorMessage() & @CRLF)
    Else
        ConsoleWrite("InstallService(" & $sServiceName & "): Installation of service successful" & @CRLF)
    EndIf
EndFunc   ;==>InstallService

Func RemoveService()
    _Service_Stop($sServiceName)
    _Service_Delete($sServiceName)
EndFunc   ;==>RemoveService

Func logprint($text, $nolog = 0); log print for services
    ConsoleWrite($text & @CRLF)
EndFunc
Edited by nend
Link to comment
Share on other sites

  • 1 month later...

According to what I read in the "Features" session, this UDF is capable of LPT ports management.

"Possibility of parallel communication (parallel port, LPT port)"

Unfortunately I haven't found nor examples, nor mentions about this functionality within udf.
could someone please post a simple example on how to put a byte on an LPT port?

Thanks a lot

 

image.jpeg.9f1a974c98e9f77d824b358729b089b0.jpeg Chimp

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Link to comment
Share on other sites

  • 2 months later...

I have been using this UDF to communicate with my Arduino Mega and it has been entirely successful. I was not so successful with the other options offered, so THANK YOU!!!!! :*

(Using Win 7 x64 Home Premium)

Edited by ckovoor
Link to comment
Share on other sites

  • 1 month later...

Hello,

I'm trying to communicate with a Agilent E3649A DC Power Supply. I have written some code using the CommAPI and so far I am only able to send commands, I cannot receive anything.  When I use the application that comes with the power supply everything is working as it should so that rules out the cable. Can someone look over my test code? I may have missed something...

#include <CommInterface.au3>
#include <MsgBoxConstants.au3>


Local Const $iPort = 1
Local Const $iBaud = 9600
Local Const $iParity = 0
Local Const $iByteSize = 8
Local Const $iStopBits = 2

Local $hFile =_CommAPI_OpenCOMPort($iPort, $iBaud, $iParity, $iByteSize, $iStopBits)
_CommAPI_ClearCommError($hFile)
_CommAPI_PurgeComm($hFile)

_CommAPI_TransmitString($hFile, "OUTP ON"&@LF) ;Turn output on
Sleep (1000)
_CommAPI_TransmitString($hFile, "VOLT 7.0"&@LF) ;Adjust voltage to 7 volts
Sleep (1000)
_CommAPI_TransmitString($hFile, "VOLT 0.0"&@LF) ;Adjust voltage to 0 volts
Sleep (1000)
_CommAPI_TransmitString($hFile, "OUTP OFF"&@LF) ;Turn output off
Sleep (1000)
_CommAPI_TransmitString($hFile, "*IDN?") ;Identify your-self

Local $sResult =_CommAPI_ReceiveString($hFile, 1, 0);Recieve string

_CommAPI_ClosePort($hFile)

MsgBox($MB_SYSTEMMODAL, "Title", $sResult, 5)

I know that the commands are being sent properly because I can see the output status change on the display of the power supply and my connected LED lights up and then goes out.  Also here is a link to the user manual http://cp.literature.agilent.com/litweb/pdf/E3646-90001.pdf

Thank you in advance!

Link to comment
Share on other sites

  • 2 weeks later...
  • 5 weeks later...

Hello,

thanks for this UDF, i really like it!

But i have a small problem: When i try to receive strings, some characters are not read right.

For example german "umlauts" like öäü are received as "

I think this may have to do with codepage? Any ideas how i can fix it?

Thanks in advance...

Link to comment
Share on other sites

  • 1 month later...
  • 3 months later...

Problem with Windows 10:

The scripts do not work with Windows 10 - _CommAPI_OpenCOMPort fails.

I found however that a Sleep(100) after _CommAPI_BuildCommDCB in the function _CommAPI_OpenPort in script CommInterface.au3 fixes the problem!

 

Rainer

Func _CommAPI_OpenPort(Const $sMode)
    Local $sFileName = "\\.\" & StringLeft($sMode, StringInStr($sMode, ":") - 1)
;   Local $sFileName = ".\" & StringLeft($sMode, StringInStr($sMode, ":") - 1)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $sFileName = ' & $sFileName & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    Local $hFile = _WinAPI_CreateFile($sFileName, 3, 6)
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hFile = ' & $hFile & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    If @error Then Return SetError(@error, @ScriptLineNumber, 0)
    If $hFile <= 0 Then Return SetError(-1, @ScriptLineNumber, 0)
    Local $tDCB = DllStructCreate($tagDCB)
    Local $tCommTimeouts = DllStructCreate($tagCOMMTIMEOUTS)

    _CommAPI_BuildCommDCB($sMode, $tDCB)
    Sleep(100);
    If @error Then Return SetError(@error, @extended, 0)

    _CommAPI_SetCommTimeoutsElement($tCommTimeouts, "ReadTotalTimeoutMultiplier", 1)
    If @error Then Return SetError(@error, @extended, 0)

    _CommAPI_SetCommTimeoutsElement($tCommTimeouts, "WriteTotalTimeoutMultiplier", 1)
    If @error Then Return SetError(@error, @extended, 0)

    If Not _CommAPI_SetCommState($hFile, $tDCB) Then Return SetError(@error, @extended, 0)
    If Not _CommAPI_SetCommTimeouts($hFile, $tCommTimeouts) Then Return SetError(@error, @extended, 0)

    Return $hFile
EndFunc   ;==>_CommAPI_OpenPort

 

Link to comment
Share on other sites

  • 2 weeks later...

Hi,

This UDF have a BIG MISTAKE and doesn't work fine on Windows 10 with some hardware &

There is problem with COM10 (uper to COM9)

 

After several test i have found the mistake :

For function "_CommAPI_BuildCommDCB" parameter

- $sMode = "COM14: BAUD=9600 PARITY=N DATA=8 STOP=1" - This is WRONG !!!

- $sMode = "BAUD=9600 PARITY=N DATA=8 STOP=1" - This is GOOOD !!!

 

So this, how i have modified the function "_CommAPI_OpenPort(Const $sMode)" in file "CommInterface.au3"

 

Func _CommAPI_OpenPort(Const $sMode)

    ;// split the $sMode string in 2 parts ($aMode[1] = "COMx" & $aMode[2] = "BAUD=xxxx PARITY=x DATA=x STOP=x")
    Local $aMode = StringSplit($sMode, ": ",1)
    If @error Then Return SetError(-1, @ScriptLineNumber, 0)
    Local $sFileName = "\\.\" & $aMode[1]
    Local $hFile = _WinAPI_CreateFile($sFileName, 3, 6)
    If @error Then Return SetError(@error, @ScriptLineNumber, 0)
    If $hFile <= 0 Then Return SetError(-1, @ScriptLineNumber, 0)

    Local $tDCB = DllStructCreate($tagDCB)
    Local $tCommTimeouts = DllStructCreate($tagCOMMTIMEOUTS)
    _CommAPI_BuildCommDCB($aMode[2], $tDCB)
    If @error Then Return SetError(@error, @extended, 0)
    _CommAPI_SetCommTimeoutsElement($tCommTimeouts, "ReadTotalTimeoutMultiplier", 1)
    If @error Then Return SetError(@error, @extended, 0)
    _CommAPI_SetCommTimeoutsElement($tCommTimeouts, "WriteTotalTimeoutMultiplier", 1)
    If @error Then Return SetError(@error, @extended, 0)

    If Not _CommAPI_SetCommState($hFile, $tDCB) Then Return SetError(@error, @extended, 0)

    If Not _CommAPI_SetCommTimeouts($hFile, $tCommTimeouts) Then Return SetError(@error, @extended, 0)

    Return $hFile
EndFunc   ;==>_CommAPI_OpenPort

 

Enjoy ;-)

PS: sorry for my bad english, i am french

 

 

Link to comment
Share on other sites

Hi,

This UDF have a BIG MISTAKE and doesn't work fine on Windows 10 with some hardware &

There is problem with COM10 (uper to COM9)

 

After several test i have found the mistake :

For function "_CommAPI_BuildCommDCB" parameter

- $sMode = "COM14: BAUD=9600 PARITY=N DATA=8 STOP=1" - This is WRONG !!!

- $sMode = "BAUD=9600 PARITY=N DATA=8 STOP=1" - This is GOOOD !!!

 

So this, how i have modified the function "_CommAPI_OpenPort(Const $sMode)" in file "CommInterface.au3"

Func _CommAPI_OpenPort(Const $sMode)

    ;// split the $sMode string in 2 parts ($aMode[1] = "COMx" & $aMode[2] = "BAUD=xxxx PARITY=x DATA=x STOP=x")
    Local $aMode = StringSplit($sMode, ": ",1)
    If @error Then Return SetError(-1, @ScriptLineNumber, 0)
    
    Local $sFileName = "\\.\" & $aMode[1]
    Local $hFile = _WinAPI_CreateFile($sFileName, 3, 6)
    If @error Then Return SetError(@error, @ScriptLineNumber, 0)
    If $hFile <= 0 Then Return SetError(-1, @ScriptLineNumber, 0)

    Local $tDCB = DllStructCreate($tagDCB)
    Local $tCommTimeouts = DllStructCreate($tagCOMMTIMEOUTS)
    _CommAPI_BuildCommDCB($aMode[2], $tDCB)
    If @error Then Return SetError(@error, @extended, 0)
    
    _CommAPI_SetCommTimeoutsElement($tCommTimeouts, "ReadTotalTimeoutMultiplier", 1)
    If @error Then Return SetError(@error, @extended, 0)
    _CommAPI_SetCommTimeoutsElement($tCommTimeouts, "WriteTotalTimeoutMultiplier", 1)
    If @error Then Return SetError(@error, @extended, 0)

    If Not _CommAPI_SetCommState($hFile, $tDCB) Then Return SetError(@error, @extended, 0)
    If Not _CommAPI_SetCommTimeouts($hFile, $tCommTimeouts) Then Return SetError(@error, @extended, 0)

    Return $hFile
EndFunc   ;==>_CommAPI_OpenPort

Enjoy ;-)

PS: sorry for my bad english, i am french

 

 

Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...