From: Gunter on
Who can help me?
I want to read out the content ( hexbyte sequence) of an image scanner
(honeywell 4600g).
It is installed as USB COM port emulation, that provides the Port COM3
(IT4600 Area Imager).
The Barcode I have to read out is Datamatrixcode with 42 byte.

thanks for help

Gunter Huebner
From: Ginny Caughey on
There are a couple of serial classes for VO around - I wrote one called just
Serial I think, and Fabrice wrote one too - FabSerial maybe?

--

Ginny Caughey
www.wasteworks.com




From: Gunter on
On Jun 3, 4:04 pm, "Ginny Caughey"
<ginny.caughey.onl...(a)wasteworks.com> wrote:
> There are a couple of serial classes for VO around - I wrote one called just
> Serial I think, and Fabrice wrote one too - FabSerial maybe?
>
> --
>
> Ginny Caugheywww.wasteworks.com

Thanks, where can I find your serial class?
Gunter Huebenr
From: Ginny Caughey on
I'm not sure where it's available these days. Anyway this is the code I'm
using currently:

STRUCTURE CommData

MEMBER hCommFile AS PTR // Handle to the serial session
MEMBER hWindowToNotify AS PTR // Which window to notify
MEMBER dwEvent AS DWORD // Which comm events to watch for
MEMBER lWorkerMustStop AS LOGIC // Tells worker thread to stop running
MEMBER lWorkerIsStopped AS LOGIC // Indicates if worker thread is running
CLASS Serial

~"ONLYEARLY+"

PROTECT hCommFile AS PTR // Handle to comm "file"
PROTECT lEventsEnabled AS LOGIC // Flag to notify a window with events

// This structure must be declared using AS rather than IS
// because it's shared by more than one thread. In other words,
// you have to Memalloc() memory for it in static storage.
PROTECT struCommData AS CommData // Communication data structure

// And these structures must be decalred using AS rather than IS
// because they are passed by reference to Windows.
PROTECT struDCB AS _WinDCB // Device control block
structure
PROTECT struTimeOuts AS _WinCommTimeOuts // Timeouts structure

PROTECT nErrorCode AS INT // Error code from the communication
session
PROTECT sErrorDesc AS STRING // Error message from the communication
session
PROTECT hWindowToNotify AS PTR // Window to notify with communication
events
PROTECT nTxBufferSize AS DWORD // Size of the transmission buffer
PROTECT nRxBufferSize AS DWORD // Size of the reception buffer
PROTECT lIsOpen AS LOGIC // Flag for an open communication
session

DECLARE ACCESS Baud
DECLARE ASSIGN Baud
DECLARE ACCESS ByteSize
DECLARE ASSIGN ByteSize
DECLARE ACCESS ErrorCode
DECLARE ACCESS ErrorDesc
DECLARE ACCESS Handle
DECLARE ACCESS IsOpen
DECLARE ACCESS Parity
DECLARE ASSIGN Parity
DECLARE ACCESS StopBits
DECLARE ASSIGN StopBits
DECLARE ACCESS ReadIntervalTimeout
DECLARE ASSIGN ReadIntervalTimeout
DECLARE ACCESS ReadTimeoutConstant
DECLARE ASSIGN ReadTimeoutConstant
DECLARE ACCESS ReadTimeoutMultiplier
DECLARE ASSIGN ReadTimeoutMultiplier
DECLARE ACCESS ReceiveBufferSize
DECLARE ASSIGN ReceiveBufferSize
DECLARE ACCESS ReceiverPending
DECLARE ACCESS TransmitBufferSize
DECLARE ASSIGN TransmitBufferSize
DECLARE ACCESS WriteTimeoutConstant
DECLARE ASSIGN WriteTimeoutConstant
DECLARE ACCESS WriteTimeoutMultiplier
DECLARE ASSIGN WriteTimeoutMultiplier

DECLARE METHOD Close
DECLARE METHOD DisableEvents
DECLARE METHOD EnableEvents
DECLARE METHOD Flush
DECLARE METHOD GetProtocol
DECLARE METHOD GetTimeout
DECLARE METHOD Open
DECLARE METHOD Read
DECLARE METHOD SetProtocol
DECLARE METHOD SetTimeout
DECLARE METHOD Write

~"ONLYEARLY-"
METHOD Init( hWindow ) CLASS Serial

~"ONLYEARLY+"

// If a valid window handle was passed...
IF !( IsNil( hWindow ) )

// Store the window handle for later use.
SELF:hWindowToNotify := hWindow

ENDIF

// Allocate storage for structure used by worker thread.
SELF:struCommData := MemAlloc( _SIZEOF( CommData ) )
SELF:struDCB := MemAlloc( _SIZEOF( _WinDCB ) )
SELF:struTimeOuts := MemAlloc( _SIZEOF( _WinCommTimeOuts ) )

// Set default value
SELF:hCommFile := INVALID_HANDLE_VALUE

// Set the size of the transmit and receive buffers.
SELF:nTxBufferSize := 4096
SELF:nRxBufferSize := 4096

// Register the Axit() method with the garbage collector.
RegisterAxit( SELF )

RETURN( SELF )

~"ONLYEARLY-"
METHOD Axit() CLASS Serial

~"ONLYEARLY+"

// If we are not in the garbage collector...
IF !( InCollect() )

// Unregister the Axit() method with the garbage collector.
UnRegisterAxit( SELF )

ENDIF

// Release memory used by AS structure instance variable.
// Note that memory used by the IS structures are released when
// Serial objects are out of scope by the garbage collector.
MemFree( SELF:struCommData )
MemFree( SELF:struDCB )
MemFree( SELF:struTimeOuts )

RETURN( SELF )

~"ONLYEARLY-"
ACCESS Baud() AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:struDCB.BaudRate )

~"ONLYEARLY-"
ASSIGN Baud( nNew AS DWORD ) AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

// If a valid baud rate was passed...
IF ( ( nNew == CBR_110 ) .OR. ;
( nNew == CBR_300 ) .OR. ;
( nNew == CBR_600 ) .OR. ;
( nNew == CBR_1200 ) .OR. ;
( nNew == CBR_2400 ) .OR. ;
( nNew == CBR_4800 ) .OR. ;
( nNew == CBR_9600 ) .OR. ;
( nNew == CBR_14400 ) .OR. ;
( nNew == CBR_19200 ) .OR. ;
( nNew == CBR_38400 ) .OR. ;
( nNew == CBR_56000 ) .OR. ;
( nNew == CBR_128000 ) .OR. ;
( nNew == CBR_256000 ) )

// Change the baud rate.
SELF:struDCB.BaudRate := nNew

ENDIF

RETURN( struDCB.BaudRate )

~"ONLYEARLY-"
ACCESS ByteSize() AS BYTE PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:struDCB.ByteSize )

~"ONLYEARLY-"
ASSIGN ByteSize( nNew AS BYTE ) AS BYTE PASCAL CLASS Serial

~"ONLYEARLY+"

// If a valid byte size was passed...
IF ( ( nNew == 07 ) .OR. ;
( nNew == 08 ) )

// Change the byte size.
SELF:struDCB.ByteSize := nNew

ENDIF

RETURN( SELF:struDCB.ByteSize )

~"ONLYEARLY-"
METHOD Close() AS LOGIC PASCAL CLASS Serial

LOCAL lResult AS LOGIC // Flag for a successful close of the session

~"ONLYEARLY+"

// If we have a valid communications session...
IF !( SELF:hCommFile == INVALID_HANDLE_VALUE )

// If window events were enabled...
IF ( SELF:lEventsEnabled )

// Shut down worker thread if running.
SELF:DisableEvents()

ENDIF

// Flush data buffers.
SELF:Flush()

// Close device handle.
lResult := CloseHandle( SELF:hCommFile )

// If the communication session was successfully closed...
IF ( lResult )

// Invalidate the handle.
SELF:lIsOpen := FALSE
SELF:hCommFile := INVALID_HANDLE_VALUE

ELSE

// Report the error.
SELF:sErrorDesc := "CloseHandle failed."
SELF:nErrorCode := GetLastError()

ENDIF

ENDIF

RETURN( lResult )

~"ONLYEARLY-"
METHOD DisableEvents() AS LOGIC PASCAL CLASS Serial

LOCAL lResult AS LOGIC // Flag for a successful disable of the events

~"ONLYEARLY-"

// If event notification was enabled...
IF ( SELF:lEventsEnabled )

// Set global quit flag so CommWatchProc will stop running.
struCommData.lWorkerMustStop := TRUE

// If event notification was NOT successfully disabled...
IF !( SetCommMask( SELF:hCommFile, 00 ) )

// Report the error.
SELF:sErrorDesc := "SetCommMask failed in DisableEvents."
SELF:nErrorCode := GetLastError()

ELSE

// While the thread is still running...
WHILE !( struCommData.lWorkerIsStopped )

// Wait for thread to shut down but give rest of time
// slice for this thread back to Windows while waiting.
Sleep( 00 )

ENDDO

// Disable event notification.
SELF:lEventsEnabled := FALSE

// Return the success.
lResult := TRUE

ENDIF

ELSE

// Return the success.
lResult := TRUE

ENDIF

RETURN( lResult )

~"ONLYEARLY-"
METHOD EnableEvents( nEvents AS DWORD ) AS LOGIC PASCAL CLASS Serial

LOCAL ptrCommWatchThread AS PTR // Handle to the thread
LOCAL nWorkerthreadID AS DWORD // Value for the thread ID


~"ONLYEARLY+"

// If event notification was enabled...
IF ( SELF:lEventsEnabled )

RETURN( FALSE )

ENDIF

// Fill CommData structure with the data the worker thread
// will need to have access to.
SELF:struCommData.hCommFile := SELF:hCommFile
SELF:struCommData.hWindowToNotify := SELF:hWindowToNotify
SELF:struCommData.dwEvent := nEvents
SELF:struCommData.lWorkerMustStop := FALSE
SELF:struCommData.lWorkerIsStopped := TRUE

BEGIN SEQUENCE

// Create 2nd thread to watch for comm events.
ptrCommWatchThread := CreateThread( ; // Use VO
Wrapper to CreateThread()
NULL, ; // Pointer to
security attributes
00, ; // Initial
thread stack size
@CommWatchProc(), ; // Pointer to
thread function
struCommData, ; // Argument
for new thread - no '@'
; // because AS
STRUCTURE IS pointer already
00, ; // Creation
flags for thread
@nWorkerthreadID ) // Pointer to
returned thread ID

// If the secondary thread was NOT created successfully...
IF ( ptrCommWatchThread == NULL )

// Report the error.
SELF:sErrorDesc := "CreateThread failed in EnableEvent."
SELF:nErrorCode := GetLastError()

// Raise an exception.
BREAK

ELSE

// Lower the thread priority.
SetThreadPriority( nWorkerThreadID, THREAD_PRIORITY_LOWEST )

// Enable the reporting of the events.
SELF:lEventsEnabled := TRUE
SELF:struCommData.lWorkerIsStopped := FALSE

ENDIF

END SEQUENCE

RETURN( SELF:lEventsEnabled )

~"ONLYEARLY-"
ACCESS ErrorDesc() AS STRING PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:sErrorDesc )

~"ONLYEARLY-"
ACCESS ErrorCode() AS STRING PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( AsString( SELF:nErrorCode ) )

~"ONLYEARLY-"
METHOD Flush() AS LOGIC PASCAL CLASS Serial

LOCAL lResult AS LOGIC // Flag for a successful flush of the buffers

~"ONLYEARLY+"

// Purge the communications buffers.
lResult := PurgeComm( SELF:hCommFile, _OR( PURGE_TXCLEAR, PURGE_RXCLEAR,
;
PURGE_TXABORT, PURGE_RXABORT ) )

// If the communication buffers were NOT successfully flushed...
IF !( lResult )

// Report the error.
SELF:sErrorDesc := "PurgeComm failed."
SELF:nErrorCode := GetLastError()

ENDIF

RETURN( lResult )

~"ONLYEARLY-"
METHOD GetProtocol() AS LOGIC PASCAL CLASS Serial

LOCAL lResult AS LOGIC // Flag for a successful get of the protocol

~"ONLYEARLY+"

// If we have a valid communications session...
IF !( SELF:hCommFile == INVALID_HANDLE_VALUE )

// Get the communications protocol for the session.
lResult := GetCommState( SELF:hCommFile, SELF:struDCB )

// If the communication protocol was NOT successfully gotten...
IF !( lResult )

// Report the error.
SELF:sErrorDesc := "GetCommState failed in GetProtocol."
SELF:nErrorCode := GetLastError()

ENDIF

ENDIF

RETURN( lResult )

~"ONLYEARLY-"
METHOD GetTimeOut() AS LOGIC PASCAL CLASS Serial

LOCAL lResult AS LOGIC // Flag for a successful get of the timeout

~"ONLYEARLY+"

// If we have a valid communications session...
IF !( SELF:hCommFile == INVALID_HANDLE_VALUE )

// Get the communications timeout for the session.
lResult := GetCommTimeouts( SELF:hCommFile, SELF:struTimeOuts )

// If the communication protocol was NOT successfully gotten...
IF !( lResult )

// Report the error.
SELF:sErrorDesc := "GetCommTimeouts failed in GetTimeOut."
SELF:nErrorCode := GetLastError()

ENDIF

ENDIF

RETURN( lResult )

~"ONLYEARLY-"
ACCESS Handle() AS PTR PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:hCommFile )

~"ONLYEARLY-"
ACCESS IsOpen() AS LOGIC PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:lIsOpen )

~"ONLYEARLY-"
METHOD Open( sPort AS STRING ) AS LOGIC PASCAL CLASS Serial

LOCAL lStatus AS LOGIC
/* IF
Right(sPort,1) != ":"
sPort += ":"
ENDIF
*/

IF Left(sPort,4) != "\\.\"
sPort := "\\.\" + sPort
ENDIF


SELF:hCommFile := CreateFile( PSZ( sPort ),
; // Name of file
DWORD( _CAST, _OR( GENERIC_READ,
GENERIC_WRITE ) ), ; // Read-write mode
00,
; // Share mode - not shared
NULL,
; // Pointer to security descriptor (WinNT only)
OPEN_EXISTING,
; // Must be Open_Existing for devices
_OR( FILE_ATTRIBUTE_NORMAL,
FILE_FLAG_OVERLAPPED ), ; // File attributes
NULL )
// Handle to file with more attributes to copy

BEGIN SEQUENCE

IF ( SELF:hCommFile == INVALID_HANDLE_VALUE )

SELF:sErrorDesc := "CreateFile failed in Open."
SELF:nErrorCode := GetLastError()

BREAK

ENDIF

// Allocate storage for input and output buffers.
lStatus := setupComm( SELF:hCommFile, SELF:nRxBufferSize,
SELF:nTxBufferSize )

IF !( lStatus )

SELF:sErrorDesc := "SetupComm failed in Open."
SELF:nErrorCode := GetLastError()

BREAK

ENDIF

// Flush data buffers
IF !( SELF:Flush() )

BREAK

ENDIF

// Set up default time out values for comm session.
// (This is needed for overlapped I/O.)
SELF:ReadIntervalTimeout := 0xffffffff
SELF:ReadTimeoutMultiplier := 500
SELF:ReadTimeoutConstant := 1000
SELF:WriteTimeoutMultiplier := 00
SELF:WriteTimeoutConstant := 1000

IF !( SELF:SetTimeOut() )

BREAK

ENDIF

// Set up default values for DCB structure
IF !( SELF:GetProtocol() )

BREAK

ENDIF

SELF:Baud := 9600
SELF:Parity := NOPARITY
SELF:ByteSize := 08
SELF:StopBits := ONESTOPBIT

IF !( SELF:SetProtocol() )

BREAK

ENDIF

END SEQUENCE

SELF:lIsOpen := lStatus

RETURN( lStatus )

~"ONLYEARLY-"
ACCESS Parity() AS BYTE PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:struDCB.Parity )

~"ONLYEARLY-"
ASSIGN Parity( nNew AS BYTE ) AS BYTE PASCAL CLASS Serial

~"ONLYEARLY+"

// If a valid parity was passed...
IF ( ( nNew == ODDPARITY ) .OR. ;
( nNew == EVENPARITY ) .OR. ;
( nNew == MARKPARITY ) .OR. ;
( nNew == SPACEPARITY ) .OR. ;
( nNew == NOPARITY ) )

// Change the parity.
SELF:struDCB.Parity := nNew

ENDIF

RETURN( SELF:struDCB.Parity )

~"ONLYEARLY-"
METHOD Read( nMaxLength AS DWORD ) AS STRING PASCAL CLASS Serial

LOCAL lStatus AS LOGIC
LOCAL struComStat IS _WinComStat
LOCAL struOverlapped IS _WinOverlapped
LOCAL pszBuffer AS BYTE PTR
LOCAL sResult AS STRING
LOCAL dwErrorFlags AS DWORD
LOCAL dwError AS DWORD
LOCAL dwLength AS DWORD

~"ONLYEARLY+"

IF ( IsNil( nMaxLength ) )

nMaxLength := 01

ENDIF

// Allocate storage for incoming data.
pszBuffer := MemAlloc( nMaxLength )

BEGIN SEQUENCE

// Create event for overlapped structure.
struOverlapped.hEvent := CreateEvent( NULL, TRUE, FALSE, NULL )

IF ( struOverlapped.hEvent == NULL )

SELF:sErrorDesc := "CreateEvent failed in Read."
SELF:nErrorCode := GetLastError()

BREAK

ENDIF

dwLength := nMaxLength // Force timeout situation

IF ( dwLength > 00 )

lStatus := ReadFile( SELF:hCommFile, pszBuffer, dwLength, ;
@dwLength, @struOverlapped )

IF !( lStatus )

IF ( GetLastError() == ERROR_IO_PENDING )

// We have to wait for read to complete.
// This function will timeout according to the
// CommTimeOuts.ReadTotalTimeoutConstant variable
// Every time it times out, check for port errors
WHILE !( GetOverlappedResult( SELF:hCommFile, ;
@struOverlapped, ;
@dwLength, TRUE ) )

dwError := GetLastError()

IF ( dwError == ERROR_IO_INCOMPLETE )

// Normal if IO still in progress.
LOOP

ELSE

// A real error occurred.
SELF:sErrorDesc := "ReadFile failed in
Serial:ReadCommBlock(1)."
SELF:nErrorCode := GetLastError()

ClearCommError( SELF:hCommFile, @dwErrorFlags,
@struComStat )

BREAK

ENDIF

ENDDO

ELSE

// Some other error occurred.
dwLength := 00

SELF:sErrorDesc := "ReadFile failed in
Serial:ReadCommBlock(2)."
SELF:nErrorCode := GetLastError()

ClearCommError( SELF:hCommFile, @dwErrorFlags, @struComStat )

ENDIF

ENDIF

ENDIF

IF ( dwLength > 00 )

sResult := Mem2String( pszBuffer, dwLength )

IF ( dwLength < nMaxLength )
/* Handle error processing in calling app instead
MessageBox( 00, PSZ( "Not all bytes requested returned." ), ;
PSZ( "ReadTest" ), MB_OK )
*/

ENDIF

ENDIF

END SEQUENCE

// Free resources no longer needed.
MemFree( pszBuffer )

IF !( struOverlapped.hEvent == NULL )

CloseHandle( struOverlapped.hEvent )

ENDIF

RETURN( sResult )

~"ONLYEARLY-"
ACCESS ReadIntervalTimeout() AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:struTimeOuts.ReadIntervalTimeout )

~"ONLYEARLY-"
ASSIGN ReadIntervalTimeout( nMilliseconds AS DWORD ) AS DWORD PASCAL CLASS
Serial

~"ONLYEARLY+"

SELF:struTimeOuts.ReadIntervalTimeout := nMilliseconds

RETURN( SELF:struTimeOuts.ReadIntervalTimeout )

~"ONLYEARLY-"
ACCESS ReadTimeoutConstant() AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:struTimeOuts.ReadTotalTimeoutConstant )

~"ONLYEARLY-"
ASSIGN ReadTimeoutConstant( nMilliseconds AS DWORD ) AS DWORD PASCAL CLASS
Serial

~"ONLYEARLY+"

SELF:struTimeOuts.ReadTotalTimeoutConstant := nMilliseconds

RETURN( SELF:struTimeOuts.ReadTotalTimeoutConstant )

~"ONLYEARLY-"
ACCESS ReadTimeoutMultiplier() AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:struTimeOuts.ReadTotalTimeoutMultiplier )

~"ONLYEARLY-"
ASSIGN ReadTimeoutMultiplier( nMilliseconds AS DWORD ) AS DWORD PASCAL CLASS
Serial

~"ONLYEARLY+"

SELF:struTimeOuts.ReadTotalTimeoutMultiplier := nMilliseconds

RETURN( SELF:struTimeOuts.ReadTotalTimeoutMultiplier )

~"ONLYEARLY-"
ACCESS ReceiveBufferSize() AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:nRxBufferSize )

~"ONLYEARLY-"
ASSIGN ReceiveBufferSize( nNewSize AS DWORD ) AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

SELF:nRxBufferSize := nNewSize

RETURN( SELF:nRxBufferSize )

~"ONLYEARLY-"
ACCESS ReceiverPending() AS DWORD PASCAL CLASS Serial

LOCAL struComStat IS _WinComStat // Communication status
LOCAL nErrorFlags AS DWORD // Error flags
LOCAL nResult AS DWORD // Number of bytes to return

~"ONLYEARLY+"

// If we have a valid communications session...
IF !( SELF:hCommFile == INVALID_HANDLE_VALUE )

// Clear the communications error.
ClearCommError( SELF:hCommFile, @nErrorFlags, @struComStat )

// How many bytes are queued at input device?
nResult := struComStat.cbInQue

ENDIF

RETURN( nResult )

~"ONLYEARLY-"
METHOD SetProtocol() AS LOGIC PASCAL CLASS Serial

LOCAL lResult AS LOGIC // Flag for a successful set of the protocol

~"ONLYEARLY+"

// If we have a valid communications session...
IF !( SELF:hCommFile == INVALID_HANDLE_VALUE )

// Set the communications protocol for the session.
lResult := SetCommState( SELF:hCommFile, SELF:struDCB )

// If the communication protocol was NOT successfully set...
IF !( lResult )

// Report the error.
SELF:sErrorDesc := "SetCommState failed in SetProtocol."
SELF:nErrorCode := GetLastError()

ENDIF

ENDIF

RETURN( lResult )

~"ONLYEARLY-"
METHOD SetTimeOut() AS LOGIC PASCAL CLASS Serial

LOCAL lResult AS LOGIC // Flag for a successful set of the timeout

~"ONLYEARLY+"

// If we have a valid communications session...
IF !( SELF:hCommFile == INVALID_HANDLE_VALUE )

// Set the communications timeout for the session.
lResult := SetCommTimeouts( SELF:hCommFile, SELF:struTimeOuts )

// If the communication timeout was NOT successfully set...
IF !( lResult )

// Report the error.
SELF:sErrorDesc := "SetCommTimeouts failed in SetTimeOut."
SELF:nErrorCode := GetLastError()

ENDIF

ENDIF

RETURN( lResult )

~"ONLYEARLY-"
ACCESS StopBits() AS BYTE PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:struDCB.StopBits )

~"ONLYEARLY-"
ASSIGN StopBits( nNew AS BYTE ) AS BYTE PASCAL CLASS Serial

~"ONLYEARLY+"

// If a valid number of stop bits was passed...
IF ( ( nNew == ONESTOPBIT ) .OR. ;
( nNew == ONE5STOPBITS ) .OR. ;
( nNew == TWOSTOPBITS ) )

// Change the stop bits.
SELF:struDCB.StopBits := nNew

ENDIF

RETURN( SELF:struDCB.StopBits )

~"ONLYEARLY-"
ACCESS TransmitBufferSize() AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:nTxBufferSize )

~"ONLYEARLY-"
ASSIGN TransmitBufferSize( nNewSize AS DWORD ) AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

SELF:nTxBufferSize := nNewSize

RETURN( SELF:nTxBufferSize )

~"ONLYEARLY-"
METHOD Write( sString AS STRING ) AS DWORD PASCAL CLASS Serial

LOCAL lStatus AS LOGIC
LOCAL nBytesWritten AS DWORD
LOCAL struOverlapped IS _WinOverlapped

~"ONLYEARLY+"

BEGIN SEQUENCE

// Create event for overlapped structure.
struOverlapped.hEvent := CreateEvent( NULL, ; // Pointer to Security
Attributes structure
TRUE, ; // State must be
manually reset to non-signaled
FALSE, ; // Initial state is
non-signaled
NULL ) // Name of the event
object (none in this case)

IF ( struOverlapped.hEvent == NULL )

SELF:sErrorDesc := "CreateEvent failed in Serial:Write."
SELF:nErrorCode := GetLastError()

BREAK

ENDIF

lStatus := WriteFile( SELF:hCommFile, PSZ( sString ), ;
SLen( sString ), ;
@nBytesWritten, @struOverlapped )

IF ( ( !lStatus ) .AND. ( GetLastError() == ERROR_IO_PENDING ) )

// Tell Windows to attempt this write operation asynchronously
// in the background for up to 1000 milliseconds.
IF !( WaitForSingleObject( struOverlapped.hEvent, 1000 ) == 00 )

// Still can't complete the write operation.
nBytesWritten := 00

ELSE

// Windows has processed this I/O request now
// so let's get the result.
GetOverlappedResult( SELF:hCommFile, ; // The file to use
@struOverlapped, ; // The _WinOverlapped
structure
@nBytesWritten, ; // Actual number of
bytes tranferred
TRUE ) // Do wait for transfer
to be completed

// With overlapped I/O, it is your responsibility to
// update the record pointer.
struOverlapped.Offset += nBytesWritten

ENDIF

ELSEIF !( lStatus )

// WriteFile failed for some reason other than IO pending.
SELF:sErrorDesc := "WriteFile failed in Serial:Write."
SELF:nErrorCode := GetLastError()

// Should ClearCommError() be called here?
BREAK

ENDIF

IF !( nBytesWritten == SLen( sString ) )

SELF:sErrorDesc := "Error writing to device."
SELF:nErrorCode := GetLastError()

ENDIF

END SEQUENCE

// Close down overlapped event.
IF !( struOverlapped.hEvent == NULL )

CloseHandle( struOverlapped.hEvent )

ENDIF

RETURN( nBytesWritten )

~"ONLYEARLY-"
ACCESS WriteTimeoutConstant() AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:struTimeOuts.WriteTotalTimeoutConstant )

~"ONLYEARLY-"
ASSIGN WriteTimeoutConstant( nMilliseconds AS DWORD ) AS DWORD PASCAL CLASS
Serial

~"ONLYEARLY+"

SELF:struTimeOuts.WriteTotalTimeoutConstant := nMilliseconds

RETURN( SELF:struTimeOuts.WriteTotalTimeoutConstant )

~"ONLYEARLY-"
ACCESS WriteTimeoutMultiplier() AS DWORD PASCAL CLASS Serial

~"ONLYEARLY+"

RETURN( SELF:struTimeOuts.WriteTotalTimeoutMultiplier )

~"ONLYEARLY-"
ASSIGN WriteTimeoutMultiplier( nMilliseconds AS DWORD ) AS DWORD PASCAL
CLASS Serial

~"ONLYEARLY+"

SELF:struTimeOuts.WriteTotalTimeoutMultiplier := nMilliseconds

RETURN( SELF:struTimeOuts.WriteTotalTimeoutMultiplier )

~"ONLYEARLY-"
FUNCTION SetBit( nValue AS DWORD, nPos AS INT ) AS DWORD PASCAL

~"ONLYEARLY+"

// Set bit at nPos to 1 (based on first bit is pos 0).
RETURN( _OR( nValue, DWORD( 02 ^ nPos ) ) )

~"ONLYEARLY-"
FUNCTION TestBit( nValue AS DWORD, nPos AS INT ) AS DWORD PASCAL

~"ONLYEARLY+"

// Test bit at nPos for 1 (based on first bit is pos 0).
RETURN( _AND( nValue, DWORD( 02 ^ nPos ) ) )

~"ONLYEARLY-"
FUNCTION CommWatchProc( ptrCommData AS PTR ) AS LONG STRICT

// This FUNCTION executes AS a separate thread so no data types
// that might trigger the VO garbage collector are used here.

// ptrCommData is a pointer to a structure that holds all the
// data needed by this function from the class
// (We only get one parameter so it has to be multi-functional)

LOCAL struCommData AS CommData
LOCAL nEventMask AS DWORD
LOCAL nResult AS LONG

~"ONLYEARLY+"

struCommData := ptrCommData
nResult := 00

WHILE ( TRUE ) // Use of BEGIN SEQUENCE not recommended inside secondary
thread.

IF !( SetCommMask( struCommData.hCommFile, struCommData.dwEvent ) )

MessageBox( 00, PSZ( "SetCommMask failed!" ), ;
PSZ( "CommWatchProc Error" ), MB_OK )

nResult := 0

EXIT // Breaks out of outer Loop

ENDIF

struCommData.lWorkerIsStopped := FALSE

nResult := 01

WHILE !( struCommData.lWorkerMustStop )

nEventMask := 00

IF !( WaitCommEvent( struCommData.hCommFile, ;
@nEventMask, NULL ) )

nResult := 00

EXIT // Break out on Error

ENDIF

IF ( _AND( nEventMask, EV_RXCHAR ) == EV_RXCHAR )

// We have a receiver pending event so notify the window about
it.
// ( The Win32 API no longer supports the WM_COMMNOTIFY
// message, but I just reused it for backward compatibility. )
// You could use VOSendMessage() here instead of PostMessage(),
// but do not use plain SendMessage() as it will cause timing
// problems in a multi-threaded function
//PostMessage( struCommData.hWindowToNotify, ;
// WM_COMMNOTIFY, EV_RXCHAR, 0L )
VOSendMessage( struCommData.hWindowToNotify, ;
WM_COMMNOTIFY, EV_RXCHAR, 0L )

ENDIF

ENDDO

EXIT // Breaks us out of outer Loop

ENDDO

// Signal primary thread that we're done
struCommData.lWorkerIsStopped := TRUE

RETURN( nResult )

~"ONLYEARLY-"
DEFINE ASCII_XOFF := 0x13
DEFINE WM_COMMNOTIFY := 0x0044


--

Ginny Caughey
www.wasteworks.com




From: Gunter on
Hi, Ginny, many thanks for the delivered code. I shell try it.
Gunter
 | 
Pages: 1
Prev: V02Ado error
Next: OwnerDraw StatusBar