News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Serial DCB BITRECORD structure in windows.inc

Started by pcMike, September 21, 2017, 03:28:23 AM

Previous topic - Next topic

pcMike

I found a serial port monitor in the old forum posted by Redskull in 2006, and it fails to build due to not recognizing  the DCB BITRECORD structure.
http://www.masmforum.com/board/index.php?topic=5972.0

Quote
.486
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

.data
szFrameError db "!"                            ; Display character for errors
displaystring1 db "Monitoring for Data:",0     ; Output display string

.data?
hSerialPort DWORD ?                             ; handle for serial port
SerialSettings DCB {?}                          ; settings for serial port
SerialTimeOuts COMMTIMEOUTS {?}                 ; timeout settings for serial port
NumberOfBytesRead DWORD ?                       ; rcv variable for bytes read from ReadFile
EvtMask DWORD ?                                 ; rcv variable for comm event returned
SerialError DWORD ?                             ; holder for error occured
RcvBuffer DWORD ?                               ; variable for holding input to go to screen

hConsoleOutput DWORD ?                          ; Handle to the display console
ConsoleWriteBytes DWORD ?                       ; rcv variable for bytes written to console

.const
Comm1 db "COM1:", 0                             ; Comm port constants
Comm2 db "COM2:", 0
Comm3 db "COM3:", 0

.code
start:
;-----------------------------
; Allocate a console for displaying output
;-----------------------------
invoke AllocConsole
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov hConsoleOutput, eax
; do not process control codes, display thier hex equivalents
invoke SetConsoleMode, hConsoleOutput, ENABLE_WRAP_AT_EOL_OUTPUT

;-----------------------------
; Serial Port initialization
;-----------------------------
invoke CreateFile, ADDR Comm1, GENERIC_READ OR\         ; Open the Serial Port
    GENERIC_WRITE,0, NULL, OPEN_EXISTING,0,NULL
mov hSerialPort, eax                                    ; save the handle
mov SerialSettings.DCBlength, SIZEOF DCB                ; configure the Settings variable
invoke GetCommState, hSerialPort, ADDR SerialSettings   ; fill it with the current settings
mov SerialSettings.BaudRate, CBR_19200                  ; Baud Rate
mov SerialSettings.ByteSize, 8                          ; Data Bits: 8
mov SerialSettings.Parity, NOPARITY                     ; Parity: None
mov SerialSettings.StopBits, ONESTOPBIT                 ; Stop Bits: 1
mov SerialSettings.fOutxCtsFlow, FALSE                  ; No RTS
mov SerialSettings.fRtsControl, RTS_CONTROL_DISABLE     ; No CTS
mov SerialSettings.fOutxDsrFlow, FALSE                  ; No DSR TX inhibiting
mov SerialSettings.fDsrSensitivity, FALSE               ; No DSR RX inhibiting
mov SerialSettings.fDtrControl, DTR_CONTROL_ENABLE      ; Enable DTR Signal
mov SerialSettings.fOutX, TRUE                          ; xOn/xOff enabled for TX
mov SerialSettings.fInX, FALSE                          ; Suspend Xon/Xoff for RCV
mov SerialSettings.fNull, TRUE                          ; Discard NULL bytes
mov SerialSettings.fAbortOnError, FALSE                 ; Do not Abort on Error
mov SerialSettings.fBinary, TRUE                        ; Binary Transfer
mov SerialSettings.fParity, TRUE                        ; Parity Enabled
invoke SetCommState, hSerialPort, ADDR SerialSettings   ; Apply the new settinsg

; Set the Time-outs to occur immedietly with everything in the buffer
invoke GetCommTimeouts, hSerialPort, ADDR SerialTimeOuts
mov SerialTimeOuts.ReadIntervalTimeout, MAXDWORD
mov SerialTimeOuts.ReadTotalTimeoutMultiplier, 0
mov SerialTimeOuts.ReadTotalTimeoutConstant, 0
mov SerialTimeOuts.WriteTotalTimeoutMultiplier, 0
mov SerialTimeOuts.WriteTotalTimeoutConstant, 0
invoke SetCommTimeouts, hSerialPort, ADDR SerialTimeOuts

;Generate events for received bytes and errors
invoke SetCommMask, hSerialPort, (EV_RXCHAR OR EV_ERR)
;------------------------------------------------------

invoke WriteConsole, hConsoleOutput, ADDR displaystring1, \  ; display a prompt
    SIZEOF displaystring1, ADDR NumberOfBytesRead, NULL
   
;-----------------------------
; Poll the serial port for RCV data
;-----------------------------

.WHILE TRUE                                                 ; Enter an endless loop
invoke WaitCommEvent, hSerialPort, ADDR EvtMask, NULL      ; Hold up for either a character or an error

.IF EvtMask == EV_ERR                                      ; If an error came in...
  invoke SetConsoleTextAttribute, hConsoleOutput,\          ; change to a red font
   FOREGROUND_RED
  invoke WriteConsole, hConsoleOutput, ADDR szFrameError,\  ; print an exclamation point
   SIZEOF szFrameError, ADDR ConsoleWriteBytes, NULL
  invoke SetConsoleTextAttribute, hConsoleOutput,\          ; change back to white font
   FOREGROUND_BLUE OR FOREGROUND_GREEN OR FOREGROUND_RED
  invoke ClearCommError, hSerialPort, ADDR SerialError, NULL; clear the error
.ENDIF

.IF EvtMask == EV_RXCHAR                                   ; if a chracter was recieved...
  .WHILE TRUE                                               ; start a loop to empty out the serial port
   invoke ReadFile, hSerialPort, RcvBuffer, SIZEOF\         ; Read in one DWORD from the serial port
    RcvBuffer, ADDR NumberOfBytesRead, NULL
   .BREAK .IF NumberOfBytesRead == 0                        ; exit if the buffer is empty
   invoke WriteConsole, hConsoleOutput, RcvBuffer,\         ; print out any characters recieved
    NumberOfBytesRead, ADDR ConsoleWriteBytes, NULL
  .ENDW
.ENDIF
.ENDW

invoke CloseHandle, hSerialPort                             ; close the serial port
invoke ExitProcess, NULL                                     ; End the Program

END start

It fails to assemble due all the <BITRECORD> values below generate "error A2600: undefined symbol" messages:

mov SerialSettings.fOutxCtsFlow, FALSE                  ; No RTS
mov SerialSettings.fRtsControl, RTS_CONTROL_DISABLE     ; No CTS
mov SerialSettings.fOutxDsrFlow, FALSE                  ; No DSR TX inhibiting
mov SerialSettings.fDsrSensitivity, FALSE               ; No DSR RX inhibiting
mov SerialSettings.fDtrControl, DTR_CONTROL_ENABLE      ; Enable DTR Signal
mov SerialSettings.fOutX, TRUE                          ; xOn/xOff enabled for TX
mov SerialSettings.fInX, FALSE                          ; Suspend Xon/Xoff for RCV
mov SerialSettings.fNull, TRUE                          ; Discard NULL bytes
mov SerialSettings.fAbortOnError, FALSE                 ; Do not Abort on Error
mov SerialSettings.fBinary, TRUE                        ; Binary Transfer

I checked windows.inc and I see they are listed as part of the DCB:
BITRECORD RECORD fBinary:1,fParity:1,fOutxCtsFlow:1,fOutxDsrFlow:1,fDtrControl:2,fDsrSensitivity:1,fTXContinueOnXoff:1,fOutX:1,fInX:1,fErrorChar:1,fNull:1,fRtsControl:2,fAbortOnError:1,fDummy2:17

DCB STRUCT
  DCBlength     DWORD      ?
  BaudRate      DWORD       ?
  fbits         BITRECORD      <>
  wReserved     WORD       ?
  XonLim        WORD          ?
  XoffLim       WORD         ?
  ByteSize      BYTE        ?
  Parity        BYTE          ?
  StopBits      BYTE        ?
  XonChar       BYTE         ?
  XoffChar      BYTE        ?
  ErrorChar     BYTE       ?
  EofChar       BYTE         ?
  EvtChar       BYTE         ?
  wReserved1    WORD       ?
DCB ENDS

Can someone tell me what I needs to be done to get past the errors?

Mike

jj2007

You need to set the bits manually...
if 1
  mov edx, 1*xxx+2*yyy+4*zzz+.... 
else
  mov SerialSettings.fOutxCtsFlow, FALSE                  ; No RTS
  mov SerialSettings.fRtsControl, RTS_CONTROL_DISABLE     ; No CTS
  mov SerialSettings.fOutxDsrFlow, FALSE                  ; No DSR TX inhibiting
  mov SerialSettings.fDsrSensitivity, FALSE               ; No DSR RX inhibiting
  mov SerialSettings.fDtrControl, DTR_CONTROL_ENABLE      ; Enable DTR Signal
  mov SerialSettings.fOutX, TRUE                          ; xOn/xOff enabled for TX
  mov SerialSettings.fInX, FALSE                          ; Suspend Xon/Xoff for RCV
  mov SerialSettings.fNull, TRUE                          ; Discard NULL bytes
  mov SerialSettings.fAbortOnError, FALSE                 ; Do not Abort on Error
  mov SerialSettings.fBinary, TRUE                        ; Binary Transfer
  mov SerialSettings.fParity, TRUE                        ; Parity Enabled
endif


There is also a SetField macro in the MasmBasic package, but honestly, I've never used it.

See also
http://masm32.com/board/index.php?topic=6293.0
http://www.masmforum.com/board/index.php?topic=17452.0
http://www.masmforum.com/board/index.php?topic=13386.msg104286#msg104286

pcMike

Thanks JJ, but something is still not right...

I read somewhere that the DCB and BITRECORD structure is being stored in reverse order in Windows.inc. Do you know if that is true?

When I run the program, it fails at SetComState if changes are made to the DCB settings - even if I only change the Baud Rate, Data Bits, Parity, and Stop bits to the suggested "19200,8,N,1" and all other parameters are left as is SetComState will fail.

If I don't change the serial settings read by GetComState and I bypass SetComState, then the WaitCommEvent function hangs, although I am sending data to the other end of the COM port the console only shows "Monitoring for Data". I even checked that data is received on the port using MS PortMon.

Here is the updated code:

Quote
.486
.model flat, stdcall
option casemap:none

include \masm32\include\masm32rt.inc

.data
szFrameError db "!"                            ; Display character for errors
displaystring1 db "Monitoring for Data:",0     ; Output display string
.data?

myDCB   STRUCT
   DCBlength  DWORD ?  ; sizeof(DCB)                     
   BaudRate   DWORD ?  ; Baudrate at which running       
   fbits      DWORD ?             
   XonLim     WORD  ?  ; Transmit X-ON threshold         
   XoffLim    WORD  ?  ; Transmit X-OFF threshold       
   ByteSize   BYTE  ?  ; Number of bits/byte, 4-8       
   Parity     BYTE  ?  ; 0-4=None,Odd,Even,Mark,Space   
   StopBits   BYTE  ?  ; 0,1,2 = 1, 1.5, 2               
   XonChar    BYTE  ?  ; Tx and Rx X-ON character       
   XoffChar   BYTE  ?  ; Tx and Rx X-OFF character       
   ErrorChar  BYTE  ?  ; Error replacement char         
   EofChar    BYTE  ?  ; End of Input character         
   EvtChar    BYTE  ?  ; Received Event character       
   wReserved1 WORD  ?  ; Fill for now.                   
myDCB      ENDS

mBinary           EQU 1
mParity           EQU 2
mOutxCtsFlow      EQU 4
mOutxDsrFlow      EQU 8
mDtrControl       EQU 16
mDsrSensitivity   EQU 32
mTXContinueOnXoff EQU 64
mOutX             EQU 128
mInX              EQU 256
mErrorChar        EQU 512
mNull             EQU 1024
mRtsControl       EQU 2048
mAbortOnError     EQU 4096


hSerialPort DWORD ?                             ; handle for serial port
SerialSettings myDCB {?}                          ; settings for serial port
SerialTimeOuts COMMTIMEOUTS {?}                 ; timeout settings for serial port
NumberOfBytesRead DWORD ?                       ; rcv variable for bytes read from ReadFile
EvtMask DWORD ?                                 ; rcv variable for comm event returned
SerialError DWORD ?                             ; holder for error occured
RcvBuffer DWORD ?                               ; variable for holding input to go to screen

hConsoleOutput DWORD ?                          ; Handle to the display console
ConsoleWriteBytes DWORD ?                       ; rcv variable for bytes written to console

.const
Comm1 db "COM1:", 0                             ; Comm port constants
Comm2 db "COM2:", 0
Comm3 db "COM3:", 0

.code
start:
;-----------------------------
; Allocate a console for displaying output
;-----------------------------
invoke AllocConsole
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov hConsoleOutput, eax

; do not process control codes, display thier hex equivalents
invoke SetConsoleMode, hConsoleOutput, ENABLE_WRAP_AT_EOL_OUTPUT

;-----------------------------
; Serial Port initialization
;-----------------------------
invoke CreateFile, ADDR Comm2, GENERIC_READ OR\         ; Open the Serial Port
    GENERIC_WRITE,0, NULL, OPEN_EXISTING,0,NULL
cmp eax,INVALID_HANDLE_VALUE
jne ok0
print "Cant open COM port"

ok0:
mov hSerialPort, eax                                    ; save the handle

mov SerialSettings.DCBlength, SIZEOF myDCB                ; configure the Settings variable
invoke GetCommState, hSerialPort, ADDR SerialSettings   ; fill it with the current settings
test eax,eax
jnz ok1
print "GetCommState failed"
jmp Exit

ok1:
mov SerialSettings.BaudRate, CBR_19200                  ; Baud Rate
mov SerialSettings.ByteSize, 8                          ; Data Bits: 8
mov SerialSettings.Parity, NOPARITY                     ; Parity: None
mov SerialSettings.StopBits, ONESTOPBIT                 ; Stop Bits: 1
;jmp setcomm
mov SerialSettings.fOutxCtsFlow, FALSE                  ; No RTS
mov SerialSettings.fRtsControl, RTS_CONTROL_DISABLE     ; No CTS
mov SerialSettings.fOutxDsrFlow, FALSE                  ; No DSR TX inhibiting
mov SerialSettings.fDsrSensitivity, FALSE               ; No DSR RX inhibiting
mov SerialSettings.fDtrControl, DTR_CONTROL_ENABLE      ; Enable DTR Signal
mov SerialSettings.fOutX, TRUE                          ; xOn/xOff enabled for TX
mov SerialSettings.fInX, FALSE                          ; Suspend Xon/Xoff for RCV
mov SerialSettings.fNull, TRUE                          ; Discard NULL bytes
mov SerialSettings.fAbortOnError, FALSE                 ; Do not Abort on Error
mov SerialSettings.fBinary, TRUE                        ; Binary Transfer
mov SerialSettings.fParity, TRUE                        ; Parity Enabled

mov eax, (mDtrControl+mOutX+mNull+mBinary+fParity)
mov SerialSettings.fbits,eax

setcomm:
invoke SetCommState, hSerialPort, ADDR SerialSettings   ; Apply the new settinsg
test eax,eax
jnz ok2
print "SetCommState failed"
jmp Exit

ok2:

; Set the Time-outs to occur immedietly with everything in the buffer
invoke GetCommTimeouts, hSerialPort, ADDR SerialTimeOuts
test eax,eax
jnz ok3
print "GetCommTimeouts failed"
jmp Exit

ok3:

mov SerialTimeOuts.ReadIntervalTimeout, MAXDWORD
mov SerialTimeOuts.ReadTotalTimeoutMultiplier, 0
mov SerialTimeOuts.ReadTotalTimeoutConstant, 0
mov SerialTimeOuts.WriteTotalTimeoutMultiplier, 0
mov SerialTimeOuts.WriteTotalTimeoutConstant, 0
invoke SetCommTimeouts, hSerialPort, ADDR SerialTimeOuts
test eax,eax
jnz ok4
print "SetCommTimeouts failed"
jmp Exit

ok4:

;Generate events for received bytes and errors
invoke SetCommMask, hSerialPort, (EV_RXCHAR OR EV_ERR)
;------------------------------------------------------

invoke WriteConsole, hConsoleOutput, ADDR displaystring1, \  ; display a prompt
    SIZEOF displaystring1, ADDR NumberOfBytesRead, NULL
   
;-----------------------------
; Poll the serial port for RCV data
;-----------------------------

.WHILE TRUE                                                 ; Enter an endless loop
invoke WaitCommEvent, hSerialPort, ADDR EvtMask, NULL      ; Hold up for either a character or an error

test eax,eax
jnz ok5
print "WaitCommEvent failed",13,10
jmp Exit

ok5:

;invoke WriteConsole, hConsoleOutput, ADDR displayx, \  ; display a prompt
;   SIZEOF displayx, ADDR NumberOfBytesRead, NULL

.IF EvtMask == EV_ERR                                      ; If an error came in...
  invoke SetConsoleTextAttribute, hConsoleOutput,\          ; change to a red font
   FOREGROUND_RED
  invoke WriteConsole, hConsoleOutput, ADDR szFrameError,\  ; print an exclamation point
   SIZEOF szFrameError, ADDR ConsoleWriteBytes, NULL
  invoke SetConsoleTextAttribute, hConsoleOutput,\          ; change back to white font
   FOREGROUND_BLUE OR FOREGROUND_GREEN OR FOREGROUND_RED
  invoke ClearCommError, hSerialPort, ADDR SerialError, NULL; clear the error
.ENDIF

.IF EvtMask == EV_RXCHAR                                   ; if a chracter was recieved...
  .WHILE TRUE                                               ; start a loop to empty out the serial port
   invoke ReadFile, hSerialPort, RcvBuffer, SIZEOF\         ; Read in one DWORD from the serial port
    RcvBuffer, ADDR NumberOfBytesRead, NULL
   .BREAK .IF NumberOfBytesRead == 0                        ; exit if the buffer is empty
   invoke WriteConsole, hConsoleOutput, RcvBuffer,\         ; print out any characters recieved
    NumberOfBytesRead, ADDR ConsoleWriteBytes, NULL
  .ENDW
.ENDIF
.ENDW

Exit:
invoke CloseHandle, hSerialPort                             ; close the serial port
invoke ExitProcess, NULL                                     ; End the Program

END start

Mike

Siekmanski

Hi Mike,

We have discussed the DCB and BITRECORD structure in this thread: http://masm32.com/board/index.php?topic=6288.0
Creative coders use backward thinking techniques as a strategy.

jj2007

Thanks, Marinus - that thread is over three months old, I didn't remember ;-)

Final outcome was the _Record macro here: http://masm32.com/board/index.php?topic=6296.msg67393#msg67393
include \masm32\include\masm32rt.inc
include BitRecord.mac

.code
start:
  print "00000000000000000010000000101101", 9, "expected", crlf
  print bin$(_Record(TRUE,FALSE,TRUE,TRUE,DTR_CONTROL_HANDSHAKE:2,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,RTS_CONTROL_HANDSHAKE:2,FALSE,0)), crlf
  inkey bin$(_RecordRev(0,FALSE,RTS_CONTROL_HANDSHAKE:2,FALSE,FALSE, FALSE,FALSE,FALSE,FALSE,DTR_CONTROL_HANDSHAKE:2,TRUE,TRUE,NULL,TRUE)), crlf
  exit
end start

jimg

I disagree.  The final correct result is to define the record properly, not like it is in windows.inc

aw27

The declaration of BITRECORD in Windows.inc is indeed wrong because follows the C/C++ convention, when in ASM the order is the inverse.

This is a sample with the modified BITRECORD :


.386
.model      flat,stdcall
option      casemap:none

;include \masm32\include\windows.inc
includelib \masm32\lib\msvcrt.lib
printf proto C :ptr, :vararg

BITRECORD RECORD fDummy2:17,fAbortOnError:1,fRtsControl:2, fNull:1,fErrorChar:1,fInX:1,fOutX:1, fTXContinueOnXoff:1,fDsrSensitivity:1,fDtrControl:2,fOutxDsrFlow:1,fOutxCtsFlow:1,fParity:1,fBinary:1

DCB STRUCT
  DCBlength     DWORD      ?
  BaudRate      DWORD       ?
  fbits         BITRECORD      <>
  wReserved     WORD       ?
  XonLim        WORD          ?
  XoffLim       WORD         ?
  ByteSize      BYTE        ?
  Parity        BYTE          ?
  StopBits      BYTE        ?
  XonChar       BYTE         ?
  XoffChar      BYTE        ?
  ErrorChar     BYTE       ?
  EofChar       BYTE         ?
  EvtChar       BYTE         ?
  wReserved1    WORD       ?
DCB ENDS

FieldSet MACRO SrcDotField, TheVal
LOCAL is, src, field
  is INSTR <SrcDotField>, <.>
  if is eq 0
.err <*** source.field required ***>
  endif
  src SUBSTR <SrcDotField>, 1, is-1
  field SUBSTR <SrcDotField>, is+1
  ifdifi <TheVal>, <eax>   
mov eax, TheVal
  endif
  if field
shl eax, field
  endif
  and src, not mask field
  add src, eax
ENDM



.data
fmt db "%c",0

.code

binPrint proc uses ebx esi value:dword
mov esi, value
mov ebx, 32
.while ebx
.if (esi & 80000000h)
INVOKE printf, offset fmt, "1"
.else
INVOKE printf, offset fmt, "0"
.endif
shl esi, 1
dec ebx
.endw
ret
binPrint endp

main proc
LOCAL bitrec : BITRECORD

mov bitrec, 0
FieldSet bitrec.fBinary, 1
FieldSet bitrec.fOutxCtsFlow, 0
FieldSet bitrec.fOutxDsrFlow, 0
FieldSet bitrec.fDtrControl, 1 ; DTR_CONTROL_ENABLE     0x01
FieldSet bitrec.fDsrSensitivity, 0
FieldSet bitrec.fOutX, 1
FieldSet bitrec.fInX, 0
FieldSet bitrec.fNull, 1
FieldSet bitrec.fRtsControl, 0 ; RTS_CONTROL_DISABLE    0x00
FieldSet bitrec.fAbortOnError, 0

mov eax, bitrec
INVOKE binPrint, eax
ret
main endp

end main


pcMike

#7
Thanks everyone for the replies. I agree with jimg that the windows.inc should be corrected. I just wonder if Hutch would agree.

Siekmanski: Thanks for the link to the other thread. I downloaded your RS232 code and it will be very useful.

JJ: Your Bitrecord macro was very helpful. The data is now in the correct order and  SetCommState no longer generates an error.

Initially I was still unable to get redskull's "Simple Serial Port monitor" to show that any data was being received, but after looking the code over I noticed he left out the "ADDR" before the "RecvBuffer" a couple places, and once I added that it worked perfectly! Maybe he forgot to test it before posting, as the backwards bitrecord should also have prevented it from working unless an older version of MASM32 included the working windows.inc perhaps.

In case it helps anyone else, here is the working version of the Serial Port Monitor:

Quote
; Serial Port Monitor using WaitCommEvent. Original author: redskull
.486
.model flat, stdcall
option casemap:none

include \masm32\include\masm32rt.inc
include \masm32\BitRecord.mac

.data
szFrameError db "!"                            ; Display character for errors
displaystring1 db "Monitoring for Data:",0     ; Output display string

.data?
hSerialPort DWORD ?                             ; handle for serial port
SerialSettings DCB {?}                          ; settings for serial port
SerialTimeOuts COMMTIMEOUTS {?}                 ; timeout settings for serial port
NumberOfBytesRead DWORD ?                       ; rcv variable for bytes read from ReadFile
EvtMask DWORD ?                                 ; rcv variable for comm event returned
SerialError DWORD ?                             ; holder for error occured
RcvBuffer DWORD ?                               ; variable for holding input to go to screen
hConsoleOutput DWORD ?                          ; Handle to the display console
ConsoleWriteBytes DWORD ?                       ; rcv variable for bytes written to console

.const
Comm1 db "COM1", 0                             ; Comm port constants
Comm2 db "COM2", 0
Comm3 db "COM3", 0
Comm4 db "COM4", 0

.code
start:
;-----------------------------
; Allocate a console for displaying output
;-----------------------------
invoke AllocConsole
invoke GetStdHandle, STD_OUTPUT_HANDLE
mov hConsoleOutput, eax

; do not process control codes, display thier hex equivalents
invoke SetConsoleMode, hConsoleOutput, ENABLE_WRAP_AT_EOL_OUTPUT

;-----------------------------
; Serial Port initialization
;-----------------------------
invoke CreateFile, ADDR Comm4, GENERIC_READ OR\         ; Open the Serial Port
    GENERIC_WRITE,0, NULL, OPEN_EXISTING,0,NULL
cmp eax,INVALID_HANDLE_VALUE
jne ok0
print "Cant open COM port"
jmp Exit

ok0:
mov hSerialPort, eax                                    ; save the handle
mov SerialSettings.DCBlength, SIZEOF DCB                ; configure the Settings variable
invoke GetCommState, hSerialPort, ADDR SerialSettings   ; fill it with the current settings
test eax,eax
jnz ok1
print "GetCommState failed"
jmp Exit

ok1:
mov SerialSettings.BaudRate, CBR_19200                  ; Baud Rate
mov SerialSettings.ByteSize, 8                          ; Data Bits: 8
mov SerialSettings.Parity, NOPARITY                     ; Parity: None
mov SerialSettings.StopBits, ONESTOPBIT                 ; Stop Bits: 1

;mov SerialSettings.fRtsControl, RTS_CONTROL_DISABLE     ; No CTS
;mov SerialSettings.fOutxDsrFlow, FALSE                  ; No DSR TX inhibiting
;mov SerialSettings.fDsrSensitivity, FALSE               ; No DSR RX inhibiting
;mov SerialSettings.fDtrControl, DTR_CONTROL_ENABLE      ; Enable DTR Signal
;mov SerialSettings.fOutX, TRUE                          ; xOn/xOff enabled for TX
;mov SerialSettings.fInX, FALSE                          ; Suspend Xon/Xoff for RCV
;mov SerialSettings.fNull, TRUE                          ; Discard NULL bytes
;mov SerialSettings.fAbortOnError, FALSE                 ; Do not Abort on Error
;mov SerialSettings.fBinary, TRUE                        ; Binary Transfer
;mov SerialSettings.fParity, TRUE                        ; Parity Enabled

mov eax,(_Record(NULL,FALSE,RTS_CONTROL_DISABLE:2,TRUE,FALSE,FALSE,FALSE,TRUE,FALSE,DTR_CONTROL_DISABLE:2,FALSE,FALSE,FALSE,TRUE))
mov SerialSettings.fbits,eax
;print bin$(eax), 32

; fBinary: 1;          /* Binary Mode (skip EOF check)    */
; fParity: 1;          /* Enable parity checking          */
; fOutxCtsFlow:1;      /* CTS handshaking on output       */
; fOutxDsrFlow:1;      /* DSR handshaking on output       */
; fDtrControl:2;       /* DTR Flow control                */
; fDsrSensitivity:1;   /* DSR Sensitivity                 */
; fTXContinueOnXoff:1; /* Continue TX when Xoff sent      */
; fOutX: 1;            /* Enable output X-ON/X-OFF        */
; fInX: 1;             /* Enable input X-ON/X-OFF         */
; fErrorChar: 1;       /* Enable Err Replacement          */
; fNull: 1;            /* Enable Null stripping           */
; fRtsControl:2;       /* Rts Flow control                */
; fAbortOnError:1;     /* Abort reads and writes on Error */
; NULL

setcomm:
invoke SetCommState, hSerialPort, ADDR SerialSettings   ; Apply the new settinsg
test eax,eax
jnz ok2
print "SetCommState failed"
jmp Exit

ok2:

; Set the Time-outs to occur immedietly with everything in the buffer
invoke GetCommTimeouts, hSerialPort, ADDR SerialTimeOuts
test eax,eax
jnz ok3
print "GetCommTimeouts failed"
jmp Exit

ok3:

mov SerialTimeOuts.ReadIntervalTimeout, MAXDWORD
mov SerialTimeOuts.ReadTotalTimeoutMultiplier, 1
mov SerialTimeOuts.ReadTotalTimeoutConstant, 1
mov SerialTimeOuts.WriteTotalTimeoutMultiplier, 1
mov SerialTimeOuts.WriteTotalTimeoutConstant, 1
invoke SetCommTimeouts, hSerialPort, ADDR SerialTimeOuts
test eax,eax
jnz ok4
print "SetCommTimeouts failed"
jmp Exit

ok4:

;Generate events for received bytes and errors
invoke SetCommMask, hSerialPort, (EV_RXCHAR OR EV_ERR)
;------------------------------------------------------

invoke WriteConsole, hConsoleOutput, ADDR displaystring1, \  ; display a prompt
    SIZEOF displaystring1, ADDR NumberOfBytesRead, NULL
   
;-----------------------------
; Poll the serial port for RCV data
;-----------------------------

.WHILE TRUE                                                 ; Enter an endless loop
invoke WaitCommEvent, hSerialPort, ADDR EvtMask, NULL       ; Hold up for either a character or an error

test eax,eax
jnz ok5
print "WaitCommEvent failed",13,10
jmp Exit

ok5:

.IF EvtMask == EV_ERR                                       ; If an error came in...
  invoke SetConsoleTextAttribute, hConsoleOutput,\          ; change to a red font
   FOREGROUND_RED
  invoke WriteConsole, hConsoleOutput, ADDR szFrameError,\  ; print an exclamation point
   SIZEOF szFrameError, ADDR ConsoleWriteBytes, NULL
  invoke SetConsoleTextAttribute, hConsoleOutput,\          ; change back to white font
   FOREGROUND_BLUE OR FOREGROUND_GREEN OR FOREGROUND_RED
  invoke ClearCommError, hSerialPort, ADDR SerialError, NULL; clear the error
.ENDIF

.IF EvtMask == EV_RXCHAR                                    ; if a chracter was recieved...
  .WHILE TRUE                                               ; start a loop to empty out the serial port
   invoke ReadFile, hSerialPort, ADDR RcvBuffer, SIZEOF\         ; Read in one DWORD from the serial port
    RcvBuffer, ADDR NumberOfBytesRead, NULL
   mov eax,NumberOfBytesRead
   .BREAK .IF NumberOfBytesRead == 0                        ; exit if the buffer is empty
   invoke WriteConsole, hConsoleOutput, ADDR RcvBuffer,\    ; print out any characters recieved
    NumberOfBytesRead, ADDR ConsoleWriteBytes, NULL
  .ENDW
.ENDIF
.ENDW

Exit:
invoke CloseHandle, hSerialPort                             ; close the serial port
invoke ExitProcess, NULL                                     ; End the Program

END start

Mike

[Edit: typo]

jj2007

Thanks for posting the code, Mike. It builds fine but doesn't work on my machine, probably no active port ("can't find the specified file") ::)

pcMike

JJ:  If your COM port is a higher number then COM4, then it needs to be defined like this:

Comm5 db "\\.\COM5", 0


Mike


jj2007

It seems this notebook really has NO COM port :(

aw27

Quote from: jj2007 on September 22, 2017, 08:33:47 AM
It seems this notebook really has NO COM port :(
I have not seen a computer with a serial adapter since last century.
But there are still a couple of uses for virtual serial ports.

hutch--

Mike,

>  I just wonder if Hutch would agree.

In a Windows world where 32 bit is in its twilight, 64 bit is on the rise, I simply don't care about ancient compatibility. There has always been a solution to the problem you are facing, write your own and you will get exactly what you want. I have 64 bit MASM code to write.

felipe