* src/common/hbstr.c
* src/rtl/hbcom.c
* src/rtl/hbproces.c
* pacified few warnings - thanks to Viktor
* contrib/sddfb/core.c
! fixed code which extracted float number from uninitialized memory.
On some systems it could even cause GPF or other (ie. FPE) exception.
4559 lines
110 KiB
C
4559 lines
110 KiB
C
/*
|
|
* Serial communication functions
|
|
*
|
|
* Copyright 2010 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
|
|
*
|
|
* 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.txt. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site https://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.
|
|
*
|
|
*/
|
|
|
|
#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 <termios.h>
|
|
# include <fcntl.h>
|
|
# include <sys/ioctl.h>
|
|
# include <unistd.h>
|
|
# include <errno.h>
|
|
# if defined( HB_OS_UNIX )
|
|
# include <sys/time.h>
|
|
# include <sys/types.h>
|
|
# if 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
|
|
# include <poll.h>
|
|
# endif
|
|
# endif
|
|
# if defined( HB_OS_HPUX )
|
|
# include <sys/modem.h>
|
|
# endif
|
|
#elif defined( HB_HAS_SIOLIB )
|
|
# include <sioLib.h>
|
|
#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 <windows.h>
|
|
# include "hbwinuni.h"
|
|
#elif defined( HB_OS_OS2 )
|
|
# define INCL_BASE
|
|
# define INCL_DOS
|
|
# define INCL_DOSERROR
|
|
# define INCL_DOSDEVICES
|
|
# define INCL_DOSDEVIOCTL
|
|
# include <os2.h>
|
|
#elif defined( HB_OS_LINUX ) && defined( __WATCOMC__ ) && ( __WATCOMC__ <= 1290 )
|
|
# include <unistd.h>
|
|
#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() ( errno == EINTR )
|
|
#define HB_COM_IS_EBADF() ( errno == 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 = timeout <= 0 ? 0 : hb_dateMilliSeconds();
|
|
struct pollfd fds;
|
|
|
|
fds.fd = pCom->fd;
|
|
fds.events = POLLIN;
|
|
fds.revents = 0;
|
|
|
|
for( ;; )
|
|
{
|
|
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;
|
|
}
|
|
if( ( ( iResult == 0 && ( timeout < 0 || timeout > 1000 ) ) ||
|
|
( iResult == -1 && timeout != 0 && HB_COM_IS_EINTR() ) ) &&
|
|
hb_vmRequestQuery() == 0 )
|
|
{
|
|
if( timeout < 0 )
|
|
continue;
|
|
else
|
|
{
|
|
HB_MAXUINT timecurr = hb_dateMilliSeconds();
|
|
if( timecurr > timer )
|
|
{
|
|
timeout -= timecurr - timer;
|
|
if( timeout > 0 )
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
struct timeval tv;
|
|
fd_set rfds;
|
|
|
|
# if ! defined( HB_HAS_SELECT_TIMER )
|
|
HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds();
|
|
# else
|
|
tv.tv_sec = ( long ) ( timeout / 1000 );
|
|
tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000;
|
|
# endif
|
|
|
|
for( ;; )
|
|
{
|
|
FD_ZERO( &rfds );
|
|
FD_SET( pCom->fd, &rfds );
|
|
|
|
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
|
|
|
|
iResult = select( ( int ) ( pCom->fd + 1 ), &rfds, NULL, NULL, &tv );
|
|
if( iResult > 0 && ! FD_ISSET( pCom->fd, &rfds ) )
|
|
iResult = 0;
|
|
hb_comSetOsError( pCom, iResult == -1 );
|
|
if( iResult == 0 && timeout < 0 && hb_vmRequestQuery() == 0 )
|
|
continue;
|
|
if( iResult != -1 || timeout == 0 || ! HB_COM_IS_EINTR() ||
|
|
hb_vmRequestQuery() != 0 )
|
|
break;
|
|
# if ! defined( HB_HAS_SELECT_TIMER )
|
|
else if( timeout > 0 )
|
|
{
|
|
HB_MAXUINT timecurr = hb_dateMilliSeconds();
|
|
if( timecurr > timer )
|
|
{
|
|
if( ( timeout -= timecurr - timer ) <= 0 )
|
|
break;
|
|
timer = timecurr;
|
|
}
|
|
}
|
|
# 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 = timeout <= 0 ? 0 : hb_dateMilliSeconds();
|
|
struct pollfd fds;
|
|
|
|
fds.fd = pCom->fd;
|
|
fds.events = POLLOUT;
|
|
fds.revents = 0;
|
|
|
|
for( ;; )
|
|
{
|
|
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;
|
|
}
|
|
if( ( ( iResult == 0 && ( timeout < 0 || timeout > 1000 ) ) ||
|
|
( iResult == -1 && timeout != 0 && HB_COM_IS_EINTR() ) ) &&
|
|
hb_vmRequestQuery() == 0 )
|
|
{
|
|
if( timeout < 0 )
|
|
continue;
|
|
else
|
|
{
|
|
HB_MAXUINT timecurr = hb_dateMilliSeconds();
|
|
if( timecurr > timer )
|
|
{
|
|
timeout -= timecurr - timer;
|
|
if( timeout > 0 )
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
struct timeval tv;
|
|
fd_set wfds;
|
|
|
|
# if ! defined( HB_HAS_SELECT_TIMER )
|
|
HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds();
|
|
# else
|
|
tv.tv_sec = ( long ) ( timeout / 1000 );
|
|
tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000;
|
|
# endif
|
|
|
|
for( ;; )
|
|
{
|
|
FD_ZERO( &wfds );
|
|
FD_SET( pCom->fd, &wfds );
|
|
|
|
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
|
|
|
|
iResult = select( ( int ) ( pCom->fd + 1 ), NULL, &wfds, NULL, &tv );
|
|
if( iResult > 0 && FD_ISSET( pCom->fd, &wfds ) )
|
|
iResult = 0;
|
|
hb_comSetOsError( pCom, iResult == -1 );
|
|
if( iResult == 0 && timeout < 0 && hb_vmRequestQuery() == 0 )
|
|
continue;
|
|
if( iResult != -1 || timeout == 0 || ! HB_COM_IS_EINTR() ||
|
|
hb_vmRequestQuery() != 0 )
|
|
break;
|
|
# if ! defined( HB_HAS_SELECT_TIMER )
|
|
else if( timeout > 0 )
|
|
{
|
|
HB_MAXUINT timecurr = hb_dateMilliSeconds();
|
|
if( timecurr > timer )
|
|
{
|
|
if( ( timeout -= timecurr - timer ) <= 0 )
|
|
break;
|
|
timer = timecurr;
|
|
}
|
|
}
|
|
# endif
|
|
break;
|
|
}
|
|
#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 accupied 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 defintions 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() && 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: implent 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() && 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
|
|
Ubuntu) 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() && hb_vmRequestQuery() == 0 );
|
|
|
|
if( iResult != -1 || HB_COM_IS_EBADF() )
|
|
{
|
|
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 occured */
|
|
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 = timeout <= 0 ? 0 : ( hb_dateMilliSeconds() + 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( timer == 0 || timer < hb_dateMilliSeconds() )
|
|
{
|
|
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 = timeout <= 0 ? 0 : ( hb_dateMilliSeconds() + 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 || timer == 0 || timer < hb_dateMilliSeconds() )
|
|
{
|
|
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 = timeout <= 0 ? 0 : ( hb_dateMilliSeconds() + 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( timer == 0 || timer < hb_dateMilliSeconds() )
|
|
{
|
|
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 = timeout <= 0 ? 0 : ( hb_dateMilliSeconds() + 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 || timer == 0 || timer < hb_dateMilliSeconds() )
|
|
{
|
|
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
|