* harbour/include/hbver.h
* removed unnecessary EOL inside comment
* harbour/contrib/hbodbc/odbc.c
! use valid integer type instead of explicit casting in function call.
Such casting is vary dangerous and may cause unpredictible results
when integer value has different binary size
* harbour/contrib/hbtpathy/Makefile
* harbour/contrib/hbtpathy/common.mak
* harbour/contrib/hbtpathy/telepath.ch
* harbour/contrib/hbtpathy/tplinux.c
* harbour/contrib/hbtpathy/tpwin32.c
* harbour/contrib/hbtpathy/tpos2.c
* harbour/contrib/hbtpathy/telepath.prg
* harbour/contrib/hbtpathy/readme.txt
* harbour/contrib/hbtpathy/tests/testtp.prg
* converted EOL style to native
* set valid SVN attributes
* harbour/contrib/hbapollo/Makefile
* disabled non W32 builds, SDE exists only for MS-Windows
* harbour/contrib/hbziparch/Makefile
! fixed C flag setting for Linux builds
* harbour/source/pp/ppcore.c
* formatting
* harbour/source/rtl/valtoexp.prg
! fixed empty date conversion
* harbour/hbgtmk.sh
* harbour/make_xmingwce.sh
* harbour/make_deb.sh
* harbour/make_rpmw32.sh
* harbour/make_gcc.sh
* harbour/make_rpm.sh
* harbour/make_xmingw.sh
* harbour/make_tgz.sh
* harbour/make_rpmce.sh
* harbour/contrib/hbmzip/make_gcc.sh
* harbour/contrib/hbsqlit3/make_gcc.sh
* harbour/contrib/make_gcc_all.sh
* harbour/contrib/hbziparch/make_gcc.sh
* harbour/contrib/hbnf/make_gcc.sh
* harbour/contrib/hbhpdf/tests/files/cp932.txt
* harbour/contrib/hbhpdf/make_gcc.sh
* harbour/contrib/rddado/make_gcc.sh
* harbour/contrib/gtwvg/make_gcc.sh
* harbour/contrib/hbpgsql/make_gcc.sh
* harbour/contrib/rddads/make_gcc.sh
* harbour/contrib/hbclipsm/make_gcc.sh
* harbour/contrib/mtpl_gcc.sh
* harbour/contrib/hbfimage/make_gcc.sh
* harbour/contrib/hbgd/tests/bld.sh
* harbour/contrib/hbgd/make_gcc.sh
* harbour/contrib/hbmisc/make_gcc.sh
* harbour/contrib/hbtip/make_gcc.sh
* harbour/contrib/hbbmcdx/make_gcc.sh
* harbour/contrib/hbvpdf/make_gcc.sh
* harbour/contrib/hbbtree/make_gcc.sh
* set valid SVN EOL attribute
868 lines
19 KiB
Plaintext
868 lines
19 KiB
Plaintext
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* Telepathy emulation library
|
|
*
|
|
* Copyright 2000, 2001 Dan Levitt <dan@boba-fett.net>
|
|
* Copyright 2004, 2005 Maurilio Longo <maurilio.longo@libero.it>
|
|
* www - http://www.xharbour.org
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
This is based upon a library originally made by Dan Levitt <dan@boba-fett.net>
|
|
(see README and ChangeLog). The original files have been committed as v1.0,
|
|
so you can always retrieve them (see CVS docs on how to)
|
|
*/
|
|
|
|
|
|
#include "common.ch"
|
|
#include "fileio.ch"
|
|
#include "telepath.ch"
|
|
|
|
|
|
|
|
STATIC s_aPorts // Array with port info
|
|
STATIC s_nErrorCode := 0 // Error code from last operation, 0 if no error
|
|
|
|
|
|
|
|
|
|
function tp_baud( nPort, nNewBaud )
|
|
|
|
local nRes
|
|
|
|
default nNewBaud to 0
|
|
|
|
if ! isport( nPort ) .OR. Empty( s_aPorts[ nPort, TPFP_NAME ] )
|
|
return TE_NOPORT
|
|
endif
|
|
|
|
if ! isopenport( nPort )
|
|
return 0
|
|
endif
|
|
|
|
if nNewBaud > 0
|
|
if ( nRes := p_InitPortSpeed( s_aPorts[ nPort, TPFP_HANDLE ] ,;
|
|
nNewBaud,;
|
|
s_aPorts[ nPort, TPFP_DBITS ] ,;
|
|
s_aPorts[ nPort, TPFP_PARITY ] ,;
|
|
s_aPorts[ nPort, TPFP_SBITS ] ) ) == 0
|
|
|
|
s_aPorts[ nPort, TPFP_BAUD ] := nNewBaud
|
|
|
|
|
|
else
|
|
// set error code
|
|
endif
|
|
endif
|
|
|
|
return s_aPorts[ nPort, TPFP_BAUD ]
|
|
|
|
|
|
|
|
function tp_inkey( nSecs )
|
|
if valtype( nSecs ) == "U"
|
|
return inkey()
|
|
endif
|
|
return inkey( nSecs )
|
|
|
|
|
|
|
|
function tp_idle( lNewval )
|
|
if lNewval == .t.
|
|
return .t.
|
|
endif
|
|
return .f.
|
|
|
|
|
|
|
|
function tp_delay( nTime )
|
|
|
|
default nTime to 0
|
|
|
|
if nTime < 0
|
|
return nil
|
|
|
|
elseif nTime > 1800
|
|
nTime := 1800
|
|
|
|
endif
|
|
|
|
ThreadSleep( nTime * 1000 )
|
|
|
|
return nil
|
|
|
|
|
|
|
|
function tp_close( nPort, nTimeout )
|
|
|
|
default nTimeout to 0
|
|
|
|
/* Clipper returns 0 even if a port is not open */
|
|
if ! isopenport( nPort )
|
|
return 0
|
|
endif
|
|
|
|
if nTimeout > 0
|
|
tp_flush( nPort, nTimeout )
|
|
endif
|
|
|
|
if s_aPorts[ nPort, TPFP_HANDLE ] >= 0
|
|
|
|
fClose( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
|
|
/* Port parameters should stay the same for the case the port
|
|
gets reopened
|
|
*/
|
|
s_aPorts[ nPort, TPFP_OC ] := .F.
|
|
s_aPorts[ nPort, TPFP_INBUF ] := ""
|
|
s_aPorts[ nPort, TPFP_HANDLE ] := -1
|
|
endif
|
|
|
|
return 0
|
|
|
|
|
|
|
|
function tp_reopen( nPort, nInSize, nOutSize )
|
|
|
|
LOCAL nBaud, nData, cParity, nStop, cPortName
|
|
|
|
default nInSize to 1536, nOutSize to 1536
|
|
|
|
if ! isport( nPort ) .OR. Empty( s_aPorts[ nPort, TPFP_NAME ] )
|
|
return TE_NOPORT
|
|
endif
|
|
|
|
cPortname := s_aPorts[ nPort, TPFP_NAME ]
|
|
nBaud := s_aPorts[ nPort, TPFP_BAUD ]
|
|
nData := s_aPorts[ nPort, TPFP_DBITS ]
|
|
cParity := s_aPorts[ nPort, TPFP_PARITY ]
|
|
nStop := s_aPorts[ nPort, TPFP_SBITS ]
|
|
|
|
return tp_open( nPort, nInSize, nOutSize, nBaud, nData, cParity, nStop, cPortName )
|
|
|
|
|
|
|
|
function tp_open( nPort, nInSize, nOutSize, nBaud, nData, cParity, nStop, cPortname )
|
|
|
|
local nRes, lPortExist
|
|
|
|
#ifdef __PLATFORM__Linux
|
|
local nFileCase, nDirCase
|
|
#endif
|
|
|
|
default nInSize to 1536, nOutSize to 1536
|
|
default nBaud to 1200, nData to 8, cParity to "N", nStop to 1
|
|
|
|
/* Serial ports name are made up of cPortName + nPort if nPort is not NIL */
|
|
#ifdef __PLATFORM__Linux
|
|
default cPortName to "/dev/ttyS"
|
|
#else
|
|
default cPortName to "COM" // Ok for Win32 and OS/2
|
|
#endif
|
|
|
|
/* This way compatibility is retained for ports 1-4 on Win32 and Linux, but,
|
|
should necessity arise, it is possible to simply pass a NIL on nPort and
|
|
a full name on cPortName
|
|
*/
|
|
#ifdef __PLATFORM__Linux
|
|
cPortname := AllTrim( cPortname ) + iif( ValType( nPort ) == "N", AllTrim( Str( nPort - 1 ) ), "" )
|
|
#else
|
|
cPortname := AllTrim( cPortname ) + iif( ValType( nPort ) == "N", AllTrim( Str( nPort ) ), "" )
|
|
#endif
|
|
|
|
#ifdef __PLATFORM__Linux
|
|
nFileCase := Set( _SET_FILECASE, 0 )
|
|
nDirCase := Set( _SET_DIRCASE, 0 )
|
|
#endif
|
|
lPortExist := File( cPortname )
|
|
#ifdef __PLATFORM__Linux
|
|
Set( _SET_FILECASE, nFileCase )
|
|
Set( _SET_DIRCASE, nDirCase )
|
|
#endif
|
|
|
|
if ! lPortExist
|
|
return TE_NOPORT
|
|
endif
|
|
|
|
if ! isport( nPort )
|
|
return TE_NOPORT
|
|
endif
|
|
|
|
s_aPorts[ nPort, TPFP_NAME ] := cPortname
|
|
s_aPorts[ nPort, TPFP_BAUD ] := nBaud
|
|
s_aPorts[ nPort, TPFP_DBITS ] := nData
|
|
s_aPorts[ nPort, TPFP_PARITY ] := cParity
|
|
s_aPorts[ nPort, TPFP_SBITS ] := nStop
|
|
s_aPorts[ nPort, TPFP_OC ] := .F.
|
|
s_aPorts[ nPort, TPFP_INBUF ] := ""
|
|
s_aPorts[ nPort, TPFP_INBUF_SIZE ] := nInSize
|
|
|
|
#ifdef __PLATFORM__Linux
|
|
// Maybe we should have a p_Open() on every platform
|
|
s_aPorts[ nPort, TPFP_HANDLE ] := p_Open( cPortname )
|
|
#else
|
|
s_aPorts[ nPort, TPFP_HANDLE ] := fOpen( cPortname, FO_READWRITE )
|
|
#endif
|
|
|
|
if s_aPorts[ nPort, TPFP_HANDLE ] >= 0
|
|
|
|
/* low level C functions are prefixed p_ (don't ask me why :)) */
|
|
if ( nRes := p_InitPortSpeed( s_aPorts[ nPort, TPFP_HANDLE ] ,;
|
|
s_aPorts[ nPort, TPFP_BAUD ] ,;
|
|
s_aPorts[ nPort, TPFP_DBITS ] ,;
|
|
s_aPorts[ nPort, TPFP_PARITY ] ,;
|
|
s_aPorts[ nPort, TPFP_SBITS ] ) ) == 0
|
|
|
|
s_aPorts[ nPort, TPFP_OC ] := .T.
|
|
return nRes
|
|
|
|
else
|
|
|
|
tp_Close( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
return nRes
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
// set error code to a static var to have tp_error() work as expected
|
|
//cnHandle := ferror()
|
|
|
|
s_aPorts[ nPort, TPFP_NAME ] := ""
|
|
s_aPorts[ nPort, TPFP_HANDLE ] := -1
|
|
s_aPorts[ nPort, TPFP_BAUD ] := 1200
|
|
s_aPorts[ nPort, TPFP_DBITS ] := 8
|
|
s_aPorts[ nPort, TPFP_PARITY ] := "N"
|
|
s_aPorts[ nPort, TPFP_SBITS ] := 1
|
|
s_aPorts[ nPort, TPFP_OC ] := .F.
|
|
s_aPorts[ nPort, TPFP_INBUF ] := ""
|
|
s_aPorts[ nPort, TPFP_INBUF_SIZE ] := 0
|
|
|
|
return TE_CONFL // maybe should return something different?
|
|
|
|
|
|
|
|
function tp_recv( nPort, nLength, nTimeout )
|
|
|
|
local nDone
|
|
local cRet := ""
|
|
|
|
default nLength to s_aPorts[ nPort, TPFP_INBUF_SIZE ]
|
|
default nTimeout to 0
|
|
|
|
FetchChars( nPort )
|
|
|
|
nDone := Seconds() + iif( nTimeout >= 0, nTimeout, 0 )
|
|
|
|
while Len( s_aPorts[ nPort, TPFP_INBUF ] ) < nLength .AND.;
|
|
( nTimeout < 0 .OR. Seconds() < nDone )
|
|
|
|
if ! tp_idle()
|
|
FetchChars( nPort )
|
|
else
|
|
exit
|
|
endif
|
|
|
|
enddo
|
|
|
|
if nLength > Len( s_aPorts[ nPort, TPFP_INBUF ] )
|
|
cRet := s_aPorts[ nPort, TPFP_INBUF ]
|
|
s_aPorts[ nPort, TPFP_INBUF ] := ""
|
|
else
|
|
cRet := SubStr( s_aPorts[ nPort, TPFP_INBUF ], 1, nLength )
|
|
s_aPorts[ nPort, TPFP_INBUF ] := SubStr( s_aPorts[ nPort, TPFP_INBUF ], nLength + 1 )
|
|
endif
|
|
|
|
return cRet
|
|
|
|
|
|
|
|
function tp_send( nPort, cString, nTimeout )
|
|
|
|
local nWritten, nTotWritten, nDone
|
|
|
|
default cString to "", nTimeout to 0
|
|
|
|
if ! isopenport( nPort )
|
|
return 0
|
|
endif
|
|
|
|
if Empty( cString )
|
|
return 0
|
|
endif
|
|
|
|
nDone := Seconds() + iif( nTimeout >= 0, nTimeout, 0)
|
|
nWritten := nTotWritten := 0
|
|
|
|
while nTotWritten < Len( cString ) .AND. ;
|
|
( nTimeout < 0 .OR. Seconds() <= nDone )
|
|
|
|
nWritten := p_WritePort( s_aPorts[ nPort, TPFP_HANDLE ], SubStr( cString, nTotWritten + 1 ) )
|
|
|
|
if nWritten >= 0
|
|
|
|
nTotWritten += nWritten
|
|
|
|
if nTotWritten < Len( cString )
|
|
|
|
if ! tp_idle()
|
|
ThreadSleep( 1000 )
|
|
else
|
|
exit
|
|
endif
|
|
|
|
endif
|
|
|
|
else // nWritten < 0, error occurred
|
|
exit
|
|
|
|
endif
|
|
|
|
enddo
|
|
|
|
return nTotWritten
|
|
|
|
|
|
|
|
function tp_sendsub( nPort, cString, nStart, nLength, nTimeout )
|
|
|
|
default nStart to 1, nLength to Len( cString )
|
|
|
|
return tp_send( nPort, SubStr( cString, nStart, nLength ), nTimeout )
|
|
|
|
|
|
|
|
function tp_recvto( nPort, cDelim, nMaxlen, nTimeout )
|
|
|
|
local cChar
|
|
local nAt
|
|
local nStartPos := 1, nFirst := 0
|
|
local nDone, cRet := ""
|
|
|
|
|
|
if ! isopenport( nPort )
|
|
return ""
|
|
endif
|
|
|
|
if !( ValType( cDelim ) == "C" ) .OR. Empty( cDelim )
|
|
return ""
|
|
endif
|
|
|
|
default nMaxlen to 64999 /* dos telepathy def. on xharbour could be higher */
|
|
default nTimeout to 0
|
|
|
|
|
|
FetchChars( nPort )
|
|
|
|
/* Telepathy ng: [...] If nTimeout is omitted or zero, reads until finding the
|
|
delimiter or the input buffer is empty. */
|
|
if nTimeout == 0 .AND. Empty( s_aPorts[ nPort, TPFP_INBUF ] )
|
|
return ""
|
|
endif
|
|
|
|
nDone := Seconds() + iif( nTimeout >= 0, nTimeout, 0 )
|
|
|
|
while ( nTimeout < 0 .OR. Seconds() < nDone )
|
|
|
|
if Len( cDelim ) == 1
|
|
|
|
nAt := hb_At( cDelim, s_aPorts[ nPort, TPFP_INBUF ], nStartPos )
|
|
|
|
if nAt > 0 .AND. iif( nFirst > 0, nAt < nFirst, .T. )
|
|
nFirst := nAt
|
|
endif
|
|
|
|
else
|
|
|
|
FOR EACH cChar IN cDelim
|
|
|
|
nAt := hb_At( cChar, s_aPorts[ nPort, TPFP_INBUF ], nStartPos )
|
|
|
|
if nAt > 0 .AND. iif( nFirst > 0, nAt < nFirst, .T. )
|
|
nFirst := nAt
|
|
endif
|
|
|
|
NEXT
|
|
|
|
endif
|
|
|
|
// I've found it
|
|
if nFirst > 0
|
|
exit
|
|
|
|
else
|
|
// Next loop I don't need to search that part of the input buffer that
|
|
// I've already just searched for
|
|
nStartPos := Max( Len( s_aPorts[ nPort, TPFP_INBUF ] ), 1 )
|
|
|
|
// I've read more characters than I'm allowed to, so I exit
|
|
if nStartPos >= nMaxLen
|
|
exit
|
|
endif
|
|
|
|
if ! tp_idle()
|
|
FetchChars( nPort )
|
|
else
|
|
exit
|
|
endif
|
|
endif
|
|
|
|
enddo
|
|
|
|
if nFirst > 0
|
|
cRet := Left( s_aPorts[ nPort, TPFP_INBUF ], nFirst )
|
|
s_aPorts[ nPort, TPFP_INBUF ] := SubStr( s_aPorts[ nPort, TPFP_INBUF ], nFirst + 1 )
|
|
endif
|
|
|
|
return cRet
|
|
|
|
|
|
|
|
/*
|
|
here's an improvement over original TP... you can "lookfor" a string
|
|
here rather than just a char. yay me.
|
|
of course, if you're using clipper/tp code and you search for a single char it will work
|
|
the same.
|
|
*/
|
|
function tp_lookfor( nPort, cLookfor )
|
|
|
|
if ! isopenport( nPort )
|
|
return 0
|
|
endif
|
|
|
|
FetchChars( nPort )
|
|
|
|
return At( cLookfor, s_aPorts[ nPort, TPFP_INBUF ] )
|
|
|
|
|
|
|
|
function tp_inchrs( nPort )
|
|
|
|
if ! isopenport( nPort )
|
|
return 0
|
|
endif
|
|
|
|
FetchChars( nPort )
|
|
|
|
return Len( s_aPorts[ nPort, TPFP_INBUF ] )
|
|
|
|
|
|
|
|
function tp_outfree( nPort )
|
|
|
|
if ! isopenport( nPort )
|
|
return 0
|
|
endif
|
|
|
|
return p_OutFree( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
|
|
|
|
|
|
function tp_clearin( nPort )
|
|
|
|
if isopenport( nPort )
|
|
FetchChars( nPort )
|
|
s_aPorts[ nPort, TPFP_INBUF ] := ""
|
|
endif
|
|
|
|
return nil
|
|
|
|
|
|
|
|
function tp_clrkbd()
|
|
|
|
clear typeahead
|
|
|
|
return nil
|
|
|
|
|
|
|
|
function tp_crc16( cString )
|
|
|
|
return p_CRC16( cString )
|
|
|
|
|
|
|
|
function tp_crc32( cString )
|
|
|
|
return p_CRC32( cString )
|
|
|
|
|
|
/* nPort, nTimeout, acList|cString..., lIgnorecase */
|
|
function tp_waitfor( ... )
|
|
|
|
local aParam := hb_AParams()
|
|
local nPort, nTimeout, lIgnorecase
|
|
|
|
nPort := aParam[ 1 ]
|
|
nTimeout := aParam[ 2 ]
|
|
lIgnorecase := aParam[ Len( aParam ) ]
|
|
|
|
if ! isopenport( nPort )
|
|
return 0
|
|
endif
|
|
|
|
default nTimeout to -1
|
|
default lIgnorecase to .f.
|
|
|
|
/*
|
|
|
|
if ntimeout < 0
|
|
nDone := _clock() + 999999
|
|
elseif ntimeout == 0
|
|
nDone := 4
|
|
else
|
|
nDone := _clock() + nTimeout
|
|
endif
|
|
|
|
while ( nDone > _clock() .or. nFirst == 100000 ) .and. ! tp_idle()
|
|
|
|
if nFirst == 100000
|
|
nFirst := 99999
|
|
endif
|
|
|
|
FetchChars( nPort )
|
|
|
|
for x := 1 to len( acList )
|
|
if lIgnorecase
|
|
nAt := at( upper( acList[ x ] ), upper( s_aPorts[ nPort, TPFP_INBUF ] ))
|
|
else
|
|
nAt := at( acList[ x ] , s_aPorts[ nPort, TPFP_INBUF ] )
|
|
endif
|
|
if nAt > 0 .and. nAt < nFirst
|
|
nFirst := nAt
|
|
nRet := x
|
|
endif
|
|
next
|
|
|
|
if nFirst < 64000
|
|
exit
|
|
endif
|
|
|
|
#if 0
|
|
sched_yield() // C level function
|
|
#endif
|
|
|
|
enddo
|
|
|
|
if nFirst < 64000
|
|
tp_recv( nPort, nAt + len( acList[ nRet ] ))
|
|
return nRet
|
|
endif
|
|
*/
|
|
|
|
return 0
|
|
|
|
|
|
|
|
/* We cannot set, well, _I_ think we cannot, CTS without setting RTS flowcontrol, so this
|
|
function and tp_ctrlrts() do the same thing, that is set/reset CRTSCTS flowcontol */
|
|
function tp_ctrlcts( nPort, nNewCtrl )
|
|
|
|
local nCurValue
|
|
|
|
if ! isopenport( nPort )
|
|
return 0
|
|
endif
|
|
|
|
if Valtype( nNewCtrl ) == "U"
|
|
nCurValue := p_ctrlcts( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
|
|
else
|
|
nCurValue := p_ctrlcts( s_aPorts[ nPort, TPFP_HANDLE ], nNewCtrl )
|
|
|
|
endif
|
|
|
|
return nCurValue
|
|
|
|
|
|
// Simply calls tp_ctrlcts()
|
|
function tp_ctrlrts( nPort, nNewCtrl )
|
|
|
|
return tp_ctrlcts( nPort, nNewCtrl )
|
|
|
|
|
|
|
|
/*
|
|
|
|
// telepathy says...
|
|
// returns old dtr value 0,1,2
|
|
// sets to 0 = dtr off, 1 dtr on, 2 = dtr flow control autotoggle
|
|
// I don't support 2. who uses dtr for flow control anyway...
|
|
function tp_ctrldtr( nPort, nParamNewval )
|
|
LOCAL nph, nnewval, noldval
|
|
|
|
if ! isopenport( nPort )
|
|
return -1
|
|
endif
|
|
nph := s_aPorts[ nPort, TPFP_HANDLE ]
|
|
|
|
_P_CTRLDTR(nph, @nnewval, @noldval)
|
|
|
|
return noldval
|
|
*/
|
|
|
|
|
|
|
|
function tp_isdcd( nPort )
|
|
|
|
if ! isopenport( nPort )
|
|
return .f.
|
|
endif
|
|
|
|
return p_isdcd( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
|
|
|
|
|
|
function tp_isri( nPort )
|
|
|
|
if ! isopenport( nPort )
|
|
return .f.
|
|
endif
|
|
|
|
return p_isri( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
|
|
|
|
|
|
function tp_isdsr( nPort )
|
|
|
|
if ! isopenport( nPort )
|
|
return .f.
|
|
endif
|
|
|
|
return p_isdsr( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
|
|
|
|
|
|
function tp_iscts( nPort )
|
|
|
|
if ! isopenport( nPort )
|
|
return .f.
|
|
endif
|
|
|
|
return p_iscts( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
|
|
|
|
|
|
#ifdef __PLATFORM__Linux
|
|
// NB: On linux i don't know how to make a drain with a timeout, so here
|
|
// I'll wait as long as it takes to drain the port.
|
|
function tp_flush( nPort, nTimeout )
|
|
|
|
local nStart := Seconds()
|
|
local nRes
|
|
|
|
default nTimeout to 0
|
|
|
|
if ! isopenport( nPort )
|
|
return TE_CLOSED
|
|
endif
|
|
|
|
nRes := p_Drain( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
|
|
// Sleep rest of timeout
|
|
/*
|
|
if nTimeout > 0 .AND. Seconds() - nStart < nTimeout
|
|
ThreadSleep( ( nTimeout - ( Seconds() - nStart ) ) * 1000 )
|
|
endif
|
|
*/
|
|
|
|
// NB: returns timeout on error trying to reach compatibility with other platforms
|
|
// to be tested
|
|
return iif( nRes == 0, 0, TE_TMOUT )
|
|
|
|
#else
|
|
|
|
function tp_flush( nPort, nTimeout )
|
|
|
|
local nDone
|
|
|
|
default nTimeout to -1
|
|
|
|
if ! isopenport( nPort )
|
|
return TE_CLOSED
|
|
endif
|
|
|
|
if nTimeout > 1800
|
|
nTimeout := 1800
|
|
endif
|
|
|
|
nDone := Seconds() + iif( nTimeout >= 0, nTimeout, 0 )
|
|
|
|
while tp_OutFree( nPort ) > 0 .AND. ;
|
|
( nTimeout < 0 .OR. Seconds() < nDone )
|
|
hb_IdleState()
|
|
enddo
|
|
|
|
return iif( tp_OutFree( nPort ) > 0, TE_TMOUT, 0 )
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
/// sorry, but ctrldsr and ctrlcts will act like isdsr and iscts... if you want
|
|
/// flow control, talk to the system.
|
|
function tp_ctrldsr( nPort )
|
|
return tp_isdsr( nPort )
|
|
|
|
/// you can't do these things. try rc.serial
|
|
function tp_shared
|
|
return 0
|
|
|
|
function tp_setport
|
|
return 0
|
|
|
|
|
|
|
|
*/
|
|
|
|
// internal (static) functions ---------------------------------------------------
|
|
|
|
static function isopenport( nPort )
|
|
|
|
if ! isport( nPort )
|
|
return .f.
|
|
endif
|
|
|
|
return s_aPorts[ nPort, TPFP_OC ]
|
|
|
|
|
|
|
|
static function isport( nPort )
|
|
|
|
if valtype( nPort ) != "N" .or. nPort < 1 .or. nPort > TP_MAXPORTS
|
|
return .f.
|
|
endif
|
|
|
|
return .t.
|
|
|
|
|
|
|
|
static function FetchChars( nPort )
|
|
|
|
local cStr := ""
|
|
|
|
if ! isopenport( nPort )
|
|
return 0
|
|
endif
|
|
|
|
cStr := p_ReadPort( s_aPorts[ nPort, TPFP_HANDLE ] )
|
|
|
|
if ! Empty( cStr )
|
|
s_aPorts[ nPort, TPFP_INBUF ] += cStr
|
|
endif
|
|
|
|
return Len( cStr )
|
|
|
|
|
|
|
|
INIT PROCEDURE _tpinit()
|
|
|
|
local x
|
|
|
|
if s_aPorts == nil
|
|
s_aPorts := array( TP_MAXPORTS )
|
|
for x := 1 to len( s_aPorts )
|
|
/// port name, file handle, baud, data bits, parity, stop bits, Open?, input buffer, input buff.size
|
|
s_aPorts[ x ] := { "", -1, 1200, 8, "N", 1, .F., "", 0 }
|
|
next
|
|
endif
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
/*
|
|
/// you can uncomment the following section for compatability with TP code... I figured
|
|
/// you'd probably want them commented so it won't compile so that you would see where
|
|
/// you have potential incomplete port problems
|
|
///function tp_mstat
|
|
///return ""
|
|
///
|
|
///function tp_szmodem
|
|
///return 0
|
|
///
|
|
///function tp_noteoff
|
|
///return 0
|
|
///
|
|
///function tp_ontime
|
|
///return 0
|
|
///
|
|
///function tp_rzmodem
|
|
///return 0
|
|
///
|
|
///function tp_error
|
|
///return 0
|
|
///
|
|
///function tp_errmsg
|
|
///return ""
|
|
///
|
|
///function tp_fifo
|
|
///return 0
|
|
///
|
|
///
|
|
///function tp_outchrs
|
|
///return 0
|
|
///
|
|
///function tp_keybd
|
|
///return 0
|
|
///
|
|
|
|
/// tp_debug is not a real TP function. I included it so you can define your own debug
|
|
/// output function.
|
|
/// the point of the first parameter is a "debug level". I keep a system variable for how
|
|
/// much debuggning output is wanted and if the tp_debug parameter is a LOWER number than
|
|
/// the global debug level I print the message. Since I don't have your system globals,
|
|
/// I will ignore the first parameter and always print it.
|
|
/// I recommend you modify this function to suit your own debugging needs
|
|
function tp_debug( nDebugLevel, cString )
|
|
? cString
|
|
return nil
|
|
*/
|