/* * Serial communication functions * * Copyright 2010 Przemyslaw Czerpak * * 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 program; see the file LICENSE.txt. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/). * * 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. * */ #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include "hbapi.h" #if defined( HB_OS_UNIX ) && ( ! defined( __WATCOMC__ ) || __WATCOMC__ > 1290 ) && \ ! defined( HB_OS_SYMBIAN ) /* || defined( __DJGPP__ ) */ # if defined( HB_OS_VXWORKS ) # if ! defined( HB_HAS_SIOLIB ) # define HB_HAS_SIOLIB # endif # else # if ! defined( HB_HAS_TERMIOS ) # define HB_HAS_TERMIOS # endif # endif # if defined( HB_OS_SUNOS ) # if ! defined( BSD_COMP ) # define BSD_COMP # endif # endif #elif defined( HB_OS_DOS ) && \ ! defined( HB_HAS_PMCOM ) && ! defined( HB_HAS_DOSSRL ) # define HB_HAS_DOSSRL #endif #if defined( HB_HAS_TERMIOS ) # include # include # include # include # include # if defined( HB_OS_UNIX ) # include # include # if ! defined( HB_HAS_POLL ) && ! defined( HB_NO_POLL ) && \ defined( _POSIX_C_SOURCE ) && _POSIX_C_SOURCE >= 200112L /* use poll() instead of select() to avoid FD_SETSIZE (1024 in Linux) file handle limit */ # define HB_HAS_POLL # endif # if defined( HB_HAS_POLL ) # include # endif # endif # if defined( HB_OS_HPUX ) # include # endif #elif defined( HB_HAS_SIOLIB ) # include #elif defined( HB_HAS_DOSSRL ) # include "../../src/3rd/hbdossrl/serial.h" #elif defined( HB_HAS_PMCOM ) # include "../../src/3rd/hbpmcom/com.h" #elif defined( HB_OS_WIN ) # include # include "hbwinuni.h" #elif defined( HB_OS_OS2 ) # define INCL_BASE # define INCL_DOS # define INCL_DOSERROR # define INCL_DOSDEVICES # define INCL_DOSDEVIOCTL # include #elif defined( HB_OS_LINUX ) && defined( __WATCOMC__ ) && ( __WATCOMC__ <= 1290 ) # include #endif #include "hbapifs.h" #include "hbapiitm.h" #include "hbapicom.h" #include "hbvm.h" #include "hbinit.h" #include "hbdate.h" #include "hbthread.h" typedef struct { #if defined( HB_HAS_TERMIOS ) HB_FHANDLE fd; # if ! defined( HB_OS_UNIX ) HB_MAXINT rdtimeout; # endif #elif defined( HB_OS_WIN ) HANDLE hComm; HB_MAXINT rdtimeout; HB_MAXINT wrtimeout; #elif defined( HB_OS_OS2 ) HFILE hFile; USHORT rdtimeout; USHORT wrtimeout; #endif int status; int error; int oserr; int port; char * name; /* struct termios tio; */ } HB_COM, * PHB_COM; static HB_CRITICAL_NEW( s_comMtx ); #define HB_COM_LOCK() do { hb_threadEnterCriticalSection( &s_comMtx ) #define HB_COM_UNLOCK() hb_threadLeaveCriticalSection( &s_comMtx ); } while( 0 ) static HB_COM s_comList[ HB_COM_PORT_MAX ]; static void hb_comCloseAll( void ) { int iPort; for( iPort = 0; iPort < HB_COM_PORT_MAX; ++iPort ) { if( s_comList[ iPort ].status & HB_COM_OPEN ) hb_comClose( iPort + 1 ); if( s_comList[ iPort ].name ) { hb_xfree( s_comList[ iPort ].name ); s_comList[ iPort ].name = NULL; } } } static void hb_comSetComError( PHB_COM pCom, int iError ) { pCom->error = iError; pCom->oserr = 0; } static PHB_COM hb_comGetPort( int iPort, int iStatus ) { if( iPort >= 1 && iPort <= HB_COM_PORT_MAX ) { PHB_COM pCom = &s_comList[ iPort - 1 ]; if( iStatus == HB_COM_ANY || ( iStatus & pCom->status ) != 0 ) return pCom; if( iStatus & HB_COM_ENABLED ) hb_comSetComError( pCom, HB_COM_ERR_WRONGPORT ); else hb_comSetComError( pCom, HB_COM_ERR_CLOSED ); } return NULL; } static const char * hb_comGetNameRaw( PHB_COM pCom, char * buffer, int size ) { const char * name = pCom->name; if( name == NULL ) { #if defined( HB_OS_UNIX ) # if defined( HB_OS_SUNOS ) hb_snprintf( buffer, size, "/dev/tty%c", pCom->port + 'a' - 1 ); # elif defined( HB_OS_HPUX ) hb_snprintf( buffer, size, "/dev/tty%dp0", pCom->port ); # elif defined( HB_OS_AIX ) hb_snprintf( buffer, size, "/dev/tty%d", pCom->port ); # elif defined( HB_OS_MINIX ) hb_snprintf( buffer, size, "/dev/tty%02d", pCom->port - 1 ); # elif defined( HB_OS_IRIX ) hb_snprintf( buffer, size, "/dev/ttyf%d", pCom->port ); # elif defined( HB_OS_DIGITAL_UNIX ) hb_snprintf( buffer, size, "/dev/ttyf%02d", pCom->port ); # elif defined( HB_OS_DARWIN ) hb_snprintf( buffer, size, "/dev/cuaa%d", pCom->port - 1 ); # else /* defined( HB_OS_LINUX ) || defined( HB_OS_CYGWIN ) || ... */ hb_snprintf( buffer, size, "/dev/ttyS%d", pCom->port - 1 ); # endif #elif defined( HB_OS_WIN_CE ) hb_snprintf( buffer, size, "COM%d:", pCom->port ); #else if( hb_iswinnt() || hb_iswince() ) hb_snprintf( buffer, size, "\\\\.\\COM%d", pCom->port ); else hb_snprintf( buffer, size, "COM%d", pCom->port ); #endif name = buffer; } return name; } static const char * hb_comGetName( PHB_COM pCom, char * buffer, int size ) { const char * name; HB_COM_LOCK(); name = hb_comGetNameRaw( pCom, buffer, size ); if( name != buffer ) name = hb_strncpy( buffer, name, size - 1 ); HB_COM_UNLOCK(); return name; } static int hb_comGetPortNum( const char * pszName ) { int iPort = 0; #if defined( HB_OS_UNIX ) # if defined( HB_OS_SUNOS ) if( strncmp( pszName, "/dev/tty", 8 ) == 0 && pszName[ 8 ] >= 'a' && pszName[ 9 ] == '\0' ) iPort = pszName[ 8 ] - 'a' + 1; # else int iLen = 0; # if defined( HB_OS_HPUX ) || defined( HB_OS_AIX ) || defined( HB_OS_MINIX ) if( strncmp( pszName, "/dev/tty", 8 ) == 0 ) iLen = 8; # elif defined( HB_OS_IRIX ) || defined( HB_OS_DIGITAL_UNIX ) if( strncmp( pszName, "/dev/ttyf", 9 ) == 0 ) iLen = 9; # elif defined( HB_OS_DARWIN ) if( strncmp( pszName, "/dev/cuaa", 9 ) == 0 ) iLen = 9; # else /* defined( HB_OS_LINUX ) || defined( HB_OS_CYGWIN ) || ... */ if( strncmp( pszName, "/dev/ttyS", 9 ) == 0 ) iLen = 9; # endif if( iLen > 0 ) { pszName += iLen; while( HB_ISDIGIT( *pszName ) ) iPort = iPort * 10 + ( *pszName++ - '0' ); # if ! defined( HB_OS_HPUX ) && \ ! defined( HB_OS_AIX ) && \ ! defined( HB_OS_IRIX ) && \ ! defined( HB_OS_DIGITAL_UNIX ) ++iPort; # endif # if defined( HB_OS_HPUX ) if( strcmp( pszName, "p0" ) != 0 ) # else if( *pszName != '\0' ) # endif iPort = 0; } # endif #else if( pszName[ 0 ] == '\\' && pszName[ 1 ] == '\\' && pszName[ 2 ] == '.' && pszName[ 3 ] == '\\' ) pszName += 4; if( HB_TOUPPER( pszName[ 0 ] ) == 'C' && HB_TOUPPER( pszName[ 1 ] ) == 'O' && HB_TOUPPER( pszName[ 2 ] ) == 'M' && pszName[ 3 ] >= '1' && pszName[ 3 ] <= '9' ) { pszName += 3; while( HB_ISDIGIT( *pszName ) ) iPort = iPort * ( 10 + *pszName++ - '0' ); if( *pszName != '\0' ) iPort = 0; } #endif return iPort; } static HB_BOOL hb_comPortCmp( const char * pszDevName1, const char * pszDevName2 ) { #if defined( HB_OS_UNIX ) return strcmp( pszDevName1, pszDevName2 ) == 0; #else # if defined( HB_OS_WIN ) if( pszDevName1[ 0 ] == '\\' && pszDevName1[ 1 ] == '\\' && pszDevName1[ 2 ] == '.' && pszDevName1[ 3 ] == '\\' ) pszDevName1 += 4; if( pszDevName2[ 0 ] == '\\' && pszDevName2[ 1 ] == '\\' && pszDevName2[ 2 ] == '.' && pszDevName2[ 3 ] == '\\' ) pszDevName2 += 4; # endif return hb_stricmp( pszDevName1, pszDevName2 ) == 0; #endif } int hb_comFindPort( const char * pszDevName, HB_BOOL fCreate ) { char buffer[ HB_COM_DEV_NAME_MAX ]; PHB_COM pCom; int iPort; if( pszDevName == NULL || *pszDevName == '\0' ) return 0; iPort = hb_comGetPortNum( pszDevName ); HB_COM_LOCK(); if( iPort > 0 ) { pCom = hb_comGetPort( iPort, HB_COM_ANY ); if( pCom == NULL || ! hb_comPortCmp( hb_comGetNameRaw( pCom, buffer, sizeof( buffer ) ), pszDevName ) ) iPort = 0; } if( iPort == 0 ) { int iPortFree = 0; for( iPort = HB_COM_PORT_MAX; iPort > 0; --iPort ) { pCom = &s_comList[ iPort - 1 ]; if( pCom->name == NULL ) { if( iPortFree == 0 && iPort > 16 ) iPortFree = iPort; } else if( hb_comPortCmp( pCom->name, pszDevName ) ) break; } #if defined( HB_OS_UNIX ) if( iPort == 0 && fCreate && access( pszDevName, F_OK ) == 0 ) #else if( iPort == 0 && fCreate ) #endif { if( iPortFree != 0 ) iPort = iPortFree; else { for( iPort = HB_COM_PORT_MAX; iPort > 0; --iPort ) { pCom = &s_comList[ iPort - 1 ]; if( ( pCom->status & HB_COM_OPEN ) == 0 ) { if( pCom->name ) { hb_xfree( pCom->name ); pCom->name = NULL; } break; } } } if( iPort != 0 ) { pCom = &s_comList[ iPort - 1 ]; if( ! hb_comPortCmp( hb_comGetNameRaw( pCom, buffer, sizeof( buffer ) ), pszDevName ) ) pCom->name = hb_strdup( pszDevName ); } } } HB_COM_UNLOCK(); return iPort; } const char * hb_comGetDevice( int iPort, char * buffer, int size ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ANY ); const char * pszName = NULL; if( pCom ) { if( buffer && size > 0 ) pszName = hb_comGetName( pCom, buffer, size ); else pszName = pCom->name; } return pszName; } int hb_comSetDevice( int iPort, const char * szDevName ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ANY ); if( pCom ) { HB_COM_LOCK(); if( pCom->name ) hb_xfree( pCom->name ); pCom->name = szDevName && *szDevName ? hb_strdup( szDevName ) : NULL; HB_COM_UNLOCK(); } return pCom ? 0 : -1; } HB_FHANDLE hb_comGetDeviceHandle( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ANY ); HB_FHANDLE hFile = FS_ERROR; if( pCom ) { #if defined( HB_HAS_TERMIOS ) hFile = pCom->fd; #elif defined( HB_OS_WIN ) hFile = ( HB_FHANDLE ) pCom->hComm; #elif defined( HB_OS_OS2 ) hFile = ( HB_FHANDLE ) pCom->hFile; #endif } return hFile; } void hb_comSetError( int iPort, int iError ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ANY ); if( pCom ) pCom->error = iError; } int hb_comGetError( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ANY ); return pCom ? pCom->error : HB_COM_ERR_WRONGPORT; } int hb_comGetOsError( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ANY ); return pCom ? pCom->oserr : 0; } int hb_comLastNum( void ) { int iPort; for( iPort = HB_COM_PORT_MAX; iPort; --iPort ) { if( s_comList[ iPort - 1 ].status & HB_COM_ENABLED ) break; } return iPort; } #if defined( HB_HAS_TERMIOS ) #define HB_COM_IS_EINTR( pCom ) ( ( pCom )->oserr == EINTR ) #define HB_COM_IS_EBADF( pCom ) ( ( pCom )->oserr == EBADF ) #define HB_COM_GETERROR() ( errno ) #if defined( HB_OS_LINUX ) # define HB_HAS_SELECT_TIMER #endif static void hb_comSetOsError( PHB_COM pCom, HB_BOOL fError ) { pCom->oserr = fError ? HB_COM_GETERROR() : 0; switch( pCom->oserr ) { case 0: pCom->error = 0; break; case EIO: pCom->error = HB_COM_ERR_IO; break; case EPIPE: pCom->error = HB_COM_ERR_PIPE; break; case EBUSY: pCom->error = HB_COM_ERR_BUSY; break; case EAGAIN: pCom->error = HB_COM_ERR_TIMEOUT; break; case EACCES: #if defined( ETXTBSY ) case ETXTBSY: #endif #if defined( EPERM ) case EPERM: #endif pCom->error = HB_COM_ERR_ACCESS; break; case ENOTTY: case ENOENT: #if defined( ENOTDIR ) case ENOTDIR: #endif pCom->error = HB_COM_ERR_NOCOM; break; default: pCom->error = HB_COM_ERR_OTHER; break; } } #if defined( HB_OS_UNIX ) static int hb_comCanRead( PHB_COM pCom, HB_MAXINT timeout ) { int iResult; #if defined( HB_HAS_POLL ) HB_MAXUINT timer = hb_timerInit( timeout ); struct pollfd fds; fds.fd = pCom->fd; fds.events = POLLIN; fds.revents = 0; do { int tout = timeout < 0 || timeout > 1000 ? 1000 : ( int ) timeout; iResult = poll( &fds, 1, tout ); hb_comSetOsError( pCom, iResult == -1 ); if( iResult > 0 && ( fds.revents & POLLIN ) == 0 ) { if( ( fds.revents & ( POLLHUP | POLLNVAL | POLLERR ) ) != 0 ) { if( fds.revents & POLLNVAL ) pCom->fd = -1; hb_comSetComError( pCom, HB_COM_ERR_PIPE ); iResult = -1; break; } iResult = 0; } else if( iResult == -1 && HB_COM_IS_EINTR( pCom ) ) iResult = 0; } while( iResult == 0 && ( timeout = hb_timerTest( timeout, &timer ) ) != 0 && hb_vmRequestQuery() == 0 ); #else /* ! HB_HAS_POLL */ struct timeval tv; fd_set rfds; # if ! defined( HB_HAS_SELECT_TIMER ) HB_MAXUINT timer = hb_timerInit( timeout ); # else tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000; # endif for( ;; ) { if( timeout < 0 ) { tv.tv_sec = 1; tv.tv_usec = 0; } # if ! defined( HB_HAS_SELECT_TIMER ) else { tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000; } # endif FD_ZERO( &rfds ); FD_SET( pCom->fd, &rfds ); iResult = select( ( int ) ( pCom->fd + 1 ), &rfds, NULL, NULL, &tv ); hb_comSetOsError( pCom, iResult == -1 ); if( iResult > 0 && ! FD_ISSET( pCom->fd, &rfds ) ) iResult = 0; else if( iResult == -1 && HB_COM_IS_EINTR( pCom ) ) iResult = 0; # if defined( HB_HAS_SELECT_TIMER ) if( iResult != 0 || timeout >= 0 || hb_vmRequestQuery() != 0 ) break; # else if( iResult != 0 || ( timeout = hb_timerTest( timeout, &timer ) ) == 0 || hb_vmRequestQuery() != 0 ) break; # endif } #endif /* ! HB_HAS_POLL */ return iResult; } static int hb_comCanWrite( PHB_COM pCom, HB_MAXINT timeout ) { int iResult; #if defined( HB_HAS_POLL ) HB_MAXUINT timer = hb_timerInit( timeout ); struct pollfd fds; fds.fd = pCom->fd; fds.events = POLLOUT; fds.revents = 0; do { int tout = timeout < 0 || timeout > 1000 ? 1000 : ( int ) timeout; iResult = poll( &fds, 1, tout ); hb_comSetOsError( pCom, iResult == -1 ); if( iResult > 0 && ( fds.revents & POLLOUT ) == 0 ) { if( ( fds.revents & ( POLLHUP | POLLNVAL | POLLERR ) ) != 0 ) { if( fds.revents & POLLNVAL ) pCom->fd = -1; hb_comSetComError( pCom, HB_COM_ERR_PIPE ); iResult = -1; break; } iResult = 0; } else if( iResult == -1 && HB_COM_IS_EINTR( pCom ) ) iResult = 0; } while( iResult == 0 && ( timeout = hb_timerTest( timeout, &timer ) ) != 0 && hb_vmRequestQuery() == 0 ); #else /* ! HB_HAS_POLL */ struct timeval tv; fd_set wfds; # if ! defined( HB_HAS_SELECT_TIMER ) HB_MAXUINT timer = hb_timerInit( timeout ); # else tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000; # endif for( ;; ) { if( timeout < 0 ) { tv.tv_sec = 1; tv.tv_usec = 0; } # if ! defined( HB_HAS_SELECT_TIMER ) else { tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000; } # endif FD_ZERO( &wfds ); FD_SET( pCom->fd, &wfds ); iResult = select( ( int ) ( pCom->fd + 1 ), NULL, &wfds, NULL, &tv ); hb_comSetOsError( pCom, iResult == -1 ); if( iResult > 0 && ! FD_ISSET( pCom->fd, &wfds ) ) iResult = 0; else if( iResult == -1 && HB_COM_IS_EINTR( pCom ) ) iResult = 0; # if defined( HB_HAS_SELECT_TIMER ) if( iResult != 0 || timeout >= 0 || hb_vmRequestQuery() != 0 ) break; # else if( iResult != 0 || ( timeout = hb_timerTest( timeout, &timer ) ) == 0 || hb_vmRequestQuery() != 0 ) break; # endif } #endif /* ! HB_HAS_POLL */ return iResult; } #endif int hb_comInputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = 0; if( pCom ) { #if defined( TIOCINQ ) int iResult = ioctl( pCom->fd, TIOCINQ, &iCount ); if( iResult == -1 ) iCount = 0; hb_comSetOsError( pCom, iResult == -1 ); #elif defined( FIONREAD ) && ! defined( HB_OS_CYGWIN ) /* Cygwin sys/termios.h explicitly says that "TIOCINQ is * utilized instead of FIONREAD which has been occupied for * other purposes under CYGWIN", so don't give Cygwin * even a chance to hit this code path. */ int iResult = ioctl( pCom->fd, FIONREAD, &iCount ); if( iResult == -1 ) iCount = 0; hb_comSetOsError( pCom, iResult == -1 ); #else int TODO_TIOCINQ; hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); #endif } else iCount = -1; return iCount; } int hb_comOutputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = 0; if( pCom ) { #if defined( TIOCOUTQ ) int iResult = ioctl( pCom->fd, TIOCOUTQ, &iCount ); if( iResult == -1 ) iCount = 0; hb_comSetOsError( pCom, iResult == -1 ); #elif defined( FIONWRITE ) int iResult = ioctl( pCom->fd, FIONWRITE, &iCount ); if( iResult == -1 ) iCount = 0; hb_comSetOsError( pCom, iResult == -1 ); #else int TODO_TIOCOUTQ; hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); #endif } else iCount = -1; return iCount; } int hb_comFlush( int iPort, int iType ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { switch( iType ) { case HB_COM_IFLUSH: iResult = tcflush( pCom->fd, TCIFLUSH ); hb_comSetOsError( pCom, iResult == -1 ); break; case HB_COM_OFLUSH: iResult = tcflush( pCom->fd, TCOFLUSH ); hb_comSetOsError( pCom, iResult == -1 ); break; case HB_COM_IOFLUSH: iResult = tcflush( pCom->fd, TCIOFLUSH ); hb_comSetOsError( pCom, iResult == -1 ); break; default: iResult = -1; hb_comSetComError( pCom, HB_COM_ERR_PARAMVALUE ); break; } } return iResult; } /* TIOCM_LE DSR (data set ready/line enable) TIOCM_DTR DTR (data terminal ready) TIOCM_RTS RTS (request to send) TIOCM_ST Secondary TXD (transmit) TIOCM_SR Secondary RXD (receive) TIOCM_CTS CTS (clear to send) TIOCM_CAR DCD (data carrier detect) TIOCM_CD see TIOCM_CAR TIOCM_RNG RNG (ring) TIOCM_RI see TIOCM_RNG TIOCM_DSR DSR (data set ready) supported only by few platforms (i.e. newer Linux kernels >= 2.4) TIOCM_OUT1 OUT 1 (auxiliary user-designated output 2) TIOCM_OUT2 OUT 2 (auxiliary user-designated output 1) TIOCM_LOOP LOOP (loopback mode) */ #ifdef HB_OS_LINUX /* hack for missing definitions in standard header files */ # ifndef TIOCM_OUT1 # define TIOCM_OUT1 0x2000 # endif # ifndef TIOCM_OUT2 # define TIOCM_OUT2 0x4000 # endif # ifndef TIOCM_LOOP # define TIOCM_LOOP 0x8000 # endif #endif int hb_comMCR( int iPort, int * piValue, int iClr, int iSet ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1, iValue = 0; if( pCom ) { #if defined( TIOCMGET ) && defined( TIOCMSET ) int iRawVal, iOldVal; iResult = ioctl( pCom->fd, TIOCMGET, &iRawVal ); if( iResult == 0 ) { if( iRawVal & TIOCM_DTR ) iValue |= HB_COM_MCR_DTR; if( iRawVal & TIOCM_RTS ) iValue |= HB_COM_MCR_RTS; #ifdef TIOCM_OUT1 if( iRawVal & TIOCM_OUT1 ) iValue |= HB_COM_MCR_OUT1; #endif #ifdef TIOCM_OUT2 if( iRawVal & TIOCM_OUT2 ) iValue |= HB_COM_MCR_OUT2; #endif #ifdef TIOCM_LOOP if( iRawVal & TIOCM_LOOP ) iValue |= HB_COM_MCR_LOOP; #endif iOldVal = iRawVal; if( iSet & HB_COM_MCR_DTR ) iRawVal |= TIOCM_DTR; else if( iClr & HB_COM_MCR_DTR ) iRawVal &= ~TIOCM_DTR; if( iSet & HB_COM_MCR_RTS ) iRawVal |= TIOCM_RTS; else if( iClr & HB_COM_MCR_RTS ) iRawVal &= ~TIOCM_RTS; #ifdef TIOCM_OUT1 if( iSet & HB_COM_MCR_OUT1 ) iRawVal |= TIOCM_OUT1; else if( iClr & HB_COM_MCR_OUT1 ) iRawVal &= ~TIOCM_OUT1; #endif #ifdef TIOCM_OUT2 if( iSet & HB_COM_MCR_OUT2 ) iRawVal |= TIOCM_OUT2; else if( iClr & HB_COM_MCR_OUT2 ) iRawVal &= ~TIOCM_OUT2; #endif #ifdef TIOCM_LOOP if( iSet & HB_COM_MCR_LOOP ) iRawVal |= TIOCM_LOOP; else if( iClr & HB_COM_MCR_LOOP ) iRawVal &= ~TIOCM_LOOP; #endif if( iRawVal != iOldVal ) iResult = ioctl( pCom->fd, TIOCMSET, &iRawVal ); } hb_comSetOsError( pCom, iResult == -1 ); #else int TODO_TIOCMGET_MCR; HB_SYMBOL_UNUSED( iClr ); HB_SYMBOL_UNUSED( iSet ); hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); #endif } if( piValue ) *piValue = iValue; return iResult; } int hb_comMSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1, iValue = 0; if( pCom ) { #if defined( TIOCMGET ) && defined( TIOCMSET ) int iRawVal; iResult = ioctl( pCom->fd, TIOCMGET, &iRawVal ); hb_comSetOsError( pCom, iResult == -1 ); if( iResult == 0 ) { if( iRawVal & TIOCM_CTS ) iValue |= HB_COM_MSR_CTS; if( iRawVal & TIOCM_DSR ) iValue |= HB_COM_MSR_DSR; if( iRawVal & TIOCM_RI ) iValue |= HB_COM_MSR_RI; if( iRawVal & TIOCM_CD ) iValue |= HB_COM_MSR_DCD; } #else int TODO_TIOCMGET_MSR; hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); #endif } if( piValue ) *piValue = iValue; return iResult; } int hb_comLSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1, iValue = 0; if( pCom ) { #ifdef TIOCSERGETLSR iResult = ioctl( pCom->fd, TIOCSERGETLSR, &iValue ); hb_comSetOsError( pCom, iResult == -1 ); #else /* NOTE: most of systems do not give access to the * Line Status Register (LSR) */ hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); #endif } if( piValue ) *piValue = iValue; return iResult; } int hb_comSendBreak( int iPort, int iDurationInMilliSecs ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { /* NOTE: duration is implementation defined non portable extension * we use 0 what means 'transmit zero-valued bits for at * least 0.25 seconds, and not more that 0.5 seconds' */ HB_SYMBOL_UNUSED( iDurationInMilliSecs ); hb_vmUnlock(); iResult = tcsendbreak( pCom->fd, 0 ); hb_comSetOsError( pCom, iResult == -1 ); hb_vmLock(); } return iResult; } #if defined( CCTS_OFLOW ) && defined( CRTS_IFLOW ) #define _HB_OCRTSCTS CCTS_OFLOW #define _HB_ICRTSCTS CRTS_IFLOW #elif defined( CRTSCTS ) && defined( CRTSXOFF ) #define _HB_OCRTSCTS CRTSCTS #define _HB_ICRTSCTS CRTSXOFF #elif defined( CRTSCTS ) #define _HB_OCRTSCTS CRTSCTS #define _HB_ICRTSCTS CRTSCTS #elif defined( CNEW_RTSCTS ) #define _HB_OCRTSCTS CNEW_RTSCTS #define _HB_ICRTSCTS CNEW_RTSCTS #elif defined( CCTS_OFLOW ) #define _HB_OCRTSCTS CCTS_OFLOW #define _HB_ICRTSCTS 0 #elif defined( CRTS_IFLOW ) #define _HB_OCRTSCTS 0 #define _HB_ICRTSCTS CCTS_IFLOW #elif defined( CRTSXOFF ) #define _HB_OCRTSCTS 0 #define _HB_ICRTSCTS CRTSXOFF #else /* if you find compiler which does not support it then please check * if such flow control is supported by OS. If yes then check exact * value for this switch on given OS and define it only for given * compiler and OS */ #if defined( HB_OS_LINUX ) && defined( __WATCOMC__ ) #define _HB_OCRTSCTS 020000000000 #define _HB_ICRTSCTS 020000000000 #endif #endif int hb_comFlowControl( int iPort, int * piFlow, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1, iValue = 0; if( pCom ) { /* NOTE: there is no support for DTR/DSR so we cannot use * DTR/DSR handshake instead of the RTS/CTS handshake * BSD systems support MDMBUF flags which enable output * flow control using CD (Carrier Detect) flag. * In SunOS TIOCSSOFTCAR can be used to control CLOCAL flag. * CLOCAL termios structure c_cflag can be used to enable CD * flow control in most portable way. */ struct termios tio; iResult = tcgetattr( pCom->fd, &tio ); hb_comSetOsError( pCom, iResult == -1 ); if( iResult == 0 ) { tcflag_t c_cflag = tio.c_cflag; tcflag_t c_iflag = tio.c_iflag; #if defined( _HB_OCRTSCTS ) if( ( tio.c_cflag & _HB_OCRTSCTS ) == _HB_OCRTSCTS ) iValue |= HB_COM_FLOW_ORTSCTS; if( ( tio.c_cflag & _HB_ICRTSCTS ) == _HB_ICRTSCTS ) iValue |= HB_COM_FLOW_IRTSCTS; if( iFlow >= 0 ) { if( iFlow & HB_COM_FLOW_ORTSCTS ) tio.c_cflag |= _HB_OCRTSCTS; else tio.c_cflag &= ~_HB_OCRTSCTS; if( iFlow & HB_COM_FLOW_IRTSCTS ) tio.c_cflag |= _HB_ICRTSCTS; else tio.c_cflag &= ~_HB_ICRTSCTS; } #else { int TODO_CRTSCTS; } #endif if( ( tio.c_cflag & CLOCAL ) != CLOCAL ) iValue |= HB_COM_FLOW_DCD; if( iFlow >= 0 ) { if( iFlow & HB_COM_FLOW_DCD ) tio.c_cflag &= ~CLOCAL; else tio.c_cflag |= CLOCAL; } if( ( tio.c_iflag & IXON ) == IXON ) iValue |= HB_COM_FLOW_XON; if( ( tio.c_iflag & IXOFF ) == IXOFF ) iValue |= HB_COM_FLOW_XOFF; if( iFlow >= 0 ) { if( iFlow & HB_COM_FLOW_XON ) tio.c_iflag |= IXON; else tio.c_iflag &= ~IXON; if( iFlow & HB_COM_FLOW_XOFF ) tio.c_iflag |= IXOFF; else tio.c_iflag &= ~IXOFF; } if( c_cflag != tio.c_cflag || c_iflag != tio.c_iflag ) { iResult = tcsetattr( pCom->fd, TCSANOW, &tio ); hb_comSetOsError( pCom, iResult == -1 ); } } } if( piFlow ) *piFlow = iValue; return iResult; } int hb_comFlowSet( int iPort, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { /* NOTE: HB_COM_FL_SOFT is ignored, we assume that user chose * correct hardware/software flow control type which is * the same as set in terminal device parameters */ if( iFlow & HB_COM_FL_OON ) iResult = tcflow( pCom->fd, TCOON ); else if( iFlow & HB_COM_FL_OOFF ) iResult = tcflow( pCom->fd, TCOOFF ); else iResult = 0; if( iFlow & HB_COM_FL_ION ) { if( tcflow( pCom->fd, TCION ) == -1 ) iResult = -1; } else if( iFlow & HB_COM_FL_IOFF ) { if( tcflow( pCom->fd, TCIOFF ) == -1 ) iResult = -1; } hb_comSetOsError( pCom, iResult == -1 ); } return iResult; } int hb_comFlowChars( int iPort, int iXONchar, int iXOFFchar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { iResult = 0; if( iXONchar >= 0 || iXOFFchar >= 0 ) { struct termios tio; iResult = tcgetattr( pCom->fd, &tio ); if( iResult == 0 ) { if( iXONchar >= 0 ) tio.c_cc[ VSTART ] = iXONchar; if( iXOFFchar >= 0 ) tio.c_cc[ VSTOP ] = iXOFFchar; iResult = tcsetattr( pCom->fd, TCSANOW, &tio ); } } hb_comSetOsError( pCom, iResult == -1 ); } return iResult; } #if ! defined( _POSIX_VDISABLE ) # define _POSIX_VDISABLE '\0' #endif int hb_comDiscardChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { #if defined( VDISCARD ) && defined( IEXTEN ) struct termios tio; iResult = tcgetattr( pCom->fd, &tio ); hb_comSetOsError( pCom, iResult == -1 ); if( iResult == 0 ) { if( ( tio.c_lflag & IEXTEN ) != 0 && tio.c_cc[ VDISCARD ] != _POSIX_VDISABLE ) iResult = 1; if( iChar == -1 ? iResult != 0 : ( iResult == 0 || tio.c_cc[ VDISCARD ] != iChar ) ) { if( iChar == -1 ) { tio.c_lflag &= ~IEXTEN; tio.c_cc[ VDISCARD ] = _POSIX_VDISABLE; } else { tio.c_lflag |= IEXTEN; tio.c_cc[ VDISCARD ] = iChar; #if defined( VLNEXT ) tio.c_cc[ VLNEXT ] = _POSIX_VDISABLE; #endif } if( tcsetattr( pCom->fd, TCSANOW, &tio ) == -1 ) { hb_comSetOsError( pCom, HB_TRUE ); iResult = -1; } } } #else int TODO_VDISCARD; HB_SYMBOL_UNUSED( iChar ); hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); #endif } return iResult; } int hb_comErrorChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { /* NOTE: there is no support for setting user defined error character */ HB_SYMBOL_UNUSED( iChar ); hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); } return iResult; } int hb_comOutputState( int iPort ) { /* NOTE: checking HB_COM_TX_* output flow states is unsupported */ int iResult = hb_comOutputCount( iPort ); if( iResult == 0 ) iResult = HB_COM_TX_EMPTY; else if( iResult > 0 ) iResult = 0; return iResult; } int hb_comInputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { /* NOTE: checking HB_COM_RX_* input flow states is unsupported */ hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); } return iResult; } long hb_comSend( int iPort, const void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lSent = -1; if( pCom ) { hb_vmUnlock(); #if defined( HB_OS_UNIX ) if( timeout >= 0 ) { lSent = hb_comCanWrite( pCom, timeout ); if( lSent == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lSent = -1; } } else lSent = 0; #else /* NOTE: write timeout is unsupported */ HB_SYMBOL_UNUSED( timeout ); lSent = 0; #endif if( lSent >= 0 ) { do { lSent = write( pCom->fd, data, len ); hb_comSetOsError( pCom, lSent == -1 ); } while( lSent == -1 && HB_COM_IS_EINTR( pCom ) && hb_vmRequestQuery() == 0 ); } hb_vmLock(); } return lSent; } long hb_comRecv( int iPort, void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lReceived = -1; if( pCom ) { hb_vmUnlock(); #if defined( HB_OS_UNIX ) if( timeout >= 0 ) { lReceived = hb_comCanRead( pCom, timeout ); if( lReceived == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lReceived = -1; } } else lReceived = 0; #else if( timeout != pCom->rdtimeout ) { /* TODO: implement timeout settings * tio.c_cc[ VTIME ] = ( timeout + 50 ) / 100; * tio.c_cc[ VMIN ] = 0; * in DJGPP builds */ } lReceived = 0; #endif if( lReceived >= 0 ) { do { lReceived = read( pCom->fd, ( char * ) data, len ); hb_comSetOsError( pCom, lReceived == -1 ); } while( lReceived == -1 && HB_COM_IS_EINTR( pCom ) && hb_vmRequestQuery() == 0 ); } hb_vmLock(); } return lReceived; } int hb_comInit( int iPort, int iBaud, int iParity, int iSize, int iStop ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { struct termios tio; iResult = tcgetattr( pCom->fd, &tio ); hb_comSetOsError( pCom, iResult == -1 ); if( iResult == 0 ) { #if defined( cfmakeraw ) || defined( HB_OS_LINUX ) /* Raw input from device */ cfmakeraw( &tio ); #endif tio.c_iflag &= ~( IGNBRK | IGNPAR | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF ); tio.c_oflag &= ~OPOST; tio.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN ); tio.c_cflag &= ~( CSIZE | PARENB ); /* Enable the receiver and set local mode... */ tio.c_cflag |= ( CLOCAL | CREAD ); tio.c_cc[ VTIME ] = 0; /* inter-character timer in 1/10 sec. */ #if 0 tio.c_cc[ VMIN ] = 0; /* minimum number of characters for read */ #else /* workaround for bug in some Linux kernels (i.e. 3.13.0-64-generic *buntu) in which select() unconditionally accepts stdin for reading if c_cc[ VMIN ] = 0 [druzus] */ tio.c_cc[ VMIN ] = 1; #endif if( iBaud ) { switch( iBaud ) { case 0: iBaud = B0; break; case 50: iBaud = B50; break; case 75: iBaud = B75; break; case 110: iBaud = B110; break; case 150: iBaud = B150; break; case 200: iBaud = B200; break; case 300: iBaud = B300; break; case 600: iBaud = B600; break; case 1200: iBaud = B1200; break; case 1800: iBaud = B1800; break; case 2400: iBaud = B2400; break; case 4800: iBaud = B4800; break; case 9600: iBaud = B9600; break; case 19200: iBaud = B19200; break; case 38400: iBaud = B38400; break; #ifdef B57600 case 57600: iBaud = B57600; break; #endif #ifdef B115200 case 115200: iBaud = B115200; break; #endif #ifdef B230400 case 230400: iBaud = B230400; break; #endif #ifdef B460800 case 460800: iBaud = B460800; break; #endif #ifdef B500000 case 500000: iBaud = B500000; break; #endif #ifdef B576000 case 576000: iBaud = B576000; break; #endif #ifdef B921600 case 921600: iBaud = B921600; break; #endif #ifdef B1000000 case 1000000: iBaud = B1000000; break; #endif default: iResult = -1; } } switch( iParity ) { case 0: case 'N': case 'n': tio.c_cflag &= ~( PARENB | PARODD ); tio.c_iflag &= ~INPCK; break; case 'E': case 'e': tio.c_cflag |= PARENB; tio.c_cflag &= ~PARODD; tio.c_iflag |= INPCK; break; case 'O': case 'o': tio.c_cflag |= PARENB | PARODD; tio.c_iflag |= INPCK; break; #if defined( CMSPAR ) case 'S': case 's': tio.c_cflag |= CMSPAR | PARENB; tio.c_cflag &= ~PARODD; tio.c_iflag |= INPCK; break; case 'M': case 'm': tio.c_cflag |= CMSPAR | PARENB | PARODD; tio.c_iflag |= INPCK; break; #endif default: iResult = -1; } switch( iSize ) { case 0: case 8: tio.c_cflag |= CS8; break; case 7: tio.c_cflag |= CS7; break; case 6: tio.c_cflag |= CS6; break; case 5: tio.c_cflag |= CS5; break; default: iResult = -1; } switch( iStop ) { case 0: case 1: tio.c_cflag &= ~CSTOPB; break; case 2: tio.c_cflag |= CSTOPB; break; default: iResult = -1; } if( iResult == 0 ) { if( iBaud ) { cfsetispeed( &tio, iBaud ); cfsetospeed( &tio, iBaud ); } iResult = tcsetattr( pCom->fd, TCSAFLUSH, &tio ); #if ! defined( HB_OS_UNIX ) if( iResult == 0 ) pCom->rdtimeout = 0; #endif hb_comSetOsError( pCom, iResult == -1 ); } else hb_comSetComError( pCom, HB_COM_ERR_PARAMVALUE ); } } return iResult; } int hb_comClose( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { hb_vmUnlock(); #if defined( TIOCNXCL ) ioctl( pCom->fd, TIOCNXCL, 0 ); #endif do { iResult = close( pCom->fd ); hb_comSetOsError( pCom, iResult == -1 ); } while( iResult == -1 && HB_COM_IS_EINTR( pCom ) && hb_vmRequestQuery() == 0 ); if( iResult != -1 || HB_COM_IS_EBADF( pCom ) ) { pCom->fd = ( HB_FHANDLE ) FS_ERROR; pCom->status &= ~HB_COM_OPEN; } hb_vmLock(); } return iResult; } int hb_comOpen( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ENABLED ); int iResult = -1; if( pCom ) { if( pCom->status & HB_COM_OPEN ) { hb_comSetComError( pCom, HB_COM_ERR_ALREADYOPEN ); } else { char buffer[ HB_COM_DEV_NAME_MAX ]; const char * name = hb_comGetName( pCom, buffer, sizeof( buffer ) ); hb_vmUnlock(); pCom->fd = open( name, O_RDWR | O_NOCTTY ); if( pCom->fd != -1 ) { #if defined( TIOCEXCL ) /* TIOCNXCL */ iResult = ioctl( pCom->fd, TIOCEXCL, 0 ); if( iResult != 0 ) { close( pCom->fd ); pCom->fd = -1; hb_comSetComError( pCom, HB_COM_ERR_BUSY ); } else #else iResult = 0; #endif pCom->status |= HB_COM_OPEN; } hb_comSetOsError( pCom, iResult == -1 ); hb_vmLock(); } } return iResult; } /* end of HB_HAS_TERMIOS */ #elif defined( HB_OS_WIN ) static void hb_comSetOsError( PHB_COM pCom, BOOL fError ) { pCom->oserr = fError ? GetLastError() : 0; switch( pCom->oserr ) { case 0: pCom->error = 0; break; case ERROR_TIMEOUT: pCom->error = HB_COM_ERR_TIMEOUT; break; case ERROR_ACCESS_DENIED: case ERROR_SHARING_VIOLATION: pCom->error = HB_COM_ERR_BUSY; break; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: pCom->error = HB_COM_ERR_NOCOM; break; default: pCom->error = HB_COM_ERR_OTHER; break; } } int hb_comInputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = 0; if( pCom ) { COMSTAT comStat; if( ClearCommError( pCom->hComm, NULL, &comStat ) ) { iCount = comStat.cbInQue; hb_comSetOsError( pCom, HB_FALSE ); } else hb_comSetOsError( pCom, HB_TRUE ); } else iCount = -1; return iCount; } int hb_comOutputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = 0; if( pCom ) { COMSTAT comStat; if( ClearCommError( pCom->hComm, NULL, &comStat ) ) { iCount = comStat.cbOutQue; hb_comSetOsError( pCom, HB_FALSE ); } else hb_comSetOsError( pCom, HB_TRUE ); } else iCount = -1; return iCount; } int hb_comFlush( int iPort, int iType ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; if( pCom ) { switch( iType ) { case HB_COM_IFLUSH: fResult = PurgeComm( pCom->hComm, PURGE_RXCLEAR ); hb_comSetOsError( pCom, ! fResult ); break; case HB_COM_OFLUSH: fResult = PurgeComm( pCom->hComm, PURGE_TXCLEAR ); hb_comSetOsError( pCom, ! fResult ); break; case HB_COM_IOFLUSH: fResult = PurgeComm( pCom->hComm, PURGE_TXCLEAR | PURGE_RXCLEAR ); hb_comSetOsError( pCom, ! fResult ); break; default: hb_comSetComError( pCom, HB_COM_ERR_PARAMVALUE ); break; } } return fResult ? 0 : -1; } int hb_comMCR( int iPort, int * piValue, int iClr, int iSet ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; int iValue = 0; if( pCom ) { if( iSet & HB_COM_MCR_DTR ) fResult = EscapeCommFunction( pCom->hComm, SETDTR ); else if( iClr & HB_COM_MCR_DTR ) fResult = EscapeCommFunction( pCom->hComm, CLRDTR ); if( iSet & HB_COM_MCR_RTS ) fResult = EscapeCommFunction( pCom->hComm, SETRTS ); else if( iClr & HB_COM_MCR_RTS ) fResult = EscapeCommFunction( pCom->hComm, CLRRTS ); /* MCR_OUT1, MCR_OUT2, MCR_LOOP and reading current state * is unsupported */ hb_comSetOsError( pCom, ! fResult ); } if( piValue ) *piValue = iValue; return fResult ? 0 : -1; } int hb_comMSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; int iValue = 0; if( pCom ) { DWORD dwModemStat = 0; fResult = GetCommModemStatus( pCom->hComm, &dwModemStat ); if( fResult ) { if( dwModemStat & MS_CTS_ON ) iValue |= HB_COM_MSR_CTS; if( dwModemStat & MS_DSR_ON ) iValue |= HB_COM_MSR_DSR; if( dwModemStat & MS_RING_ON ) iValue |= HB_COM_MSR_RI; if( dwModemStat & MS_RLSD_ON ) iValue |= HB_COM_MSR_DCD; /* MSR_DELTA_CTS, MSR_DELTA_DSR, MSR_TERI, MSR_DELTA_DCD * are unsupported */ } hb_comSetOsError( pCom, ! fResult ); } if( piValue ) *piValue = iValue; return fResult ? 0 : -1; } int hb_comLSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; int iValue = 0; if( pCom ) { DWORD dwErrors = 0; fResult = ClearCommError( pCom->hComm, &dwErrors, NULL ); if( fResult ) { if( dwErrors & CE_BREAK ) iValue |= HB_COM_LSR_BREAK; if( dwErrors & CE_FRAME ) iValue |= HB_COM_LSR_FRAMING_ERR; if( dwErrors & CE_OVERRUN ) iValue |= HB_COM_LSR_OVERRUN_ERR; if( dwErrors & CE_RXPARITY ) iValue |= HB_COM_LSR_PARITY_ERR; /* LSR_DATA_READY, LSR_TRANS_HOLD_EMPTY, LSR_TRANS_EMPTY * are unsupported */ } hb_comSetOsError( pCom, ! fResult ); } if( piValue ) *piValue = iValue; return fResult ? 0 : -1; } int hb_comSendBreak( int iPort, int iDurationInMilliSecs ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; if( pCom ) { hb_vmUnlock(); fResult = SetCommBreak( pCom->hComm ); if( fResult ) { Sleep( iDurationInMilliSecs ); fResult = ClearCommBreak( pCom->hComm ); } hb_comSetOsError( pCom, ! fResult ); hb_vmLock(); } return fResult ? 0 : -1; } int hb_comFlowControl( int iPort, int * piFlow, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; int iValue = 0; if( pCom ) { DCB dcb; dcb.DCBlength = sizeof( DCB ); fResult = GetCommState( pCom->hComm, &dcb ); if( fResult ) { if( dcb.fRtsControl == RTS_CONTROL_HANDSHAKE ) iValue |= HB_COM_FLOW_IRTSCTS; if( dcb.fOutxCtsFlow ) iValue |= HB_COM_FLOW_ORTSCTS; if( dcb.fDtrControl == DTR_CONTROL_HANDSHAKE ) iValue |= HB_COM_FLOW_IDTRDSR; if( dcb.fOutxDsrFlow ) iValue |= HB_COM_FLOW_ODTRDSR; if( dcb.fInX ) iValue |= HB_COM_FLOW_XOFF; if( dcb.fOutX ) iValue |= HB_COM_FLOW_XON; if( iFlow >= 0 ) { if( iFlow & HB_COM_FLOW_IRTSCTS ) dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; else if( dcb.fRtsControl == RTS_CONTROL_HANDSHAKE ) dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fOutxCtsFlow = ( iFlow & HB_COM_FLOW_ORTSCTS ) != 0; if( iFlow & HB_COM_FLOW_IDTRDSR ) dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; else if( dcb.fDtrControl == DTR_CONTROL_HANDSHAKE ) dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fOutxDsrFlow = ( iFlow & HB_COM_FLOW_ODTRDSR ) != 0; dcb.fInX = ( iFlow & HB_COM_FLOW_XOFF ) != 0; dcb.fOutX = ( iFlow & HB_COM_FLOW_XON ) != 0; fResult = SetCommState( pCom->hComm, &dcb ); } } hb_comSetOsError( pCom, ! fResult ); } if( piFlow ) *piFlow = iValue; return fResult ? 0 : -1; } int hb_comFlowSet( int iPort, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE, fNotSup = FALSE; if( pCom ) { if( iFlow & HB_COM_FL_SOFT ) { if( iFlow & HB_COM_FL_OOFF ) fResult = EscapeCommFunction( pCom->hComm, SETXOFF ); else if( iFlow & HB_COM_FL_OON ) fResult = EscapeCommFunction( pCom->hComm, SETXON ); else fNotSup = TRUE; hb_comSetOsError( pCom, ! fResult ); } else if( iFlow & HB_COM_FL_RTSCTS ) { if( iFlow & HB_COM_FL_IOFF ) fResult = EscapeCommFunction( pCom->hComm, CLRRTS ); else if( iFlow & HB_COM_FL_ION ) fResult = EscapeCommFunction( pCom->hComm, SETRTS ); else fNotSup = TRUE; } else if( iFlow & HB_COM_FL_DTRDSR ) { if( iFlow & HB_COM_FL_IOFF ) fResult = EscapeCommFunction( pCom->hComm, CLRDTR ); else if( iFlow & HB_COM_FL_ION ) fResult = EscapeCommFunction( pCom->hComm, SETDTR ); else fNotSup = TRUE; } else fNotSup = TRUE; if( fNotSup ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); else hb_comSetOsError( pCom, ! fResult ); } return fResult ? 0 : -1; } int hb_comFlowChars( int iPort, int iXONchar, int iXOFFchar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; if( pCom ) { fResult = TRUE; if( iXONchar >= 0 || iXOFFchar >= 0 ) { DCB dcb; dcb.DCBlength = sizeof( DCB ); fResult = GetCommState( pCom->hComm, &dcb ); if( fResult ) { if( iXONchar >= 0 ) dcb.XonChar = ( char ) iXONchar; if( iXOFFchar >= 0 ) dcb.XoffChar = ( char ) iXOFFchar; fResult = SetCommState( pCom->hComm, &dcb ); } } hb_comSetOsError( pCom, ! fResult ); } return fResult ? 0 : -1; } int hb_comDiscardChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { /* NOTE: there is no support for setting user defined character * discarding input buffer */ HB_SYMBOL_UNUSED( iChar ); hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); } return iResult; } int hb_comErrorChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; if( pCom ) { DCB dcb; dcb.DCBlength = sizeof( DCB ); fResult = GetCommState( pCom->hComm, &dcb ); if( fResult ) { if( iChar >= 0 ) { dcb.fErrorChar = TRUE; dcb.ErrorChar = ( char ) iChar; } else dcb.fErrorChar = FALSE; fResult = SetCommState( pCom->hComm, &dcb ); } hb_comSetOsError( pCom, ! fResult ); } return fResult ? 0 : -1; } int hb_comOutputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; int iValue = 0; if( pCom ) { COMSTAT comStat; fResult = ClearCommError( pCom->hComm, NULL, &comStat ); if( fResult ) { /* NOTE: HB_COM_TX_RFLUSH is unsupported */ if( comStat.fCtsHold ) iValue |= HB_COM_TX_CTS; if( comStat.fDsrHold ) iValue |= HB_COM_TX_DSR; if( comStat.fRlsdHold ) iValue |= HB_COM_TX_DCD; if( comStat.fXoffHold ) iValue |= HB_COM_TX_XOFF; if( comStat.cbOutQue == 0 ) iValue |= HB_COM_TX_EMPTY; } hb_comSetOsError( pCom, ! fResult ); } return fResult ? iValue : -1; } int hb_comInputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; int iValue = 0; if( pCom ) { COMSTAT comStat; fResult = ClearCommError( pCom->hComm, NULL, &comStat ); if( fResult ) { if( comStat.fXoffSent ) iValue |= HB_COM_RX_XOFF; } hb_comSetOsError( pCom, ! fResult ); } return fResult ? iValue : -1; } static BOOL hb_comSetTimeouts( PHB_COM pCom, HB_MAXINT rdtimeout, HB_MAXINT wrtimeout ) { COMMTIMEOUTS timeouts; BOOL fResult; if( rdtimeout == 0 ) { timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; } else { timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; timeouts.ReadTotalTimeoutConstant = ( DWORD ) rdtimeout; } timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = ( DWORD ) HB_MAX( wrtimeout, 1 ); fResult = SetCommTimeouts( pCom->hComm, &timeouts ); if( fResult ) { pCom->rdtimeout = rdtimeout; pCom->wrtimeout = wrtimeout; } return fResult; } long hb_comSend( int iPort, const void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lSent = -1; if( pCom ) { hb_vmUnlock(); if( timeout < 0 ) timeout = 0; if( pCom->wrtimeout == timeout || hb_comSetTimeouts( pCom, pCom->rdtimeout, timeout ) ) { DWORD dwWritten = 0; BOOL fResult; fResult = WriteFile( pCom->hComm, data, ( DWORD ) len, &dwWritten, NULL ); lSent = fResult ? ( long ) dwWritten : -1; if( lSent == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lSent = -1; } else hb_comSetOsError( pCom, ! fResult ); } else hb_comSetOsError( pCom, HB_TRUE ); hb_vmLock(); } return lSent; } long hb_comRecv( int iPort, void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lReceived = -1; if( pCom ) { hb_vmUnlock(); if( timeout < 0 ) timeout = 0; if( pCom->rdtimeout == timeout || hb_comSetTimeouts( pCom, timeout, pCom->wrtimeout ) ) { DWORD dwRead = 0; BOOL fResult; fResult = ReadFile( pCom->hComm, data, ( DWORD ) len, &dwRead, NULL ); lReceived = fResult ? ( long ) dwRead : -1; if( lReceived == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lReceived = -1; } else hb_comSetOsError( pCom, ! fResult ); } else hb_comSetOsError( pCom, HB_TRUE ); hb_vmLock(); } return lReceived; } int hb_comInit( int iPort, int iBaud, int iParity, int iSize, int iStop ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; if( pCom ) { DCB dcb; dcb.DCBlength = sizeof( DCB ); fResult = GetCommState( pCom->hComm, &dcb ); if( fResult ) { switch( iParity ) { case 0: case 'N': case 'n': iParity = NOPARITY; break; case 'E': case 'e': iParity = EVENPARITY; break; case 'O': case 'o': iParity = ODDPARITY; break; case 'S': case 's': iParity = SPACEPARITY; break; case 'M': case 'm': iParity = MARKPARITY; break; default: fResult = FALSE; } switch( iSize ) { case 0: iSize = 8; case 8: case 7: case 6: case 5: break; default: fResult = FALSE; } switch( iStop ) { case 0: case 1: iStop = ONESTOPBIT; break; case 2: iStop = TWOSTOPBITS; break; default: fResult = FALSE; } if( fResult ) { if( iBaud ) dcb.BaudRate = ( DWORD ) iBaud; dcb.fBinary = 1; dcb.fParity = 0; dcb.fOutxCtsFlow = 0; dcb.fOutxDsrFlow = 0; dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fDsrSensitivity = 0; dcb.fTXContinueOnXoff = 1; dcb.fOutX = 0; dcb.fInX = 0; dcb.fErrorChar = 0; dcb.fNull = 0; dcb.fRtsControl = RTS_CONTROL_ENABLE; dcb.fAbortOnError = 0; /*dcb.XonLim*/ /*dcb.XoffLim*/ dcb.ByteSize = ( BYTE ) iSize; dcb.Parity = ( BYTE ) iParity; dcb.StopBits = ( BYTE ) iStop; /*dcb.XonChar*/ /*dcb.XoffChar*/ dcb.ErrorChar = '?'; /*dcb.EofChar*/ /*dcb.EvtChar*/ fResult = SetCommState( pCom->hComm, &dcb ); if( fResult ) fResult = hb_comSetTimeouts( pCom, 0, 0 ); hb_comSetOsError( pCom, ! fResult ); } else hb_comSetComError( pCom, HB_COM_ERR_PARAMVALUE ); } else hb_comSetOsError( pCom, ! fResult ); } return fResult ? 0 : -1; } int hb_comClose( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); BOOL fResult = FALSE; if( pCom ) { hb_vmUnlock(); /* FlushFileBuffers( pCom->hComm ); */ fResult = CloseHandle( pCom->hComm ); pCom->hComm = INVALID_HANDLE_VALUE; pCom->status &= ~HB_COM_OPEN; hb_comSetOsError( pCom, ! fResult ); hb_vmLock(); } return fResult ? 0 : -1; } int hb_comOpen( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ENABLED ); BOOL fResult = FALSE; if( pCom ) { if( pCom->status & HB_COM_OPEN ) { hb_comSetComError( pCom, HB_COM_ERR_ALREADYOPEN ); } else { char buffer[ HB_COM_DEV_NAME_MAX ]; const char * szName = hb_comGetName( pCom, buffer, sizeof( buffer ) ); LPCTSTR lpName; LPTSTR lpFree; lpName = HB_FSNAMECONV( szName, &lpFree ); hb_vmUnlock(); pCom->hComm = CreateFile( lpName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL ); if( pCom->hComm != INVALID_HANDLE_VALUE ) { fResult = TRUE; pCom->status |= HB_COM_OPEN; } hb_comSetOsError( pCom, ! fResult ); hb_vmLock(); if( lpFree ) hb_xfree( lpFree ); } } return fResult ? 0 : -1; } /* end of HB_OS_WIN */ #elif defined( HB_OS_OS2 ) static void hb_comSetOsError( PHB_COM pCom, APIRET rc ) { pCom->oserr = rc; switch( pCom->oserr ) { case NO_ERROR: pCom->error = 0; break; case ERROR_TIMEOUT: pCom->error = HB_COM_ERR_TIMEOUT; break; case ERROR_ACCESS_DENIED: case ERROR_SHARING_VIOLATION: pCom->error = HB_COM_ERR_BUSY; break; case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: pCom->error = HB_COM_ERR_NOCOM; break; default: pCom->error = HB_COM_ERR_OTHER; break; } } int hb_comInputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = -1; if( pCom ) { APIRET rc; RXQUEUE rxqueue; memset( &rxqueue, 0, sizeof( rxqueue ) ); rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETINQUECOUNT, NULL, 0, NULL, &rxqueue, sizeof( RXQUEUE ), NULL ); if( rc == NO_ERROR ) iCount = rxqueue.cch; hb_comSetOsError( pCom, rc ); } return iCount; } int hb_comOutputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = -1; if( pCom ) { APIRET rc; RXQUEUE rxqueue; memset( &rxqueue, 0, sizeof( rxqueue ) ); rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETOUTQUECOUNT, NULL, 0, NULL, &rxqueue, sizeof( RXQUEUE ), NULL ); if( rc == NO_ERROR ) iCount = rxqueue.cch; hb_comSetOsError( pCom, rc ); } return iCount; } int hb_comFlush( int iPort, int iType ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); APIRET rc = ERROR_INVALID_HANDLE; if( pCom ) { UCHAR cmdinfo = 0; USHORT reserved = 0; switch( iType ) { case HB_COM_IFLUSH: case HB_COM_IOFLUSH: rc = DosDevIOCtl( pCom->hFile, IOCTL_GENERAL, DEV_FLUSHINPUT, &cmdinfo, sizeof( cmdinfo ), NULL, &reserved, sizeof( reserved ), NULL ); if( iType == HB_COM_IFLUSH ) break; cmdinfo = 0; reserved = 0; case HB_COM_OFLUSH: rc = DosDevIOCtl( pCom->hFile, IOCTL_GENERAL, DEV_FLUSHOUTPUT, &cmdinfo, sizeof( cmdinfo ), NULL, &reserved, sizeof( reserved ), NULL ); break; default: rc = ERROR_INVALID_PARAMETER; break; } } hb_comSetOsError( pCom, rc ); return ( rc == NO_ERROR ) ? 0 : -1; } int hb_comMCR( int iPort, int * piValue, int iClr, int iSet ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; int iValue = 0; if( pCom ) { APIRET rc; UCHAR mcos = 0; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETMODEMOUTPUT, NULL, 0, NULL, &mcos, sizeof( mcos ), NULL ); if( rc == NO_ERROR ) { MODEMSTATUS ms; /* MCR_OUT1, MCR_OUT2, MCR_LOOP are unsupported */ if( mcos & DTR_ON ) iValue |= HB_COM_MCR_DTR; if( mcos & RTS_ON ) iValue |= HB_COM_MCR_RTS; ms.fbModemOn = 0x00; ms.fbModemOff = 0xFF; if( iSet & HB_COM_MCR_DTR ) ms.fbModemOn |= DTR_ON; else if( iClr & HB_COM_MCR_DTR ) ms.fbModemOff &= DTR_OFF; if( iSet & HB_COM_MCR_RTS ) ms.fbModemOn |= RTS_ON; else if( iClr & HB_COM_MCR_RTS ) ms.fbModemOff &= RTS_OFF; if( ms.fbModemOn != 0x00 || ms.fbModemOff != 0xFF ) { USHORT comError = 0; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, &ms, sizeof( ms ), NULL, &comError, sizeof( comError ), NULL ); } } hb_comSetOsError( pCom, rc ); if( rc == NO_ERROR ) iResult = 0; } if( piValue ) *piValue = iValue; return iResult; } int hb_comMSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; int iValue = 0; if( pCom ) { APIRET rc; UCHAR mcis = 0; USHORT comEvent = 0; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETMODEMINPUT, NULL, 0, NULL, &mcis, sizeof( mcis ), NULL ); if( rc == NO_ERROR ) { if( mcis & CTS_ON ) iValue |= HB_COM_MSR_CTS; if( mcis & DSR_ON ) iValue |= HB_COM_MSR_DSR; if( mcis & RI_ON ) iValue |= HB_COM_MSR_RI; if( mcis & DCD_ON ) iValue |= HB_COM_MSR_DCD; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETCOMMEVENT, NULL, 0, NULL, &comEvent, sizeof( comEvent ), NULL ); if( rc == NO_ERROR ) { if( comEvent & CTS_CHANGED ) iValue |= HB_COM_MSR_DELTA_CTS; if( comEvent & DSR_CHANGED ) iValue |= HB_COM_MSR_DELTA_DSR; if( comEvent & DCD_CHANGED ) iValue |= HB_COM_MSR_DELTA_DCD; if( comEvent & RI_DETECTED ) iValue |= HB_COM_MSR_TERI; iResult = 0; } } hb_comSetOsError( pCom, rc ); } if( piValue ) *piValue = iValue; return iResult; } int hb_comLSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; int iValue = 0; if( pCom ) { APIRET rc; USHORT comError = 0; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETCOMMERROR, NULL, 0, NULL, &comError, sizeof( comError ), NULL ); if( rc == NO_ERROR ) { if( comError & ( RX_QUE_OVERRUN | RX_HARDWARE_OVERRUN ) ) iValue |= HB_COM_LSR_OVERRUN_ERR; if( comError & PARITY_ERROR ) iValue |= HB_COM_LSR_PARITY_ERR; if( comError & FRAMING_ERROR ) iValue |= HB_COM_LSR_FRAMING_ERR; /* LSR_DATA_READY, LSR_TRANS_HOLD_EMPTY, LSR_TRANS_EMPTY, LSR_BREAK * are unsupported */ iResult = 0; } hb_comSetOsError( pCom, rc ); } if( piValue ) *piValue = iValue; return iResult; } int hb_comSendBreak( int iPort, int iDurationInMilliSecs ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { APIRET rc; USHORT comError = 0; hb_vmUnlock(); rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETBREAKON, NULL, 0, NULL, &comError, sizeof( comError ), NULL ); if( rc == NO_ERROR ) { DosSleep( iDurationInMilliSecs ); rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETBREAKOFF, NULL, 0, NULL, &comError, sizeof( comError ), NULL ); if( rc == NO_ERROR ) iResult = 0; } hb_comSetOsError( pCom, rc ); hb_vmLock(); } return iResult; } /* some missing defines in bsedev.h */ #define MODE_RTS_MASK ( MODE_RTS_CONTROL | MODE_RTS_HANDSHAKE ) #define MODE_DTR_MASK ( MODE_DTR_CONTROL | MODE_RTS_HANDSHAKE ) #define MODE_FULL_DUPLEX 0x20 int hb_comFlowControl( int iPort, int *piFlow, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); APIRET rc = ERROR_INVALID_HANDLE; int iValue = 0; if( pCom ) { DCBINFO dcb; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETDCBINFO, NULL, 0, NULL, &dcb, sizeof( dcb ), NULL ); if( rc == NO_ERROR ) { if( ( dcb.fbFlowReplace & MODE_RTS_MASK ) == MODE_RTS_HANDSHAKE ) iValue |= HB_COM_FLOW_IRTSCTS; if( dcb.fbCtlHndShake & MODE_CTS_HANDSHAKE ) iValue |= HB_COM_FLOW_ORTSCTS; if( ( dcb.fbCtlHndShake & MODE_DTR_MASK ) == MODE_DTR_HANDSHAKE ) iValue |= HB_COM_FLOW_IDTRDSR; if( dcb.fbCtlHndShake & MODE_DSR_HANDSHAKE ) iValue |= HB_COM_FLOW_ODTRDSR; if( dcb.fbCtlHndShake & MODE_DCD_HANDSHAKE ) iValue |= HB_COM_FLOW_DCD; if( dcb.fbFlowReplace & MODE_AUTO_TRANSMIT ) iValue |= HB_COM_FLOW_XON; if( dcb.fbFlowReplace & MODE_AUTO_RECEIVE ) iValue |= HB_COM_FLOW_XOFF; if( iFlow >= 0 ) { if( iFlow & HB_COM_FLOW_IRTSCTS ) { dcb.fbFlowReplace &= ~MODE_RTS_MASK; dcb.fbFlowReplace |= MODE_RTS_HANDSHAKE; } else dcb.fbFlowReplace &= ~MODE_RTS_HANDSHAKE; if( iFlow & HB_COM_FLOW_ORTSCTS ) dcb.fbCtlHndShake |= MODE_CTS_HANDSHAKE; else dcb.fbCtlHndShake &= ~MODE_CTS_HANDSHAKE; if( iFlow & HB_COM_FLOW_IDTRDSR ) { dcb.fbCtlHndShake &= ~MODE_DTR_MASK; dcb.fbCtlHndShake |= MODE_DTR_HANDSHAKE; } else dcb.fbCtlHndShake &= ~MODE_DTR_HANDSHAKE; if( iFlow & HB_COM_FLOW_ODTRDSR ) dcb.fbCtlHndShake |= MODE_DSR_HANDSHAKE; else dcb.fbCtlHndShake &= ~MODE_DSR_HANDSHAKE; if( iFlow & HB_COM_FLOW_DCD ) dcb.fbCtlHndShake |= MODE_DCD_HANDSHAKE; else dcb.fbCtlHndShake &= ~MODE_DCD_HANDSHAKE; if( iFlow & HB_COM_FLOW_XON ) dcb.fbFlowReplace |= MODE_AUTO_TRANSMIT; else dcb.fbFlowReplace &= ~MODE_AUTO_TRANSMIT; if( iFlow & HB_COM_FLOW_XOFF ) dcb.fbFlowReplace |= MODE_AUTO_RECEIVE; else dcb.fbFlowReplace &= ~MODE_AUTO_RECEIVE; dcb.fbCtlHndShake &= ~MODE_DSR_SENSITIVITY; dcb.fbFlowReplace |= MODE_FULL_DUPLEX; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, sizeof( dcb ), NULL, NULL, 0, NULL ); } } hb_comSetOsError( pCom, rc ); } if( piFlow ) *piFlow = iValue; return ( rc == NO_ERROR ) ? 0 : -1; } int hb_comFlowSet( int iPort, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); APIRET rc = ERROR_INVALID_HANDLE, fNotSup = FALSE; if( pCom ) { if( iFlow & HB_COM_FL_SOFT ) { if( iFlow & HB_COM_FL_OOFF ) rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_STOPTRANSMIT, NULL, 0, NULL, NULL, 0, NULL ); else if( iFlow & HB_COM_FL_OON ) rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_STARTTRANSMIT, NULL, 0, NULL, NULL, 0, NULL ); else fNotSup = TRUE; } else fNotSup = TRUE; if( fNotSup ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); else hb_comSetOsError( pCom, rc ); } return ( rc == NO_ERROR ) ? 0 : -1; } int hb_comFlowChars( int iPort, int iXONchar, int iXOFFchar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); APIRET rc = ERROR_INVALID_HANDLE; if( pCom ) { rc = NO_ERROR; if( iXONchar >= 0 || iXOFFchar >= 0 ) { DCBINFO dcb; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETDCBINFO, NULL, 0, NULL, &dcb, sizeof( dcb ), NULL ); if( rc == NO_ERROR ) { if( iXONchar >= 0 ) dcb.bXONChar = ( BYTE ) iXONchar; if( iXOFFchar >= 0 ) dcb.bXOFFChar = ( BYTE ) iXOFFchar; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, sizeof( dcb ), NULL, NULL, 0, NULL ); } } hb_comSetOsError( pCom, rc ); } return ( rc == NO_ERROR ) ? 0 : -1; } int hb_comDiscardChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { /* NOTE: there is no support for setting user defined character * discarding input buffer */ HB_SYMBOL_UNUSED( iChar ); hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); } return iResult; } int hb_comErrorChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); APIRET rc = ERROR_INVALID_HANDLE; if( pCom ) { DCBINFO dcb; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETDCBINFO, NULL, 0, NULL, &dcb, sizeof( dcb ), NULL ); if( rc == NO_ERROR ) { if( iChar >= 0 ) { dcb.fbFlowReplace |= MODE_ERROR_CHAR; dcb.bErrorReplacementChar = ( BYTE ) iChar; } else dcb.fbFlowReplace &= ~MODE_ERROR_CHAR; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, sizeof( dcb ), NULL, NULL, 0, NULL ); } hb_comSetOsError( pCom, rc ); } return ( rc == NO_ERROR ) ? 0 : -1; } int hb_comOutputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); APIRET rc = ERROR_INVALID_HANDLE; int iValue = 0; if( pCom ) { UCHAR comStatus = 0; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETCOMMSTATUS, NULL, 0, NULL, &comStatus, sizeof( comStatus ), NULL ); if( rc == NO_ERROR ) { /* NOTE: HB_COM_TX_RFLUSH is unsupported */ if( comStatus & TX_WAITING_FOR_CTS ) iValue |= HB_COM_TX_CTS; if( comStatus & TX_WAITING_FOR_DSR ) iValue |= HB_COM_TX_DSR; if( comStatus & TX_WAITING_FOR_DCD ) iValue |= HB_COM_TX_DCD; if( comStatus & TX_WAITING_FOR_XON ) iValue |= HB_COM_TX_XOFF; if( hb_comOutputCount( iPort ) == 0 ) iValue |= HB_COM_TX_EMPTY; } hb_comSetOsError( pCom, rc ); } return ( rc == NO_ERROR ) ? iValue : -1; } int hb_comInputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { /* TODO: checking HB_COM_RX_* input flow states is unsupported */ hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); } return iResult; } long hb_comSend( int iPort, const void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lSent = -1; if( pCom ) { APIRET rc = NO_ERROR; hb_vmUnlock(); if( timeout < 0 ) timeout = 0; else if( timeout > 0 ) { timeout = ( timeout / 10 ) + 1; if( timeout > USHRT_MAX ) timeout = USHRT_MAX; } if( pCom->wrtimeout != ( USHORT ) timeout ) { DCBINFO dcb; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETDCBINFO, NULL, 0, NULL, &dcb, sizeof( dcb ), NULL ); if( rc == NO_ERROR ) { dcb.fbTimeout &= ~MODE_NO_WRITE_TIMEOUT; /* dcb.usWriteTimeout is 0 based (0 = 0.01 sec.) and this is * the minimal write timeout what seems to be reasonable. */ if( timeout ) dcb.usWriteTimeout = ( USHORT ) ( timeout - 1 ); else dcb.usWriteTimeout = 0; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, sizeof( dcb ), NULL, NULL, 0, NULL ); if( rc == NO_ERROR ) pCom->wrtimeout = ( USHORT ) timeout; } } if( rc == NO_ERROR ) { ULONG ulWritten = 0; rc = DosWrite( pCom->hFile, ( void * ) data, len, &ulWritten ); if( rc == NO_ERROR ) lSent = ( long ) ulWritten; } if( lSent == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lSent = -1; } else hb_comSetOsError( pCom, rc ); hb_vmLock(); } return lSent; } long hb_comRecv( int iPort, void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lReceived = -1; if( pCom ) { APIRET rc = NO_ERROR; hb_vmUnlock(); if( timeout < 0 ) timeout = 0; else if( timeout > 0 ) { timeout = ( timeout / 10 ) + 1; if( timeout > USHRT_MAX ) timeout = USHRT_MAX; } if( pCom->rdtimeout != ( USHORT ) timeout ) { DCBINFO dcb; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETDCBINFO, NULL, 0, NULL, &dcb, sizeof( dcb ), NULL ); if( rc == NO_ERROR ) { dcb.fbTimeout &= ~( MODE_READ_TIMEOUT | MODE_NOWAIT_READ_TIMEOUT ); if( timeout ) { dcb.fbTimeout |= MODE_READ_TIMEOUT; dcb.usReadTimeout = ( USHORT ) ( timeout - 1 ); } else { dcb.fbTimeout |= MODE_NOWAIT_READ_TIMEOUT; dcb.usReadTimeout = 0; } rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, sizeof( dcb ), NULL, NULL, 0, NULL ); if( rc == NO_ERROR ) pCom->rdtimeout = ( USHORT ) timeout; } } if( rc == NO_ERROR ) { ULONG ulRead = 0; rc = DosRead( pCom->hFile, data, len, &ulRead ); if( rc == NO_ERROR ) lReceived = ( long ) ulRead; } if( lReceived == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lReceived = -1; } else hb_comSetOsError( pCom, rc ); hb_vmLock(); } return lReceived; } int hb_comInit( int iPort, int iBaud, int iParity, int iSize, int iStop ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); APIRET rc = ERROR_INVALID_HANDLE; if( pCom ) { LINECONTROL lctrl; rc = NO_ERROR; switch( iSize ) { case 0: iSize = 8; case 8: case 7: case 6: case 5: lctrl.bDataBits = iSize; break; default: rc = ERROR_INVALID_PARAMETER; } switch( iParity ) { case 0: case 'N': case 'n': lctrl.bParity = 0; break; case 'O': case 'o': lctrl.bParity = 1; break; case 'E': case 'e': lctrl.bParity = 2; break; case 'M': case 'm': lctrl.bParity = 3; break; case 'S': case 's': lctrl.bParity = 4; break; default: rc = ERROR_INVALID_PARAMETER; } switch( iStop ) { case 0: case 1: lctrl.bStopBits = 0; break; case 2: lctrl.bStopBits = 2; break; default: rc = ERROR_INVALID_PARAMETER; } lctrl.fTransBreak = 0; if( iBaud < 0 || iBaud > USHRT_MAX ) rc = ERROR_INVALID_PARAMETER; if( rc == NO_ERROR ) { if( iBaud ) { USHORT baud = ( USHORT ) iBaud; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETBAUDRATE, &baud, sizeof( baud ), NULL, NULL, 0L, NULL ); } } if( rc == NO_ERROR ) rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETLINECTRL, &lctrl, sizeof( lctrl ), NULL, NULL, 0L, NULL ); if( rc == NO_ERROR ) { DCBINFO dcb; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_GETDCBINFO, NULL, 0, NULL, &dcb, sizeof( dcb ), NULL ); if( rc == NO_ERROR ) { dcb.usWriteTimeout = 0; dcb.usReadTimeout = 0; dcb.fbCtlHndShake = 0x00; dcb.fbFlowReplace = MODE_FULL_DUPLEX; dcb.fbTimeout &= ~MODE_NO_WRITE_TIMEOUT; dcb.fbTimeout |= MODE_NOWAIT_READ_TIMEOUT; rc = DosDevIOCtl( pCom->hFile, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, sizeof( dcb ), NULL, NULL, 0, NULL ); pCom->rdtimeout = pCom->wrtimeout = 0; } } hb_comSetOsError( pCom, rc ); } return ( rc == NO_ERROR ) ? 0 : -1; } int hb_comClose( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); APIRET rc = ERROR_INVALID_HANDLE; if( pCom ) { hb_vmUnlock(); /* DosResetBuffer( pCom->hFile ); */ rc = DosClose( pCom->hFile ); pCom->hFile = 0; pCom->status &= ~HB_COM_OPEN; hb_comSetOsError( pCom, rc ); hb_vmLock(); } return ( rc == NO_ERROR ) ? 0 : -1; } int hb_comOpen( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ENABLED ); APIRET rc = ERROR_INVALID_HANDLE; if( pCom ) { if( pCom->status & HB_COM_OPEN ) { hb_comSetComError( pCom, HB_COM_ERR_ALREADYOPEN ); } else { char buffer[ HB_COM_DEV_NAME_MAX ]; const char * pszName = hb_comGetName( pCom, buffer, sizeof( buffer ) ); ULONG ulAction = 0; HB_FHANDLE hFile; hb_vmUnlock(); rc = hb_fsOS2DosOpen( pszName, &hFile, &ulAction, 0L, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE ); if( rc == NO_ERROR ) { pCom->hFile = ( HFILE ) hFile; pCom->status |= HB_COM_OPEN; } hb_comSetOsError( pCom, rc ); hb_vmLock(); } } return ( rc == NO_ERROR ) ? 0 : -1; } /* end of HB_OS_OS2 */ #elif defined( HB_HAS_DOSSRL ) static void hb_comSetOsError( PHB_COM pCom, int iError ) { pCom->oserr = iError; switch( iError ) { case SER_SUCCESS: /* Function completed successfully */ pCom->error = 0; break; case SER_ERR_NOT_OPEN: /* The specified COM port is not opened */ pCom->error = HB_COM_ERR_CLOSED; break; case SER_ERR_ALREADY_OPEN: /* The specified COM port is already opened */ pCom->error = HB_COM_ERR_ALREADYOPEN; break; case SER_ERR_NO_UART: /* Could not find a UART for this COM port */ pCom->error = HB_COM_ERR_NOCOM; break; case SER_ERR_INVALID_COMPORT: /* User specified an invalid COM port */ pCom->error = HB_COM_ERR_WRONGPORT; break; case SER_ERR_INVALID_BPS: /* User specified an invalid BPS rate */ case SER_ERR_INVALID_DATA_BITS: /* User specified an invalid number of data bits */ case SER_ERR_INVALID_PARITY: /* User specified an invalid parity type */ case SER_ERR_INVALID_STOP_BITS: /* User specified an invalid number of stop bits */ case SER_ERR_INVALID_HANDSHAKING: /* User specified an invalid handshaking type */ case SER_ERR_INVALID_FIFO_THRESHOLD:/* User specified an invalid fifo threshold value */ case SER_ERR_NULL_PTR: /* User specified a buffer address that was NULL */ pCom->error = HB_COM_ERR_PARAMVALUE; break; case SER_ERR_INVALID_BASE: /* User specified an invalid base address */ case SER_ERR_INVALID_IRQ: /* User specified an invalid IRQ number */ pCom->error = HB_COM_ERR_PARAMVALUE; break; case SER_ERR_IRQ_NOT_FOUND: /* Could not find an IRQ for the specified COM port */ case SER_ERR_LOCK_MEM: /* Could not lock memory in DPMI mode */ case SER_ERR_UNKNOWN: /* An unknown error occurred */ default: pCom->error = iError < 0 ? HB_COM_ERR_OTHER : 0; } } int hb_comInputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = -1; if( pCom ) { iCount = serial_get_rx_buffered( iPort - 1 ); hb_comSetOsError( pCom, iCount ); if( iCount < 0 ) iCount = -1; } return iCount; } int hb_comOutputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = -1; if( pCom ) { iCount = serial_get_tx_buffered( iPort - 1 ); hb_comSetOsError( pCom, iCount ); if( iCount < 0 ) iCount = -1; } return iCount; } int hb_comFlush( int iPort, int iType ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { switch( iType ) { case HB_COM_IFLUSH: case HB_COM_IOFLUSH: iResult = serial_clear_rx_buffer( iPort - 1 ); if( iType == HB_COM_IFLUSH || iResult != SER_SUCCESS ) break; break; case HB_COM_OFLUSH: iResult = serial_clear_tx_buffer( iPort - 1 ); break; default: hb_comSetComError( pCom, HB_COM_ERR_PARAMVALUE ); return -1; } hb_comSetOsError( pCom, iResult ); if( iResult < 0 ) iResult = -1; } return iResult; } int hb_comMCR( int iPort, int * piValue, int iClr, int iSet ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; int iValue = 0; if( pCom ) { iResult = serial_get_mcr( iPort - 1 ); if( iResult >= 0 ) { int iNewVal = ( iResult & ~iClr ) | iSet; iValue = iResult; iResult = iValue == iNewVal ? 0 : serial_set_mcr( iPort - 1, iNewVal ); } hb_comSetOsError( pCom, iResult ); if( iResult < 0 ) iResult = -1; } if( piValue ) *piValue = iValue; return iResult; } int hb_comMSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; int iValue = 0; if( pCom ) { iValue = serial_get_msr( iPort - 1 ); hb_comSetOsError( pCom, iValue ); if( iValue < 0 ) { iResult = -1; iValue = 0; } } if( piValue ) *piValue = iValue; return iResult; } int hb_comLSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1, iValue = 0; if( pCom ) { iValue = serial_get_lsr( iPort - 1 ); hb_comSetOsError( pCom, iValue ); if( iValue < 0 ) { iResult = -1; iValue = 0; } } if( piValue ) *piValue = iValue; return iResult; } int hb_comSendBreak( int iPort, int iDurationInMilliSecs ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iDurationInMilliSecs ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comFlowControl( int iPort, int *piFlow, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1, iValue = 0; if( pCom ) { iResult = serial_get_handshaking( iPort - 1 ); if( iResult >= 0 ) { switch( iResult ) { case SER_HANDSHAKING_XONXOFF: iValue |= HB_COM_FLOW_XOFF | HB_COM_FLOW_XOFF; break; case SER_HANDSHAKING_RTSCTS: iValue |= HB_COM_FLOW_IRTSCTS | HB_COM_FLOW_ORTSCTS; break; case SER_HANDSHAKING_DTRDSR: iValue |= HB_COM_FLOW_IDTRDSR | HB_COM_FLOW_ODTRDSR; break; case SER_HANDSHAKING_NONE: break; } if( iFlow >= 0 ) { int iFlowVal = 0; if( iFlow & ( HB_COM_FLOW_IRTSCTS | HB_COM_FLOW_ORTSCTS ) ) iFlowVal = SER_HANDSHAKING_RTSCTS; else if( iFlow & ( HB_COM_FLOW_IDTRDSR | HB_COM_FLOW_ODTRDSR ) ) iFlowVal = SER_HANDSHAKING_DTRDSR; else if( iFlow & ( HB_COM_FLOW_XON | HB_COM_FLOW_XOFF ) ) iFlowVal = SER_HANDSHAKING_XONXOFF; if( iFlowVal != iResult ) iResult = serial_set_handshaking( iPort - 1, iFlowVal ); } } hb_comSetOsError( pCom, iResult ); if( iResult < 0 ) iResult = -1; } if( piFlow ) *piFlow = iValue; return iResult; } int hb_comFlowSet( int iPort, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iFlow ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comFlowChars( int iPort, int iXONchar, int iXOFFchar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; HB_SYMBOL_UNUSED( iXONchar ); HB_SYMBOL_UNUSED( iXOFFchar ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return iResult; } int hb_comDiscardChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iChar ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comErrorChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iChar ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comOutputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { iResult = serial_get_tx_buffered( iPort - 1 ); hb_comSetOsError( pCom, iResult ); if( iResult < 0 ) iResult = -1; else if( iResult == 0 ) iResult = HB_COM_TX_EMPTY; else iResult = 0; } return iResult; } int hb_comInputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return iResult; } long hb_comSend( int iPort, const void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lSent = -1; if( pCom ) { const char * buffer = ( const char * ) data; HB_MAXUINT timer = hb_timerInit( timeout ); hb_comSetOsError( pCom, SER_SUCCESS ); lSent = 0; hb_vmUnlock(); while( len > 0 ) { int iSent; iSent = serial_write_buffered( iPort - 1, buffer, len ); if( iSent < 0 ) { hb_comSetOsError( pCom, iSent ); if( lSent == 0 ) lSent = -1; break; } lSent += iSent; buffer += iSent; len -= iSent; if( len > 0 ) { if( ( timeout = hb_timerTest( timeout, &timer ) ) == 0 ) { if( lSent == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lSent = -1; } break; } hb_releaseCPU(); } } hb_vmLock(); } return lSent; } long hb_comRecv( int iPort, void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lReceived = -1; if( pCom ) { char * buffer = ( char * ) data; HB_MAXUINT timer = hb_timerInit( timeout ); hb_comSetOsError( pCom, SER_SUCCESS ); lReceived = 0; hb_vmUnlock(); while( len > 0 ) { int iRecv = serial_read( iPort - 1, buffer, len ); if( iRecv < 0 ) { hb_comSetOsError( pCom, iRecv ); if( lReceived == 0 ) lReceived = -1; break; } lReceived += iRecv; buffer += iRecv; len -= iRecv; if( lReceived > 0 || ( timeout = hb_timerTest( timeout, &timer ) ) == 0 ) { if( lReceived == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lReceived = -1; } break; } hb_releaseCPU(); } hb_vmLock(); } return lReceived; } static int s_comChkPortParam( int *piBaud, int *piParity, int *piSize, int *piStop ) { int iResult = 0; if( *piBaud == 0 ) *piBaud = 9600; *piParity = HB_TOLOWER( *piParity ); switch( *piParity ) { case 0: *piParity = 'n'; case 'n': case 'e': case 'o': case 's': case 'm': break; default: iResult = -1; } switch( *piSize ) { case 0: *piSize = 8; case 8: case 7: case 6: case 5: break; default: iResult = -1; } switch( *piStop ) { case 0: *piStop = 1; case 1: case 2: break; default: iResult = -1; } return iResult; } int hb_comInit( int iPort, int iBaud, int iParity, int iSize, int iStop ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { iResult = s_comChkPortParam( &iBaud, &iParity, &iSize, &iStop ); if( iResult == 0 ) { iResult = serial_set_bps( iPort - 1, iBaud ); if( iResult == SER_SUCCESS ) iResult = serial_set_data( iPort - 1, iSize ); if( iResult == SER_SUCCESS ) iResult = serial_set_parity( iPort - 1, iParity ); if( iResult == SER_SUCCESS ) iResult = serial_set_stop( iPort - 1, iStop ); hb_comSetOsError( pCom, iResult ); if( iResult < 0 ) iResult = -1; } else hb_comSetComError( pCom, HB_COM_ERR_PARAMVALUE ); } return iResult; } int hb_comClose( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { hb_vmUnlock(); iResult = serial_close( iPort - 1 ); pCom->status &= ~HB_COM_OPEN; hb_comSetOsError( pCom, iResult ); if( iResult < 0 ) iResult = -1; hb_vmLock(); } return iResult; } int hb_comOpen( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ENABLED ); int iResult = -1; if( pCom ) { if( pCom->status & HB_COM_OPEN ) { hb_comSetComError( pCom, HB_COM_ERR_ALREADYOPEN ); } else { int iBaud, iParity, iSize, iStop, iFlowControl; hb_vmUnlock(); iBaud = iParity = iSize = iStop = 0; iFlowControl = SER_HANDSHAKING_NONE; s_comChkPortParam( &iBaud, &iParity, &iSize, &iStop ); iResult = serial_open( iPort - 1, iBaud, iSize, iParity, iStop, iFlowControl ); if( iResult == 0 ) { pCom->status |= HB_COM_OPEN; hb_comSetOsError( pCom, 0 ); } else { serial_close( iPort - 1 ); hb_comSetOsError( pCom, iResult ); iResult = -1; } hb_vmLock(); } } return iResult; } /* end of HB_HAS_DOSSRL */ #elif defined( HB_HAS_PMCOM ) static void hb_comSetOsError( PHB_COM pCom, int iError ) { pCom->oserr = iError; switch( iError ) { case COMERR_NOCHIP: pCom->error = HB_COM_ERR_WRONGPORT; break; case COMERR_RXOVERFLOW: case COMERR_NOMEMORY: case COMERR_GENERAL: default: pCom->error = HB_COM_ERR_OTHER; } } int hb_comInputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = -1; if( pCom ) iCount = COMTXBufferUsed( iPort - 1 ); return iCount; } int hb_comOutputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iCount = -1; if( pCom ) iCount = COMRXBufferUsed( iPort - 1 ); return iCount; } int hb_comFlush( int iPort, int iType ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { iResult = 0; hb_comSetOsError( pCom, 0 ); switch( iType ) { case HB_COM_IFLUSH: case HB_COM_IOFLUSH: COMClearRXBuffer( iPort - 1 ); if( iType == HB_COM_IFLUSH ) break; break; case HB_COM_OFLUSH: COMClearTXBuffer( iPort - 1 ); break; default: iResult = -1; hb_comSetComError( pCom, HB_COM_ERR_PARAMVALUE ); break; } } return iResult; } int hb_comMCR( int iPort, int * piValue, int iClr, int iSet ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; int iValue = 0; if( pCom ) { /* MCR_OUT1, MCR_OUT2, MCR_LOOP and reading current state * is unsupported */ if( iSet & HB_COM_MCR_DTR ) COMSetDtr( iPort - 1, 1 ); else if( iClr & HB_COM_MCR_DTR ) COMSetDtr( iPort - 1, 0 ); if( iSet & HB_COM_MCR_RTS ) COMSetRts( iPort - 1, 1 ); else if( iClr & HB_COM_MCR_RTS ) COMSetRts( iPort - 1, 0 ); iResult = 0; } if( piValue ) *piValue = iValue; return iResult; } int hb_comMSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; int iValue = 0; if( pCom ) { int iMSR = COMGetModemStatus( iPort - 1 ); if( iMSR & DELTA_CTS ) iValue |= HB_COM_MSR_DELTA_CTS; if( iMSR & DELTA_DSR ) iValue |= HB_COM_MSR_DELTA_DSR; if( iMSR & DELTA_RI ) iValue |= HB_COM_MSR_TERI; if( iMSR & DELTA_CD ) iValue |= HB_COM_MSR_DELTA_DCD; if( iMSR & CTS_LINE ) iValue |= HB_COM_MSR_CTS; if( iMSR & DSR_LINE ) iValue |= HB_COM_MSR_DSR; if( iMSR & RI_LINE ) iValue |= HB_COM_MSR_RI; if( iMSR & CD_LINE ) iValue |= HB_COM_MSR_DCD; iResult = 0; } if( piValue ) *piValue = iValue; return iResult; } int hb_comLSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1, iValue = 0; if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); if( piValue ) *piValue = iValue; return iResult; } int hb_comSendBreak( int iPort, int iDurationInMilliSecs ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iDurationInMilliSecs ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comFlowControl( int iPort, int *piFlow, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1, iValue = 0; if( pCom ) { int iFlowVal = COMGetFlowControl( iPort - 1 ); if( iFlowVal & FLOW_RTS ) iValue |= HB_COM_FLOW_IRTSCTS; if( iFlowVal & FLOW_CTS ) iValue |= HB_COM_FLOW_ORTSCTS; if( iFlowVal & FLOW_DTR ) iValue |= HB_COM_FLOW_IDTRDSR; if( iFlowVal & FLOW_DSR ) iValue |= HB_COM_FLOW_ODTRDSR; if( iFlowVal & FLOW_DCD ) iValue |= HB_COM_FLOW_DCD; if( iFlowVal & FLOW_XOFF ) iValue |= HB_COM_FLOW_XOFF; if( iFlowVal & FLOW_XON ) iValue |= HB_COM_FLOW_XON; if( iFlow >= 0 ) { iFlowVal = 0; if( iFlow & HB_COM_FLOW_IRTSCTS ) iFlowVal |= FLOW_RTS; if( iFlow & HB_COM_FLOW_ORTSCTS ) iFlowVal |= FLOW_CTS; if( iFlow & HB_COM_FLOW_IDTRDSR ) iFlowVal |= FLOW_DTR; if( iFlow & HB_COM_FLOW_ODTRDSR ) iFlowVal |= FLOW_DSR; if( iFlow & HB_COM_FLOW_DCD ) iFlowVal |= FLOW_DCD; if( iFlow & HB_COM_FLOW_XOFF ) iFlowVal |= FLOW_XOFF; if( iFlow & HB_COM_FLOW_XON ) iFlowVal |= FLOW_XON; COMSetFlowControl( iPort - 1, iFlowVal ); } iResult = 0; } if( piFlow ) *piFlow = iValue; return iResult; } int hb_comFlowSet( int iPort, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iFlow ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comFlowChars( int iPort, int iXONchar, int iXOFFchar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { COMSetFlowChars( iPort - 1, iXONchar, iXOFFchar ); iResult = 0; } return iResult; } int hb_comDiscardChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iChar ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comErrorChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iChar ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comOutputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { iResult = COMRXBufferUsed( iPort - 1 ); if( iResult == 0 ) iResult = HB_COM_TX_EMPTY; else if( iResult > 0 ) iResult = 0; } return iResult; } int hb_comInputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return iResult; } long hb_comSend( int iPort, const void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lSent = -1; if( pCom ) { const char * buffer = ( const char * ) data; HB_MAXUINT timer = hb_timerInit( timeout ); hb_comSetOsError( pCom, 0 ); lSent = 0; hb_vmUnlock(); while( len > 0 ) { int iSent, iErr; iErr = COMWriteBuffer( iPort - 1, buffer, NULL, len, &iSent ); lSent += iSent; if( iErr == COMERR_TXOVERFLOW ) { buffer += iSent; len -= iSent; if( ( timeout = hb_timerTest( timeout, &timer ) ) == 0 ) { if( lSent == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lSent = -1; } break; } hb_releaseCPU(); } else break; } hb_vmLock(); } return lSent; } long hb_comRecv( int iPort, void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); long lReceived = -1; if( pCom ) { char * buffer = ( char * ) data; HB_MAXUINT timer = hb_timerInit( timeout ); hb_comSetOsError( pCom, 0 ); lReceived = 0; hb_vmUnlock(); while( len > 0 ) { int iErr = COMReadChar( iPort - 1, buffer, NULL ); if( iErr == 0 ) { ++buffer; --len; ++lReceived; } else if( iErr == COM_BUFEMPTY ) { if( lReceived > 0 || ( timeout = hb_timerTest( timeout, &timer ) ) == 0 ) { if( lReceived == 0 ) { hb_comSetComError( pCom, HB_COM_ERR_TIMEOUT ); lReceived = -1; } break; } hb_releaseCPU(); } else { hb_comSetOsError( pCom, iErr ); break; } } hb_vmLock(); } return lReceived; } static int s_comChkPortParam( int *piBaud, int *piParity, int *piSize, int *piStop ) { int iResult = 0; if( *piBaud == 0 ) *piBaud = 9600; *piParity = HB_TOUPPER( *piParity ); switch( *piParity ) { case 0: *piParity = 'N'; case 'N': case 'E': case 'O': case 'S': case 'M': break; default: iResult = -1; } switch( *piSize ) { case 0: *piSize = 8; case 8: case 7: case 6: case 5: break; default: iResult = -1; } switch( *piStop ) { case 0: *piStop = 1; case 1: case 2: break; default: iResult = -1; } return iResult; } int hb_comInit( int iPort, int iBaud, int iParity, int iSize, int iStop ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { iResult = s_comChkPortParam( &iBaud, &iParity, &iSize, &iStop ); if( iResult == 0 ) { COMSetTransmitParameters( iPort - 1, iBaud, iSize, iParity, iStop ); hb_comSetOsError( pCom, 0 ); } else hb_comSetComError( pCom, HB_COM_ERR_PARAMVALUE ); } return iResult; } int hb_comClose( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); int iResult = -1; if( pCom ) { hb_vmUnlock(); COMPortClose( iPort - 1 ); pCom->status &= ~HB_COM_OPEN; hb_comSetOsError( pCom, 0 ); iResult = 0; hb_vmLock(); } return iResult; } int hb_comOpen( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ENABLED ); int iResult = -1; if( pCom ) { if( pCom->status & HB_COM_OPEN ) { hb_comSetComError( pCom, HB_COM_ERR_ALREADYOPEN ); } else { int iBaud, iParity, iSize, iStop, iFlowControl; hb_vmUnlock(); iBaud = iParity = iSize = iStop = 0; iFlowControl = 0; s_comChkPortParam( &iBaud, &iParity, &iSize, &iStop ); iResult = COMPortOpen( iPort - 1, iBaud, iSize, iParity, iStop, iFlowControl, NULL ); if( iResult == 0 ) { pCom->status |= HB_COM_OPEN; hb_comSetOsError( pCom, 0 ); } else { hb_comSetOsError( pCom, iResult ); iResult = -1; } hb_vmLock(); } } return iResult; } /* end of HB_HAS_PMCOM */ #else int hb_comInputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comOutputCount( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comFlush( int iPort, int iType ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iType ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comMCR( int iPort, int * piValue, int iClr, int iSet ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( piValue ); HB_SYMBOL_UNUSED( iClr ); HB_SYMBOL_UNUSED( iSet ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comMSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( piValue ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comLSR( int iPort, int * piValue ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( piValue ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comSendBreak( int iPort, int iDurationInMilliSecs ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iDurationInMilliSecs ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comFlowControl( int iPort, int *piFlow, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( piFlow ); HB_SYMBOL_UNUSED( iFlow ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comFlowSet( int iPort, int iFlow ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iFlow ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comFlowChars( int iPort, int iXONchar, int iXOFFchar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iXONchar ); HB_SYMBOL_UNUSED( iXOFFchar ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comDiscardChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iChar ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comErrorChar( int iPort, int iChar ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iChar ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comOutputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comInputState( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } long hb_comSend( int iPort, const void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( data ); HB_SYMBOL_UNUSED( len ); HB_SYMBOL_UNUSED( timeout ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } long hb_comRecv( int iPort, void * data, long len, HB_MAXINT timeout ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( data ); HB_SYMBOL_UNUSED( len ); HB_SYMBOL_UNUSED( timeout ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comInit( int iPort, int iBaud, int iParity, int iSize, int iStop ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); HB_SYMBOL_UNUSED( iBaud ); HB_SYMBOL_UNUSED( iParity ); HB_SYMBOL_UNUSED( iSize ); HB_SYMBOL_UNUSED( iStop ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comClose( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } int hb_comOpen( int iPort ) { PHB_COM pCom = hb_comGetPort( iPort, HB_COM_ENABLED ); int iTODO_serial_port_support; if( pCom ) hb_comSetComError( pCom, HB_COM_ERR_NOSUPPORT ); return -1; } #endif static int s_iComInit = 0; static void hb_com_exit( void* cargo ) { HB_SYMBOL_UNUSED( cargo ); if( s_iComInit ) { hb_comCloseAll(); s_iComInit = 0; } } static void hb_com_init( void* cargo ) { HB_SYMBOL_UNUSED( cargo ); if( ! s_iComInit ) { int iPort; for( iPort = 0; iPort < HB_COM_PORT_MAX; ++iPort ) { s_comList[ iPort ].port = iPort + 1; s_comList[ iPort ].status = HB_COM_ENABLED; } hb_vmAtQuit( hb_com_exit, NULL ); s_iComInit = 1; } } HB_CALL_ON_STARTUP_BEGIN( _hb_com_init_ ) hb_vmAtInit( hb_com_init, NULL ); HB_CALL_ON_STARTUP_END( _hb_com_init_ ) #if defined( HB_PRAGMA_STARTUP ) #pragma startup _hb_com_init_ #elif defined( HB_DATASEG_STARTUP ) #define HB_DATASEG_BODY HB_DATASEG_FUNC( _hb_com_init_ ) #include "hbiniseg.h" #endif