Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

DllCall to GetCommState


  • Please log in to reply
5 replies to this topic
olfen
  • Members
  • 115 posts
  • Last active: Dec 25 2012 09:48 AM
  • Joined: 04 Jun 2005
Hi,
this function retrieves the configuration settings of a given serial port.
Having hardly any C\C++ experience it took me some time to find out that there is a bitmask in the DCB (Device Configuration Block) structure.

Using BuildCommDCB and SetCommState functions it should also be possible to configure a serial port.
Data can be written to a serial port using one of the binary writing functions on this forum.
I appologize for the script not beeing commented at all, also I am not sure if I did everything right. Comments and suggestions are welcome.

Regards,
olfen

GetCommState(ComPort)
{
/*
http://msdn.microsoft.com/library/en-us/fileio/fs/createfile.asp?frame=true
http://msdn.microsoft.com/library/en-us/devio/base/getcommstate.asp?frame=true
http://msdn.microsoft.com/library/en-us/devio/base/dcb_str.asp

http://msdn.microsoft.com/library/en-us/devio/base/buildcommdcb.asp?frame=true
http://msdn.microsoft.com/library/en-us/devio/base/setcommstate.asp?frame=true
http://msdn.microsoft.com/library/en-us/devio/base/waitcommevent.asp?frame=true

typedef struct _DCB {
    DWORD DCBlength;      /* sizeof(DCB)                     */
    DWORD BaudRate;       /* Baudrate at which running       */
    DWORD fBinary: 1;     /* Binary Mode (skip EOF check)    */
    DWORD fParity: 1;     /* Enable parity checking          */
    DWORD fOutxCtsFlow:1; /* CTS handshaking on output       */
    DWORD fOutxDsrFlow:1; /* DSR handshaking on output       */
    DWORD fDtrControl:2;  /* DTR Flow control                */
    DWORD fDsrSensitivity:1; /* DSR Sensitivity              */
    DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */
    DWORD fOutX: 1;       /* Enable output X-ON/X-OFF        */
    DWORD fInX: 1;        /* Enable input X-ON/X-OFF         */
    DWORD fErrorChar: 1;  /* Enable Err Replacement          */
    DWORD fNull: 1;       /* Enable Null stripping           */
    DWORD fRtsControl:2;  /* Rts Flow control                */
    DWORD fAbortOnError:1; /* Abort all reads and writes on Error */
    DWORD fDummy2:17;     /* Reserved                        */
    WORD wReserved;       /* Not currently used              */
    WORD XonLim;          /* Transmit X-ON threshold         */
    WORD XoffLim;         /* Transmit X-OFF threshold        */
    BYTE ByteSize;        /* Number of bits/byte, 4-8        */
    BYTE Parity;          /* 0-4=None,Odd,Even,Mark,Space    */
    BYTE StopBits;        /* 0,1,2 = 1, 1.5, 2               */
    char XonChar;         /* Tx and Rx X-ON character        */
    char XoffChar;        /* Tx and Rx X-OFF character       */
    char ErrorChar;       /* Error replacement char          */
    char EofChar;         /* End of Input character          */
    char EvtChar;         /* Received Event character        */
    WORD wReserved1;      /* Fill for now.                   */
} DCB, *LPDCB;

Flowcontrol
Xon/Xoff: 21393 -> 0101 0011 1001 0001
Hardware: 24725 -> 0110 0000 1001 0101
Off:      20625 -> 0101 0000 1001 0001
*/

global
local h, cs, ch, port, DCB, Str, Uint

port=com%comport%
h := DllCall("CreateFile","Str", port,"Uint",0x80000000,"Uint",3,"UInt",0,"UInt",3,"Uint",0,"UInt",0)
If (h = -1 or h = 0 or ErrorLevel != 0)
return, -1
VarSetCapacity(DCB, 28, 0)
cs := DllCall("GetCommState", Uint, h, str, DCB)
If (cs = 0 or ErrorLevel != 0)
return, -2

;DCB_DCBlength:=ExtractInteger(DCB, 0, true, 4)
DCB_BaudRate:=ExtractInteger(DCB, 4, true, 4)

DCB_fBitMask:=ExtractInteger(DCB, 8, true, 4)
DCB_fBitMaskDec:=DCB_fBitMask
DCB_fBitMask:=DecToBin(DCB_fBitMask)

StringLeft, DCB_fAbortOnError, DCB_fBitMask, 1
StringMid, DCB_fRtsControl, DCB_fBitMask, 2, 2
StringMid, DCB_fNull, DCB_fBitMask, 4, 1
StringMid, DCB_fErrorChar, DCB_fBitMask, 5, 1
StringMid, DCB_fInX, DCB_fBitMask, 6, 1
StringMid, DCB_fOutX, DCB_fBitMask, 7, 1
StringMid, DCB_fTXContinueOnXoff, DCB_fBitMask, 8, 1
StringMid, DCB_fDsrSensitivity, DCB_fBitMask, 9, 1
StringMid, DCB_fDtrControl, DCB_fBitMask, 10, 2
StringMid, DCB_fOutxDsrFlow, DCB_fBitMask, 12, 1
StringMid, DCB_fOutxCtsFlow, DCB_fBitMask, 13, 1
StringMid, DCB_fParity, DCB_fBitMask, 14, 1
StringRight, DCB_fBinary, DCB_fBitMask, 1

IfEqual, DCB_fDtrControl, 00, SetEnv, DCB_fDtrControl, DTR_CONTROL_DISABLE
IfEqual, DCB_fDtrControl, 01, SetEnv, DCB_fDtrControl, DTR_CONTROL_ENABLE
IfEqual, DCB_fDtrControl, 10, SetEnv, DCB_fDtrControl, DTR_CONTROL_HANDSHAKE

IfEqual, DCB_fRtsControl, 00, SetEnv, DCB_fRtsControl, RTS_CONTROL_DISABLE
IfEqual, DCB_fRtsControl, 01, SetEnv, DCB_fRtsControl, RTS_CONTROL_ENABLE
IfEqual, DCB_fRtsControl, 10, SetEnv, DCB_fRtsControl, RTS_CONTROL_HANDSHAKE
IfEqual, DCB_fRtsControl, 11, SetEnv, DCB_fRtsControl, RTS_CONTROL_TOGGLE

DCB_XonLim:=ExtractInteger(DCB, 14, true, 2)
DCB_XoffLim:=ExtractInteger(DCB, 16, true, 2)
DCB_ByteSize:=ExtractInteger(DCB, 18, true, 1)

DCB_Parity:=ExtractInteger(DCB, 19, true, 1)
IfEqual, DCB_Parity, 2, SetEnv, DCB_Parity, Even
IfEqual, DCB_Parity, 3, SetEnv, DCB_Parity, Mark
IfEqual, DCB_Parity, 0, SetEnv, DCB_Parity, None
IfEqual, DCB_Parity, 1, SetEnv, DCB_Parity, Odd
IfEqual, DCB_Parity, 4, SetEnv, DCB_Parity, Space

DCB_StopBits:=ExtractInteger(DCB, 20, true, 1)
IfEqual, DCB_StopBits, 2, SetEnv, DCB_StopBits, 2
IfEqual, DCB_StopBits, 1, SetEnv, DCB_StopBits, 1,5
IfEqual, DCB_StopBits, 0, SetEnv, DCB_StopBits, 1

DCB_XonChar:=ExtractInteger(DCB, 21, true, 1)
DCB_XoffChar:=ExtractInteger(DCB, 22, true, 1)
DCB_ErrorChar:=ExtractInteger(DCB, 23, true, 1)
DCB_EofChar:=ExtractInteger(DCB, 24, true, 1)
DCB_EvtChar:=ExtractInteger(DCB, 25, true, 1)

ch:=DllCall("CloseHandle", "Uint", h)
If (ch = 0 or ErrorLevel != 0)
return, -3
return, 0
}

ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
; pSource is a string (buffer) whose memory area contains a raw/binary integer at pOffset.
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
; pSource must be ByRef to avoid corruption during the formal-to-actual copying process
; (since pSource might contain valid data beyond its first binary zero).
{
	Loop %pSize%  ; Build the integer by adding up its bytes.
		result += *(&pSource + pOffset + A_Index-1) << 8*(A_Index-1)
	if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
		return result  ; Signed vs. unsigned doesn't matter in these cases.
	; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
	return -(0xFFFFFFFF - result + 1)
}

DecToBin(In_Val)
{
	local bit, bin, dec
	if In_Val is not integer
	return, "ERROR"
	dec:=In_Val
	Loop
	{
		bit:=mod(dec, 2)
		dec:=dec//2
		bin=%bit%%bin%
		IfEqual, dec, 0, break
  }
	return, %bin%
}

msgbox, % GetCommState(4)
listvars
pause


Edit: Changed naming of variables and return values.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Nice-looking script. I like how you documented the complete structure and the purpose of each of its members.

olfen
  • Members
  • 115 posts
  • Last active: Dec 25 2012 09:48 AM
  • Joined: 04 Jun 2005

I like how you documented the complete structure and the purpose of each of its members.

I have to disappoint you. It is extracted from Winbase.h :) .

Meanwhile, I also got BuildCommDCB and SetCommState working and am looking forward to posting it after further testing.

Browsing MSDN I stumbled across WaitCommEvent:

The WaitCommEvent function waits for an event to occur for a specified communications device. The set of events that are monitored by this function is contained in the event mask associated with the device handle.

The WaitCommEvent function should be executed as an overlapped operation so the other threads of the process can perform I/O operations during the wait.

Can it be "executed as an overlapped operation" in AutoHotkey?
Would this make it possible to have a rudimentary serial terminal?

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004

Can [WaitCommEvent] be "executed as an overlapped operation" in AutoHotkey? Would this make it possible to have a rudimentary serial terminal?

I don't know enough about it to give a useful answer. Maybe someone else here knows.

wisely
  • Guests
  • Last active:
  • Joined: --

I also got BuildCommDCB and SetCommState working and am looking forward to posting it after further testing.
Browsing MSDN I stumbled across WaitCommEvent:

olfen, please i would like to know when you are going to post your working BuildCommDCB and SetCommState functions :?:
And thanks for the GetCommState function

olfen
  • Members
  • 115 posts
  • Last active: Dec 25 2012 09:48 AM
  • Joined: 04 Jun 2005
Sorry, I had forgotten about it. I cannot remember, if this snippet works ok. Please test.
#NoEnv



; http://msdn2.microsoft.com/en-us/library/aa363214.aspx

VarSetCapacity(DCB, 28)



; http://msdn.microsoft.com/library/en-us/devio/base/buildcommdcb.asp

; The string must have the same form as the mode command's command-line arguments:

; COMx[:][baud=b][parity=p][data=d][stop=s][to={on|off}][xon={on|off}][odsr={on|off}][octs={on|off}][dtr={on|off|hs}][rts={on|off|hs|tg}][idsr={on|off}] 

mode = COM1:baud=9600 parity=N data=8 stop=1

DllCall("BuildCommDCB", "str",mode, "uint",&DCB)



; http://msdn2.microsoft.com/en-us/library/aa363858.aspx

hCOMM := DllCall("CreateFile", "Str","COM1:" ,"Uint",0x80000000, "Uint",3, "UInt",0, "UInt",3, "Uint",0, "UInt",0)



; http://msdn2.microsoft.com/en-us/library/aa363436.aspx

DllCall("SetCommState", "Uint",hCOMM, "uint",&DCB)



DllCall("CloseHandle", "Uint",hCOMM)