From 9d13008427a75c7cb3daa0a94b2cd72e0dc4b87e Mon Sep 17 00:00:00 2001 From: Przemyslaw Czerpak Date: Wed, 12 May 2010 00:27:04 +0000 Subject: [PATCH] 2010-05-12 02:26 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/external/minizip/ioapi.h ! fixed FreeBSD and HAIKU builds * harbour/src/rtl/fserr.c * added translation for EPERM * harbour/include/Makefile + harbour/include/hbapicom.h * harbour/src/rtl/Makefile + harbour/src/rtl/hbcom.c + added Harbour multiplatform serial port C API (hb_com*() functions). implemented code for *nixes, MS-Windows and OS2. DOS is not supported yet. Please make test on different platforms. ; few notes about this code: termios (*nix) based builds: - reading LSR is not supported - duration in break signal is fixed (at least 0.25 seconds, and not more that 0.5 seconds) - DTR/DSR hardware flow control is not supported - setting error character is not supported - discard card is supported only on few platforms - checking input/output flow state is not supported - if some platforms do not support some termio extensions then compile time warnings TODO_* should be generated. MS-Windows builds: - discard card is not supported OS2 builds: - checking for input flow state is not supported - discard card is not supported In all builds not all RS-232 hardware flags/state are available. OS2 build supports most of them, This code needs to be extensively tested. I wrote it without any serious tests. Especially OS2 builds should be verified by OS2 users. I wrote this port using only documentation which OS2 API available in the Internet. DOS is not supported yet though it's possible to compile termio code for *nixes with DJGPP. Anyhow it would be very nice if we can add our own DOS serial port code. I would like to ask if any of you has low level serial port code in C for DOS (i.e. used with Clipper) and can send it to us so we can use it with Harbour. I have my own serial port library for Clipper but it's written in assembler and it's much wider then sth what we need so it cannot be easy adopted for Harbour. * harbour/contrib/hbct/Makefile + harbour/contrib/hbct/ctcom1.c + harbour/contrib/hbct/ctcom.ch + harbour/contrib/hbct/ctcom2.c + added CT3 compatible COM_*() functions. + added CT3 compatible XMOBLOCK(), XMOCHECK(), ZEROINSERT() and ZEROREMOVE() functions. + added new CT COM function: COM_DEVNAME( [, ] ) -> which can be used to specify device name for given port in modern systems which do not give direct hardware access for the process. ; few notes about CT3 COM_*() functions in Harbour. In COM_OPEN() only 1-st parameter is significant, input/output buffer sizes and trap mode parameters are ignored. In modern OS-es such functionality is controlled by OS and usually buffered read/write is always enabled. The sizes of IO buffers can be used only as suggested IO buffer size for OS in some systems. It's possible that these additional parameters will be used in DOS builds in the future. COM_READ() does not support 2-nd parameter . It can be implemented but because we do not have direct access to OS buffers then we will have to emulate it ourselves what is rather inefficient. Anyhow I can implement it if users think it's critical. In COM_CRC() I fixed few CT3 bugs so it's not bug compatible with CT3, i.e. it works correctly for 8 bit and smaller polynomials instead of returning 0 or supports much larger polynomials up to 64bits. For 16/17 bit polynomials it gives the same results as CT3 so for most common usage it should be binary compatible with CT3. In ZEROREMOVE() I fixed decoding some wrong CCITT strings which does not have trailing 0 so it returns empty string "" for such corrupted data. If someone needs original CT3 behavior for some broken code then is can be enabled by HB_CT3_ZEROREMOVE_BUG macro. I haven't implemented few functions. COM_GETIO(), COM_SETIO(), COM_GETIRQ(), COM_SETIRQ() are not portable and can be implemented only for really few platforms, i.e. for DOS when/if we add support for serial ports to Harbour DOS builds. Similar functionality for all other platforms gives our new function COM_DEVNAME(). COM_KEY(), COM_SKEY() and COM_EVENT() are also not implemented. To make them well we should add support for asynchronous events to HVM and such extension is still unavailable. Some simulation can be implemented using idle tasks but this can be done also by final Harbour users so I decided to not make it. Please test it - I've never used CT3 COM_*() API with Clipper. * harbour/contrib/hbct/dummy.c * removed dummy CT3 serial communication functions ; such files with dummy functions introduces very serious problems for user code because they do not respect original module granularity effectively breaking overloading only chosen functions so it breaks also some real Clipper code. --- harbour/ChangeLog | 100 + harbour/contrib/hbct/Makefile | 3 + harbour/contrib/hbct/ctcom.ch | 98 + harbour/contrib/hbct/ctcom1.c | 524 +++++ harbour/contrib/hbct/ctcom2.c | 398 ++++ harbour/contrib/hbct/dummy.c | 41 - harbour/contrib/hbnetio/netiosrv.c | 2 +- harbour/external/minizip/ioapi.h | 4 +- harbour/include/Makefile | 2 + harbour/include/hbapicom.h | 154 ++ harbour/src/rtl/Makefile | 1 + harbour/src/rtl/fserr.c | 3 + harbour/src/rtl/hbcom.c | 2947 ++++++++++++++++++++++++++++ 13 files changed, 4234 insertions(+), 43 deletions(-) create mode 100644 harbour/contrib/hbct/ctcom.ch create mode 100644 harbour/contrib/hbct/ctcom1.c create mode 100644 harbour/contrib/hbct/ctcom2.c create mode 100644 harbour/include/hbapicom.h create mode 100644 harbour/src/rtl/hbcom.c diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 697daa2476..8c735a85d4 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,106 @@ past entries belonging to author(s): Viktor Szakats. */ +2010-05-12 02:26 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/external/minizip/ioapi.h + ! fixed FreeBSD and HAIKU builds + + * harbour/src/rtl/fserr.c + * added translation for EPERM + + * harbour/include/Makefile + + harbour/include/hbapicom.h + * harbour/src/rtl/Makefile + + harbour/src/rtl/hbcom.c + + added Harbour multiplatform serial port C API (hb_com*() functions). + implemented code for *nixes, MS-Windows and OS2. DOS is not supported + yet. Please make test on different platforms. + ; few notes about this code: + termios (*nix) based builds: + - reading LSR is not supported + - duration in break signal is fixed (at least 0.25 seconds, and not + more that 0.5 seconds) + - DTR/DSR hardware flow control is not supported + - setting error character is not supported + - discard card is supported only on few platforms + - checking input/output flow state is not supported + - if some platforms do not support some termio extensions then + compile time warnings TODO_* should be generated. + MS-Windows builds: + - discard card is not supported + OS2 builds: + - checking for input flow state is not supported + - discard card is not supported + In all builds not all RS-232 hardware flags/state are available. + OS2 build supports most of them, + + This code needs to be extensively tested. I wrote it without any + serious tests. Especially OS2 builds should be verified by OS2 + users. I wrote this port using only documentation which OS2 API + available in the Internet. + + DOS is not supported yet though it's possible to compile termio code + for *nixes with DJGPP. Anyhow it would be very nice if we can add + our own DOS serial port code. I would like to ask if any of you + has low level serial port code in C for DOS (i.e. used with Clipper) + and can send it to us so we can use it with Harbour. I have my + own serial port library for Clipper but it's written in assembler + and it's much wider then sth what we need so it cannot be easy + adopted for Harbour. + + * harbour/contrib/hbct/Makefile + + harbour/contrib/hbct/ctcom1.c + + harbour/contrib/hbct/ctcom.ch + + harbour/contrib/hbct/ctcom2.c + + added CT3 compatible COM_*() functions. + + added CT3 compatible XMOBLOCK(), XMOCHECK(), ZEROINSERT() and + ZEROREMOVE() functions. + + added new CT COM function: + COM_DEVNAME( [, ] ) -> + which can be used to specify device name for given port in modern + systems which do not give direct hardware access for the process. + ; few notes about CT3 COM_*() functions in Harbour. + In COM_OPEN() only 1-st parameter is significant, input/output buffer + sizes and trap mode parameters are ignored. In modern OS-es such + functionality is controlled by OS and usually buffered read/write + is always enabled. The sizes of IO buffers can be used only as + suggested IO buffer size for OS in some systems. It's possible that + these additional parameters will be used in DOS builds in the future. + COM_READ() does not support 2-nd parameter . It can be + implemented but because we do not have direct access to OS buffers + then we will have to emulate it ourselves what is rather inefficient. + Anyhow I can implement it if users think it's critical. + In COM_CRC() I fixed few CT3 bugs so it's not bug compatible with CT3, + i.e. it works correctly for 8 bit and smaller polynomials instead of + returning 0 or supports much larger polynomials up to 64bits. + For 16/17 bit polynomials it gives the same results as CT3 so for most + common usage it should be binary compatible with CT3. + In ZEROREMOVE() I fixed decoding some wrong CCITT strings which does + not have trailing 0 so it returns empty string "" for such corrupted + data. If someone needs original CT3 behavior for some broken code then + is can be enabled by HB_CT3_ZEROREMOVE_BUG macro. + + I haven't implemented few functions. + COM_GETIO(), COM_SETIO(), COM_GETIRQ(), COM_SETIRQ() are not portable + and can be implemented only for really few platforms, i.e. for DOS + when/if we add support for serial ports to Harbour DOS builds. + Similar functionality for all other platforms gives our new function + COM_DEVNAME(). + COM_KEY(), COM_SKEY() and COM_EVENT() are also not implemented. + To make them well we should add support for asynchronous events to HVM + and such extension is still unavailable. Some simulation can be + implemented using idle tasks but this can be done also by final + Harbour users so I decided to not make it. + + Please test it - I've never used CT3 COM_*() API with Clipper. + + * harbour/contrib/hbct/dummy.c + * removed dummy CT3 serial communication functions + ; such files with dummy functions introduces very serious problems for + user code because they do not respect original module granularity + effectively breaking overloading only chosen functions so it breaks + also some real Clipper code. + 2010-05-11 22:22 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * contrib/hbziparc/Makefile * contrib/hbziparc/hbziparc.prg diff --git a/harbour/contrib/hbct/Makefile b/harbour/contrib/hbct/Makefile index 2e8ec21445..dafeef80eb 100644 --- a/harbour/contrib/hbct/Makefile +++ b/harbour/contrib/hbct/Makefile @@ -30,6 +30,8 @@ C_SOURCES := \ count.c \ ctc.c \ ctchksum.c \ + ctcom1.c \ + ctcom2.c \ ctcrypt.c \ ctmath.c \ ctmath2.c \ @@ -115,6 +117,7 @@ PRG_SOURCES := \ PRG_HEADERS := \ ct.ch \ + ctcom.ch \ ctdisk.ch \ cterror.ch \ ctextern.ch \ diff --git a/harbour/contrib/hbct/ctcom.ch b/harbour/contrib/hbct/ctcom.ch new file mode 100644 index 0000000000..6a6de9cf42 --- /dev/null +++ b/harbour/contrib/hbct/ctcom.ch @@ -0,0 +1,98 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * constant values for CT3 serial communication COM_*() functions + * + * Copyright 2010 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + + +/* COM_MCR() */ +#define MCR_ERROR 0 /* Parameter error */ +#define MCR_DTR 1 /* Data terminal ready (DTR) */ +#define MCR_RTS 2 /* Request to send (RTS) */ +#define MCR_OUT_1 4 /* OUT 1 */ +#define MCR_OUT_2 8 /* OUT 2 */ +#define MCR_LOOP 16 /* LOOP */ + + +/* COM_MSR() */ +#define MSR_ERROR 0 /* Parameter error */ +#define MSR_DELTA_CTS 1 /* DELTA ready to send (DCTS) */ +#define MSR_DELTA_DSR 2 /* DELTA data terminal ready (DDSR) */ +#define MSR_TERI 4 /* Trailing edge RING (TERI) */ +#define MSR_DELTA_DCD 8 /* DELTA data carrier detected (DDCD) */ +#define MSR_CTS 16 /* Clear to send (CTS) */ +#define MSR_DSR 32 /* Data terminal ready (DSR) */ +#define MSR_RI 64 /* RING indicator (RI) */ +#define MSR_DCD 128 /* Data carrier detected (DCD) */ + + +/* COM_LSR() */ +#define LSR_ERROR 0 /* Parameter error */ +#define LSR_DATA_READY 1 /* Data ready */ +#define LSR_OVERRUN_ERR 2 /* Overflow error */ +#define LSR_PARITY_ERR 4 /* Parity error */ +#define LSR_FRAMING_ERR 8 /* Framing error */ +#define LSR_BREAK 16 /* BREAK recognized */ +#define LSR_TRANS_HOLD_EMPTY 32 /* Transmission holder register empty */ +#define LSR_TRANS_EMPTY 64 /* TX shift register empty */ + + +/* COM_SMODE() */ +#define SMODE_EMPTY 1 /* Sending buffer empty */ +#define SMODE_SOFT 2 /* Wait for software handshake release(XON) */ +#define SMODE_HARD 4 /* Wait for hardware handshake release(CTS) */ +#define SMODE_RFLUSH 8 /* Deleted from remote station */ + + +/* COM_CRC() polynomials */ +#define Parity 3 /* 2^1 + 1^0 */ +#define LCR_8 257 /* 2^8 + 1^0 */ +#define CRC_12 5011 /* 2^12 + 2^11 + 2^3 + 2^2 + 2^1 + 1^0 */ +#define CRC_16_X25 69665 /* 2^16 + 2^12 + 2^5 + 1^0 */ +#define CRC_16 98309 /* 2^16 + 2^15 + 2^2 + 1^0 */ diff --git a/harbour/contrib/hbct/ctcom1.c b/harbour/contrib/hbct/ctcom1.c new file mode 100644 index 0000000000..bee3a7bbde --- /dev/null +++ b/harbour/contrib/hbct/ctcom1.c @@ -0,0 +1,524 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * CT3 serial communication COM_*() functions + * + * Copyright 2010 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbapi.h" +#include "hbapiitm.h" +#include "hbapicom.h" +#include "ctcom.ch" + +static int hb_ctComCharParam( int iParam ) +{ + const char * pszParam = hb_parc( iParam ); + + if( pszParam ) + { + if( hb_parclen( iParam ) > 0 ) + return ( unsigned char ) pszParam[ 0 ]; + } + else if( HB_ISNUM( iParam ) ) + return ( unsigned char ) hb_parni( iParam ); + + return -1; +} + +static void hb_ctComTestMSR( int iLine ) +{ + HB_BOOL fResult; + int iMSR; + + if( hb_comMSR( hb_parni( 1 ), &iMSR ) != -1 ) + fResult = ( iMSR & iLine ) != 0; + else + fResult = HB_FALSE; + + hb_retl( fResult ); +} + +/* COM_COUNT( ) -> + */ +HB_FUNC( COM_COUNT ) +{ + hb_retni( hb_comInputCount( hb_parni( 1 ) ) ); +} + +/* COM_SCOUNT( ) -> + */ +HB_FUNC( COM_SCOUNT ) +{ + hb_retni( hb_comOutputCount( hb_parni( 1 ) ) ); +} + +/* COM_FLUSH( ) -> + */ +HB_FUNC( COM_FLUSH ) +{ + hb_retl( hb_comFlush( hb_parni( 1 ), HB_COM_IFLUSH ) != -1 ); +} + +/* COM_SFLUSH( ) -> + */ +HB_FUNC( COM_SFLUSH ) +{ + hb_retl( hb_comFlush( hb_parni( 1 ), HB_COM_OFLUSH ) != -1 ); +} + +/* COM_CTS( ) -> + */ +HB_FUNC( COM_CTS ) +{ + hb_ctComTestMSR( HB_COM_MSR_CTS ); +} + +/* COM_DCD( ) -> + */ +HB_FUNC( COM_DCD ) +{ + hb_ctComTestMSR( HB_COM_MSR_DCD ); +} + +/* COM_DSR( ) -> + */ +HB_FUNC( COM_DSR ) +{ + hb_ctComTestMSR( HB_COM_MSR_DSR ); +} + +/* COM_RING( ) -> + */ +HB_FUNC( COM_RING ) +{ + hb_ctComTestMSR( HB_COM_MSR_RI ); +} + +/* COM_RTS( , [] ) -> + */ +HB_FUNC( COM_RTS ) +{ + int iMCR, iClr = 0, iSet = 0; + + if( HB_ISLOG( 2 ) ) + { + if( hb_parl( 2 ) ) + iSet = HB_COM_MCR_RTS; + else + iClr = HB_COM_MCR_RTS; + } + hb_comMCR( hb_parni( 1 ), &iMCR, iClr, iSet ); + hb_retl( ( iMCR & HB_COM_MCR_DTR ) != 0 ); +} + +/* COM_DTR( , [] ) -> + */ +HB_FUNC( COM_DTR ) +{ + int iMCR, iClr = 0, iSet = 0; + + if( HB_ISLOG( 2 ) ) + { + if( hb_parl( 2 ) ) + iSet = HB_COM_MCR_DTR; + else + iClr = HB_COM_MCR_DTR; + } + hb_comMCR( hb_parni( 1 ), &iMCR, iClr, iSet ); + hb_retl( ( iMCR & HB_COM_MCR_DTR ) != 0 ); +} + +/* COM_MCR( , [] ) -> (MCR_*) + */ +HB_FUNC( COM_MCR ) +{ + int iMCR, iClr, iSet; + + if( HB_ISNUM( 2 ) ) + { + iClr = 0xff; + iSet = hb_parni( 2 ) & 0xff; + } + else + iClr = iSet = 0; + + if( hb_comMCR( hb_parni( 1 ), &iMCR, iClr, iSet ) == -1 ) + iMCR = MCR_ERROR; + + hb_retni( iMCR ); +} + +/* COM_MSR( ) -> (MSR_*) + */ +HB_FUNC( COM_MSR ) +{ + int iMSR; + + if( hb_comMSR( hb_parni( 1 ), &iMSR ) == -1 ) + iMSR = MSR_ERROR; + + hb_retni( iMSR ); +} + +/* COM_LSR( ) -> (LSR_*) + */ +HB_FUNC( COM_LSR ) +{ + int iLSR; + + if( hb_comLSR( hb_parni( 1 ), &iLSR ) == -1 ) + iLSR = LSR_ERROR; + + hb_retni( iLSR ); +} + +/* COM_BREAK( , =100 ) -> + */ +HB_FUNC( COM_BREAK ) +{ + hb_retl( hb_comSendBreak( hb_parni( 1 ), hb_parnidef( 2, 100 ) ) != 0 ); +} + +/* COM_HARD( , [], [] ) -> + */ +HB_FUNC( COM_HARD ) +{ + int iPort = hb_parni( 1 ), iFlow, iMask; + HB_BOOL fResult = HB_FALSE; + + if( hb_comFlowControl( iPort, &iFlow, -1 ) != -1 ) + { + iMask = hb_parl( 3 ) ? ( HB_COM_FLOW_IDTRDSR | HB_COM_FLOW_ODTRDSR ) : + ( HB_COM_FLOW_IRTSCTS | HB_COM_FLOW_ORTSCTS ); + fResult = ( iFlow & iMask ) == iMask; + + if( HB_ISLOG( 2 ) ) + { + iFlow &= ~( HB_COM_FLOW_IDTRDSR | HB_COM_FLOW_ODTRDSR | + HB_COM_FLOW_IRTSCTS | HB_COM_FLOW_ORTSCTS ); + if( hb_parl( 2 ) ) + iFlow |= iMask; + hb_comFlowControl( iPort, NULL, iFlow ); + } + } + hb_retl( fResult ); +} + +/* COM_SOFT( , [], + [], [] ) -> + */ +HB_FUNC( COM_SOFT ) +{ + int iPort = hb_parni( 1 ), iFlow, iMask; + HB_BOOL fResult = HB_FALSE; + + if( hb_comFlowControl( iPort, &iFlow, -1 ) != -1 ) + { + iMask = ( HB_COM_FLOW_XON | HB_COM_FLOW_XOFF ); + fResult = ( iFlow & iMask ) == iMask; + + if( HB_ISLOG( 2 ) ) + { + if( hb_parl( 2 ) ) + iFlow |= iMask; + else + iFlow &= ~iMask; + hb_comFlowControl( iPort, NULL, iFlow ); + } + if( hb_pcount() > 2 ) + hb_comFlowChars( iPort, hb_ctComCharParam( 3 ), hb_ctComCharParam( 4 ) ); + } + hb_retl( fResult ); +} + +/* COM_SOFT_R( , [] ) -> + */ +HB_FUNC( COM_SOFT_R ) +{ + HB_BOOL fResult = HB_FALSE; + int iPort = hb_parni( 1 ), iMode; + + if( HB_ISLOG( 2 ) ) + hb_comFlowSet( iPort, HB_COM_FL_SOFT | + ( hb_parl( 2 ) ? HB_COM_FL_OOFF : HB_COM_FL_OON ) ); + + iMode = hb_comOutputState( iPort ); + if( iMode > 0 ) + fResult = ( iMode & HB_COM_TX_XOFF ) != 0; + + hb_retl( fResult ); +} + +/* COM_SOFT_S( ) -> + */ +HB_FUNC( COM_SOFT_S ) +{ + HB_BOOL fResult = HB_FALSE; + int iMode = hb_comInputState( hb_parni( 1 ) ); + + if( iMode > 0 ) + fResult = ( iMode & HB_COM_RX_XOFF ) != 0; + + hb_retl( fResult ); +} + +/* COM_ERRCHR( , [] ) -> + */ +HB_FUNC( COM_ERRCHR ) +{ + hb_retl( hb_comErrorChar( hb_parni( 1 ), hb_ctComCharParam( 2 ) ) != -1 ); +} + +/* COM_REMOTE( , [] ) -> + */ +HB_FUNC( COM_REMOTE ) +{ + hb_retl( hb_comDiscardChar( hb_parni( 1 ), hb_ctComCharParam( 2 ) ) > 0 ); +} + +/* COM_SMODE( ) -> + */ +HB_FUNC( COM_SMODE ) +{ + int iMode = hb_comOutputState( hb_parni( 1 ) ), iResult = 0; + + if( iMode > 0 ) + { + if( iMode & HB_COM_TX_EMPTY ) + iResult |= SMODE_EMPTY; + if( iMode & HB_COM_TX_XOFF ) + iResult |= SMODE_SOFT; + if( iMode & ( HB_COM_TX_CTS | HB_COM_TX_DSR | HB_COM_TX_DCD ) ) + iResult |= SMODE_HARD; + if( iMode & HB_COM_TX_RFLUSH ) + iResult |= SMODE_RFLUSH; + } + + hb_retni( iResult ); +} + +/* COM_EVENT( , ) -> + */ +HB_FUNC( COM_EVENT ) +{ + /* TODO: unsupported */ + hb_retni( 0 ); +} + +/* COM_KEY( , [], [] ) -> + */ +HB_FUNC( COM_KEY ) +{ + /* TODO: unsupported */ + hb_retl( HB_FALSE ); +} + +/* COM_SKEY( [], [], + * [] ) -> + */ +HB_FUNC( COM_SKEY ) +{ + /* TODO: unsupported */ + hb_retl( HB_FALSE ); +} + + +/* COM_INIT( , [=300], [=N], + * [=8], [=1] ) -> + */ +HB_FUNC( COM_INIT ) +{ + int iPort = hb_parni( 1 ), + iBaud = hb_parnidef( 2, 300 ), + iParity = hb_parcx( 3 )[ 0 ], + iSize = hb_parnidef( 4, 8 ), + iStop = hb_parnidef( 5, 1 ); + + hb_retl( hb_comInit( iPort, iBaud, iParity, iSize, iStop ) != -1 ); +} + +/* COM_OPEN( , [=100] [, =0], + * [] ) -> + */ +HB_FUNC( COM_OPEN ) +{ + /* TODO: add support for */ + /* TODO: add support for */ + /* TODO: add support for */ + + hb_retl( hb_comOpen( hb_parni( 1 ) ) != -1 ); +} + +/* COM_CLOSE( ) -> + */ +HB_FUNC( COM_CLOSE ) +{ + int iPort = hb_parni( 1 ); + + hb_comFlush( iPort, HB_COM_IOFLUSH ); + hb_retl( hb_comClose( iPort ) != -1 ); +} + +/* COM_READ( , [], [] ) -> + */ +HB_FUNC( COM_READ ) +{ + char buffer[ 1024 ]; + char * data; + long lLen, lRecv; + int iPort = hb_parni( 1 ); + + /* TODO: add support for */ + + if( HB_ISNUM( 2 ) ) + lLen = hb_parnl( 2 ); + else + { + lLen = hb_comInputCount( iPort ); + if( lLen < ( long ) sizeof( buffer ) >> 1 ) + lLen = sizeof( buffer ); + else + lLen <<= 2; + } + if( lLen <= ( long ) sizeof( buffer ) ) + data = buffer; + else + data = ( char * ) hb_xgrab( lLen + 1 ); + + lRecv = hb_comRecv( iPort, buffer, lLen, 0 ); + if( lRecv < 0 ) + lRecv = 0; + + if( data == buffer ) + hb_retclen( data, lRecv ); + else if( lLen > 16 && ( lLen >> 2 ) > lRecv ) + { + hb_retclen( data, lRecv ); + hb_xfree( data ); + } + else + hb_retclen_buffer( data, lRecv ); +} + +/* COM_SEND( , ) -> + */ +HB_FUNC( COM_SEND ) +{ + const char * data = hb_parc( 2 ); + long lLen = 0; + char buffer; + + /* TODO: add automatic drain call for ports open without send buffer */ + + if( data ) + lLen = ( long ) hb_parclen( 2 ); + else if( HB_ISNUM( 2 ) ) + { + buffer = ( unsigned char ) hb_parni( 2 ); + data = &buffer; + lLen = 1; + } + + if( lLen ) + { + long lResult = hb_comSend( hb_parni( 1 ), data, lLen, 0 ); + if( lResult > 0 ) + lLen -= lResult; + } + + hb_retnl( lLen ); +} + +/* COM_NUM() -> + */ +HB_FUNC( COM_NUM ) +{ + hb_retni( hb_comLastNum() ); +} + + +/* COM_GETIO( ) -> | -1 + */ +HB_FUNC( COM_GETIO ) +{ + /* TODO! */ +} + +/* COM_SETIO( , ) -> + */ +HB_FUNC( COM_SETIO ) +{ + /* TODO! */ +} + +/* COM_GETIRQ( ) -> | -1 + */ +HB_FUNC( COM_GETIRQ ) +{ + /* TODO! */ +} + +/* COM_SETIRQ( , ) -> + */ +HB_FUNC( COM_SETIRQ ) +{ + /* TODO! */ +} + +/* COM_DEVNAME( [, ] ) -> + */ +HB_FUNC( COM_DEVNAME ) +{ + int iPort = hb_parni( 1 ); + const char * szDevName = hb_parc( 2 ); + char buffer[ HB_COM_DEV_NAME_MAX ]; + + hb_retc( hb_comGetDevice( iPort, buffer, sizeof( buffer ) ) ); + if( szDevName ) + hb_comSetDevice( iPort, szDevName ); +} diff --git a/harbour/contrib/hbct/ctcom2.c b/harbour/contrib/hbct/ctcom2.c new file mode 100644 index 0000000000..b972244bbb --- /dev/null +++ b/harbour/contrib/hbct/ctcom2.c @@ -0,0 +1,398 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * CT3 serial communication functions not directly operating on + * serial devices + * + * Copyright 2010 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#include "hbapi.h" +#include "hbapiitm.h" +#include "hbapigt.h" +#include "hbchksum.h" + + +/* COM_DOSCON( , [], [] ) -> + */ +HB_FUNC( COM_DOSCON ) +{ + HB_SIZE nLen = hb_parclen( 1 ); + + if( nLen > 0 ) + { + if( HB_ISNUM( 2 ) || HB_ISNUM( 3 ) ) + { + int iRow, iCol; + + hb_gtGetPos( &iRow, &iCol ); + if( HB_ISNUM( 2 ) ) + iRow = hb_parni( 1 ); + if( HB_ISNUM( 3 ) ) + iCol = hb_parni( 2 ); + hb_gtSetPos( iRow, iCol ); + } + hb_gtWriteCon( hb_parc( 1 ), nLen ); + } + hb_retc_null(); +} + +/* COM_CRC( , [], [] ) -> + */ +HB_FUNC( COM_CRC ) +{ + HB_MAXUINT crc = hb_parnint( 2 ); + const char * szString = hb_parc( 1 ); + + if( szString ) + { + HB_MAXUINT nPolynomial = ( HB_MAXUINT ) hb_parnint( 3 ); + + if( nPolynomial == 0 ) + nPolynomial = 0x11021; /* CRC_16_X25 */ + + /* NOTE: warning this function is not bug compatible with CT3. + * It fixes few problems in original CT3 implementation + * i.e. it works correctly for 8 bit and smaller polynomials + * instead of returning 0 or supports much larger polynomials + * up to 64bits. + * For 16/17 bit polynomials it gives the same results as CT3 + * so for most common usage it should be binary compatible + * with CT3. [druzus] + */ + crc = hb_crcct( crc, szString, hb_parclen( 1 ), nPolynomial ); + } + hb_retnint( crc ); +} + +static char s_xmoblock_sum( const char * szData, HB_SIZE nLen ) +{ + unsigned char uc = 0; + while( nLen-- ) + uc += ( unsigned char ) *szData++; + return ( char ) uc; +} + +/* XMOBLOCK( , , [], [] ) -> + */ +HB_FUNC( XMOBLOCK ) +{ + const char * szData; + HB_SIZE nLen, nSize; + char * pszBlock; + int iBlock; + HB_BOOL fCRC; + + szData = hb_parc( 1 ); + nLen = hb_parclen( 1 ); + iBlock = hb_parni( 2 ); + fCRC = hb_parl( 3 ); + nSize = hb_parni( 4 ) == 2 ? 1024 : 128; + + iBlock &= 0xFF; + if( nLen > nSize ) + nLen = nSize; + pszBlock = ( char * ) hb_xgrab( nSize + ( fCRC ? 6 : 5 ) ); + pszBlock[ 0 ] = nSize == 128 ? 1 : 2; + pszBlock[ 1 ] = ( char ) iBlock; + pszBlock[ 2 ] = ( char ) ( 0xFF - iBlock ); + if( szData ) + memcpy( pszBlock + 3, szData, nLen ); + if( nLen < nSize ) + memset( pszBlock + nLen + 3, 0, nSize - nLen ); + if( fCRC ) + { + HB_U16 crc = ( HB_U16 ) hb_crcct( 0, pszBlock + 3, nSize, 0x11021 ); + HB_PUT_BE_UINT16( &pszBlock[ 3 + nSize ], crc ); + nSize += 5; + } + else + { + pszBlock[ 3 + nSize ] = s_xmoblock_sum( szData, nLen ); + nSize += 4; + } + hb_retclen_buffer( pszBlock, nSize ); +} + +/* XMOCHECK( , [] ) -> |-1 + */ +HB_FUNC( XMOCHECK ) +{ + HB_SIZE nLen = hb_parclen( 1 ), nSize; + int iResult = -1; + + if( nLen >= 132 ) + { + const char * szBlock = hb_parc( 1 ); + HB_BOOL fCRC = hb_parl( 2 ); + + if( *szBlock == 0x01 ) + nSize = 128; + else if( *szBlock == 0x02 ) + nSize = 1024; + else + nSize = nLen; + if( nLen == nSize + ( fCRC ? 5 : 4 ) && + ( unsigned char ) szBlock[ 1 ] + + ( unsigned char ) szBlock[ 2 ] == 0xFF ) + { + if( fCRC ? + hb_crcct( 0, szBlock + 3, nSize + 2, 0x11021 ) == 0 : + s_xmoblock_sum( szBlock + 3, nSize ) == szBlock[ 3 + nSize ] ) + iResult = ( unsigned char ) szBlock[ 1 ]; + } + } + hb_retni( iResult ); +} + +/* ZEROINSERT( ) -> + */ +HB_FUNC( ZEROINSERT ) +{ + PHB_ITEM pString = hb_param( 1, HB_IT_STRING ); + + if( pString ) + { + const char * szText; + HB_SIZE nLen, nBits, n; + unsigned int uiVal; + int i, j; + + szText = hb_itemGetCPtr( pString ); + nLen = hb_itemGetCLen( pString ); + uiVal = 0; + nBits = 0; + uiVal = 0; + /* NOTE: trailing zero accessed intentionally */ + for( n = 0; n <= nLen; ++n ) + { + uiVal |= ( unsigned char ) szText[ n ]; + for( i = 0; i < 8; ++i ) + { + if( ( uiVal & 0xF800 ) == 0xF800 ) + { + uiVal &= 0xF7FF; + ++nBits; + } + uiVal <<= 1; + } + } + if( nBits ) + { + HB_SIZE nDest = nLen + ( ( nBits + 7 ) >> 3 ); + char * pszDest = ( char * ) hb_xgrab( nDest + 1 ); + unsigned char c = 0; + + nBits = n = 0; + i = 1; + j = 8; + uiVal = ( unsigned char ) szText[ n ]; + uiVal <<= 8; + while( nBits < nDest ) + { + if( --i == 0 ) + { + if( ++n < nLen ) + { + uiVal |= ( unsigned char ) szText[ n ]; + i = 8; + } + } + if( ( uiVal & 0xF800 ) == 0xF800 ) + { + c = ( c << 1 ) | 1; + if( --j == 0 ) + { + pszDest[ nBits++ ] = c; + j = 8; + } + uiVal &= 0xF7FF; + } + c <<= 1; + if( uiVal & 0x8000 ) + c |= 1; + if( --j == 0 ) + { + pszDest[ nBits++ ] = c; + j = 8; + } + uiVal <<= 1; + } + + hb_retclen_buffer( pszDest, nDest ); + } + else + hb_itemReturn( pString ); + } + else + hb_retc_null(); +} + +/* ZEROREMOVE( ) -> cString + */ +HB_FUNC( ZEROREMOVE ) +{ + PHB_ITEM pString = hb_param( 1, HB_IT_STRING ); + + if( pString ) + { + const char * szText; + HB_SIZE nLen, nDest, nBits, n; + int i, j, l; + unsigned char ucVal; + + szText = hb_itemGetCPtr( pString ); + nLen = hb_itemGetCLen( pString ); + j = 8; + l = 0; + ucVal = 0; + + for( n = nDest = nBits = 0; n < nLen; ++n ) + { + unsigned char c = szText[ n ]; + + for( i = 0; i < 8; ++i ) + { + if( l == 5 ) + { + if( c & 0x80 ) + { + /* wrong string encoding which does not confirm + * CCITT specification. + */ + hb_retc_null(); + return; + } + l = 0; + ++nBits; + } + else + { + ucVal <<= 1; + if( c & 0x80 ) + { + ++l; + ucVal |= 1; + } + else + l = 0; + if( --j == 0 ) + { + ucVal = 0; + ++nDest; + j = 8; + } + } + c <<= 1; + } + } + + /* NOTE: CT3 decodes some wrong CCITT strings which does not have + * trailing 0 instead of returning empty string "", i.e.: + * ? Len( ZeroRemove( Chr( 31 ) ) ) + * ? Len( ZeroRemove( Chr( 31 ) + Chr( 31 ) ) ) + * this implementation fixed this bug but if you need strict + * CT3 behavior for compatibility in some broken code then + * you can disable this fix setting HB_CT3_ZEROREMOVE_BUG + * macro. [druzus] + */ +#ifdef HB_CT3_ZEROREMOVE_BUG + if( l == 5 ) + { + ++nLen; + ++nDest; + ucVal = 0; + } + if( ucVal != 0 ) +#else + if( ucVal != 0 || l == 5 ) +#endif + + hb_retc_null(); + else if( nBits ) + { + char * pszDest = ( char * ) hb_xgrab( nDest + 1 ); + + j = 8; + l = 0; + ucVal = 0; + for( n = nDest = 0; n < nLen; ++n ) + { + unsigned char c = szText[ n ]; + + for( i = 0; i < 8; ++i ) + { + if( l == 5 ) + l = 0; + else + { + ucVal <<= 1; + if( c & 0x80 ) + { + ++l; + ucVal |= 1; + } + else + l = 0; + if( --j == 0 ) + { + pszDest[ nDest++ ] = ucVal; + j = 8; + } + } + c <<= 1; + } + } + + hb_retclen_buffer( pszDest, nDest ); + } + else + hb_itemReturn( pString ); + } + else + hb_retc_null(); +} diff --git a/harbour/contrib/hbct/dummy.c b/harbour/contrib/hbct/dummy.c index b61cb40389..cd28701510 100644 --- a/harbour/contrib/hbct/dummy.c +++ b/harbour/contrib/hbct/dummy.c @@ -101,47 +101,6 @@ HB_FUNC( TRAPINPUT ) {;} HB_FUNC( TRAPSHIFT ) {;} HB_FUNC( VGA28 ) {;} HB_FUNC( VGA50 ) {;} -/* Introduction Serial Communications */ -HB_FUNC( COM_BREAK ) {;} -HB_FUNC( COM_CLOSE ) {;} -HB_FUNC( COM_COUNT ) {;} -HB_FUNC( COM_CRC ) {;} -HB_FUNC( COM_CTS ) {;} -HB_FUNC( COM_DCD ) {;} -HB_FUNC( COM_DOSCON ) {;} -HB_FUNC( COM_DSR ) {;} -HB_FUNC( COM_DTR ) {;} -HB_FUNC( COM_ERRCHR ) {;} -HB_FUNC( COM_EVENT ) {;} -HB_FUNC( COM_FLUSH ) {;} -HB_FUNC( COM_GETIO ) {;} -HB_FUNC( COM_GETIRQ ) {;} -HB_FUNC( COM_HARD ) {;} -HB_FUNC( COM_INIT ) {;} -HB_FUNC( COM_KEY ) {;} -HB_FUNC( COM_LSR ) {;} -HB_FUNC( COM_MCR ) {;} -HB_FUNC( COM_MSR ) {;} -HB_FUNC( COM_NUM ) {;} -HB_FUNC( COM_OPEN ) {;} -HB_FUNC( COM_READ ) {;} -HB_FUNC( COM_REMOTE ) {;} -HB_FUNC( COM_RING ) {;} -HB_FUNC( COM_RTS ) {;} -HB_FUNC( COM_SCOUNT ) {;} -HB_FUNC( COM_SEND ) {;} -HB_FUNC( COM_SETIO ) {;} -HB_FUNC( COM_SETIRQ ) {;} -HB_FUNC( COM_SFLUSH ) {;} -HB_FUNC( COM_SKEY ) {;} -HB_FUNC( COM_SMODE ) {;} -HB_FUNC( COM_SOFT ) {;} -HB_FUNC( COM_SOFT_R ) {;} -HB_FUNC( COM_SOFT_S ) {;} -HB_FUNC( XMOBLOCK ) {;} -HB_FUNC( XMOCHECK ) {;} -HB_FUNC( ZEROINSERT ) {;} -HB_FUNC( ZEROREMOVE ) {;} /* Introduction Video Functions */ HB_FUNC( EGAPALETTE ) {;} HB_FUNC( FONTLOAD ) {;} diff --git a/harbour/contrib/hbnetio/netiosrv.c b/harbour/contrib/hbnetio/netiosrv.c index f25803604a..9919a401ae 100644 --- a/harbour/contrib/hbnetio/netiosrv.c +++ b/harbour/contrib/hbnetio/netiosrv.c @@ -1351,7 +1351,7 @@ HB_FUNC( NETIO_SRVSTATUS ) if( !conn ) iStatus = -1; - else if( conn->sd != HB_NO_SOCKET ) + else if( conn->sd == HB_NO_SOCKET ) iStatus = -2; else if( conn->stop ) iStatus = -3; diff --git a/harbour/external/minizip/ioapi.h b/harbour/external/minizip/ioapi.h index 4363a2d281..36904319eb 100644 --- a/harbour/external/minizip/ioapi.h +++ b/harbour/external/minizip/ioapi.h @@ -46,7 +46,9 @@ #if defined( __BORLANDC__ ) || \ defined( __WATCOMC__ ) || \ defined( __MINGW32CE__ ) || \ - defined( HB_OS_DARWIN ) + defined( HB_OS_BSD ) || \ + defined( HB_OS_DARWIN ) || \ + defined( HB_OS_HAIKU ) # define USE_FILE32API #endif diff --git a/harbour/include/Makefile b/harbour/include/Makefile index 90c19f42a7..19f0e2655f 100644 --- a/harbour/include/Makefile +++ b/harbour/include/Makefile @@ -10,6 +10,7 @@ C_HEADERS := \ hbapi.h \ hbapicdp.h \ hbapicls.h \ + hbapicom.h \ hbapidbg.h \ hbapierr.h \ hbapifs.h \ @@ -57,6 +58,7 @@ C_HEADERS := \ hbsocket.h \ hbstack.h \ hbsxfunc.h \ + hbtask.h \ hbthread.h \ hbtrace.h \ hbtypes.h \ diff --git a/harbour/include/hbapicom.h b/harbour/include/hbapicom.h new file mode 100644 index 0000000000..2d15252419 --- /dev/null +++ b/harbour/include/hbapicom.h @@ -0,0 +1,154 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * serial communication functions and constant values + * + * Copyright 2010 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#ifndef HB_APICOM_H_ +#define HB_APICOM_H_ + +#include "hbapi.h" + +#define HB_COM_PORT_MAX 256 + +#define HB_COM_DEV_NAME_MAX 64 + +#define HB_COM_ANY -1 +#define HB_COM_DISABLED 0 +#define HB_COM_ENABLED 1 +#define HB_COM_OPEN 2 + +#define HB_COM_IFLUSH 1 +#define HB_COM_OFLUSH 2 +#define HB_COM_IOFLUSH 3 + +#define HB_COM_MCR_DTR 0x01 /* Data terminal ready (DTR) TIOCM_DTR */ +#define HB_COM_MCR_RTS 0x02 /* Request to send (RTS) TIOCM_RTS */ +#define HB_COM_MCR_OUT_1 0x04 /* OUT 1 */ +#define HB_COM_MCR_OUT_2 0x08 /* OUT 2 */ +#define HB_COM_MCR_LOOP 0x10 /* LOOP */ + +#define HB_COM_MSR_DELTA_CTS 0x01 /* DELTA ready to send (DCTS) */ +#define HB_COM_MSR_DELTA_DSR 0x02 /* DELTA data terminal ready (DDSR) */ +#define HB_COM_MSR_TERI 0x04 /* Trailing edge RING (TERI) */ +#define HB_COM_MSR_DELTA_DCD 0x08 /* DELTA data carrier detected (DDCD) */ +#define HB_COM_MSR_CTS 0x10 /* Clear to send (CTS) TIOCM_CTS */ +#define HB_COM_MSR_DSR 0x20 /* Data terminal ready (DSR) TIOCM_DSR */ +#define HB_COM_MSR_RI 0x40 /* RING indicator (RI) TIOCM_RI */ +#define HB_COM_MSR_DCD 0x80 /* Data carrier detected (DCD) TIOCM_CD */ + +#define HB_COM_LSR_DATA_READY 0x01 /* Data ready */ +#define HB_COM_LSR_OVERRUN_ERR 0x02 /* Overflow error */ +#define HB_COM_LSR_PARITY_ERR 0x04 /* Parity error */ +#define HB_COM_LSR_FRAMING_ERR 0x08 /* Framing error */ +#define HB_COM_LSR_BREAK 0x10 /* BREAK recognized */ +#define HB_COM_LSR_TRANS_HOLD_EMPTY 0x20 /* Transmission holder register empty */ +#define HB_COM_LSR_TRANS_EMPTY 0x40 /* TX shift register empty */ + +#define HB_COM_FLOW_IRTSCTS 0x01 +#define HB_COM_FLOW_ORTSCTS 0x02 +#define HB_COM_FLOW_IDTRDSR 0x04 +#define HB_COM_FLOW_ODTRDSR 0x08 +#define HB_COM_FLOW_DCD 0x10 +#define HB_COM_FLOW_XOFF 0x20 /* XON/XOFF on input */ +#define HB_COM_FLOW_XON 0x40 /* XON/XOFF on output */ + +#define HB_COM_FL_OOFF 0x01 +#define HB_COM_FL_OON 0x02 +#define HB_COM_FL_IOFF 0x04 +#define HB_COM_FL_ION 0x08 +#define HB_COM_FL_SOFT 0x10 +#define HB_COM_FL_RTSCTS 0x20 +#define HB_COM_FL_DTRDSR 0x40 +#define HB_COM_FL_DCD 0x80 + +#define HB_COM_TX_CTS 0x01 +#define HB_COM_TX_DSR 0x02 +#define HB_COM_TX_DCD 0x04 +#define HB_COM_TX_XOFF 0x08 +#define HB_COM_TX_EMPTY 0x10 +#define HB_COM_TX_RFLUSH 0x20 + +#define HB_COM_RX_XOFF 0x01 + +#define HB_COM_ERR_WRONGPORT 1 +#define HB_COM_ERR_CLOSED 2 +#define HB_COM_ERR_TIMEOUT 3 +#define HB_COM_ERR_NOSUPPORT 4 +#define HB_COM_ERR_PARAMVALUE 5 +#define HB_COM_ERR_BUSY 6 +#define HB_COM_ERR_OTHER 7 + + +extern int hb_comLastNum( void ); +extern int hb_comOpen( int iPort ); +extern int hb_comClose( int iPort ); +extern int hb_comInit( int iPort, int iBaud, int iParity, int iSize, int iStop ); +extern long hb_comSend( int iPort, const void * data, long len, HB_MAXINT timeout ); +extern long hb_comRecv( int iPort, void * data, long len, HB_MAXINT timeout ); +extern int hb_comGetError( int iPort ); +extern int hb_comGetOsError( int iPort ); +extern int hb_comInputCount( int iPort ); +extern int hb_comOutputCount( int iPort ); +extern int hb_comFlush( int iPort, int iType ); +extern int hb_comMCR( int iPort, int * piValue, int iClr, int iSet ); +extern int hb_comMSR( int iPort, int * piValue ); +extern int hb_comLSR( int iPort, int * piValue ); +extern int hb_comSendBreak( int iPort, int iDurationInMilliSecs ); +extern int hb_comFlowControl( int iPort, int *piFlow, int iFlow ); +extern int hb_comFlowSet( int iPort, int iFlow ); +extern int hb_comFlowChars( int iPort, int iXONchar, int iXOFFchar ); +extern int hb_comDiscardChar( int iPort, int iChar ); +extern int hb_comErrorChar( int iPort, int iChar ); +extern int hb_comOutputState( int iPort ); +extern int hb_comInputState( int iPort ); +extern int hb_comSetDevice( int iPort, const char * szDevName ); +extern const char * hb_comGetDevice( int iPort, char * buffer, int size ); + +#endif /* HB_APICOM_H_ */ diff --git a/harbour/src/rtl/Makefile b/harbour/src/rtl/Makefile index 38486cefef..d13ac7a5fd 100644 --- a/harbour/src/rtl/Makefile +++ b/harbour/src/rtl/Makefile @@ -72,6 +72,7 @@ C_SOURCES := \ hbbfish.c \ hbbit.c \ hbbyte.c \ + hbcom.c \ hbcrc.c \ hbdyn.c \ hbdynhb.c \ diff --git a/harbour/src/rtl/fserr.c b/harbour/src/rtl/fserr.c index 7c364f57c5..59db709b89 100644 --- a/harbour/src/rtl/fserr.c +++ b/harbour/src/rtl/fserr.c @@ -84,6 +84,9 @@ static HB_ERRCODE hb_errnoToDosError( int ErrCode ) case EACCES: #if defined( ETXTBSY ) case ETXTBSY: +#endif +#if defined( EPERM ) + case EPERM: #endif return 5; /* Access denied */ case EBADF: diff --git a/harbour/src/rtl/hbcom.c b/harbour/src/rtl/hbcom.c new file mode 100644 index 0000000000..9cddcf7975 --- /dev/null +++ b/harbour/src/rtl/hbcom.c @@ -0,0 +1,2947 @@ +/* + * $Id$ + */ + +/* + * Harbour Project source code: + * serial communication functions + * + * Copyright 2010 Przemyslaw Czerpak + * www - http://www.harbour-project.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). + * + * As a special exception, the Harbour Project gives permission for + * additional uses of the text contained in its release of Harbour. + * + * The exception is that, if you link the Harbour libraries with other + * files to produce an executable, this does not by itself cause the + * resulting executable to be covered by the GNU General Public License. + * Your use of that executable is in no way restricted on account of + * linking the Harbour library code into it. + * + * This exception does not however invalidate any other reasons why + * the executable file might be covered by the GNU General Public License. + * + * This exception applies only to the code released by the Harbour + * Project under the name Harbour. If you copy code from other + * Harbour Project or Free Software Foundation releases into a copy of + * Harbour, as the General Public License permits, the exception does + * not apply to the code that you add in this way. To avoid misleading + * anyone as to the status of such modified files, you must delete + * this exception notice from them. + * + * If you write modifications of your own for Harbour, it is your choice + * whether to permit this exception to apply to your modifications. + * If you do not wish that, delete this exception notice. + * + */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include "hbapi.h" +#include "hbapifs.h" +#include "hbapiitm.h" +#include "hbapicom.h" +#include "hbvm.h" +#include "hbinit.h" +#include "hbdate.h" + +#if defined( HB_OS_UNIX ) /* || defined( __DJGPP__ ) */ +# if !defined( HB_HAS_TERMIOS ) +# define HB_HAS_TERMIOS +# endif +# if defined( HB_OS_SUNOS ) +# if !defined( BSD_COMP ) +# define BSD_COMP +# endif +# endif +#endif + + +#if defined( HB_HAS_TERMIOS ) +# include +# include +# include +# include +# include +# if defined( HB_OS_UNIX ) +# include +# include +# endif +#elif defined( HB_OS_WIN ) +# include +#elif defined( HB_OS_OS2 ) +# define INCL_BASE +# define INCL_DOS +# define INCL_DOSERROR +# define INCL_DOSDEVICES +# define INCL_DOSDEVIOCTL +# include +#endif + +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_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_comSetError( 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_comSetError( pCom, HB_COM_ERR_WRONGPORT ); + else + hb_comSetError( pCom, HB_COM_ERR_CLOSED ); + } + return NULL; +} + +static const char * hb_comGetName( 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_IRIX ) + hb_snprintf( buffer, size, "/dev/ttyf%d", pCom->port ); +# elif defined( HB_OS_DIGITAL_UNIX ) + hb_snprintf( buffer, size, "/dev/tty%02d", pCom->port ); +# elif defined( HB_OS_DARWIN ) + hb_snprintf( buffer, size, "/dev/cuaa%d", pCom->port - 1 ); +# else /* defined( HB_OS_LINUX ) || ... */ + hb_snprintf( buffer, size, "/dev/ttyS%d", pCom->port - 1 ); +# endif + /* other OS-es: + * IRIX: "/dev/ttyf%d" (1-based) + * Digital UNIX: "/dev/ttyf%02d" (1-based) + */ +#else + if( hb_iswinnt() ) + hb_snprintf( buffer, size, "\\\\.\\COM%d", pCom->port ); + else + hb_snprintf( buffer, size, "COM%d", pCom->port ); +#endif + name = buffer; + } + return name; +} + +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 ) + { + if( pCom->name ) + hb_xfree( pCom->name ); + pCom->name = szDevName ? hb_strdup( szDevName ) : NULL; + } + + return pCom ? 0 : -1; +} + +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; + pCom->error = pCom->oserr ? HB_COM_ERR_OTHER : 0; +} + +#if defined( HB_OS_UNIX ) +static int hb_comCanRead( PHB_COM pCom, HB_MAXINT timeout ) +{ + struct timeval tv, * ptv; + fd_set rfds; + int iResult; +#if !defined( HB_HAS_SELECT_TIMER ) + HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); +#endif + + for( ;; ) + { + FD_ZERO( &rfds ); + FD_SET( pCom->fd, &rfds ); + + if( timeout >= 0 ) + { + tv.tv_sec = ( long ) ( timeout / 1000 ); + tv.tv_usec = ( timeout % 1000 ) * 1000; + ptv = &tv; + } + else + ptv = NULL; + + iResult = select( ( int ) ( pCom->fd + 1 ), &rfds, NULL, NULL, ptv ); + hb_comSetOsError( pCom, iResult == -1 ); + if( iResult == -1 && timeout > 0 && HB_COM_IS_EINTR() && + hb_vmRequestQuery() == 0 ) +#if defined( HB_HAS_SELECT_TIMER ) + continue; +#else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + timer = timecurr; + if( timeout > 0 ) + continue; + } + } +#endif + break; + } + + return iResult < 0 ? -1 : + ( iResult > 0 && FD_ISSET( pCom->fd, &rfds ) ? 1 : 0 ); +} + +static int hb_comCanWrite( PHB_COM pCom, HB_MAXINT timeout ) +{ + struct timeval tv, * ptv; + fd_set wfds; + int iResult; +#if !defined( HB_HAS_SELECT_TIMER ) + HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); +#endif + + for( ;; ) + { + FD_ZERO( &wfds ); + FD_SET( pCom->fd, &wfds ); + + if( timeout >= 0 ) + { + tv.tv_sec = ( long ) ( timeout / 1000 ); + tv.tv_usec = ( timeout % 1000 ) * 1000; + ptv = &tv; + } + else + ptv = NULL; + + iResult = select( ( int ) ( pCom->fd + 1 ), NULL, &wfds, NULL, ptv ); + hb_comSetOsError( pCom, iResult == -1 ); + if( iResult == -1 && timeout > 0 && HB_COM_IS_EINTR() && + hb_vmRequestQuery() == 0 ) +#if defined( HB_HAS_SELECT_TIMER ) + continue; +#else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + timer = timecurr; + if( timeout > 0 ) + continue; + } + } +#endif + break; + } + + return iResult < 0 ? -1 : + ( iResult > 0 && FD_ISSET( pCom->fd, &wfds ) ? 1 : 0 ); +} +#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 ) + int iResult = ioctl( pCom->fd, FIONREAD, &iCount ); + if( iResult == -1 ) + iCount = 0; + hb_comSetOsError( pCom, iResult == -1 ); +#else + int TODO_TIOCINQ; + hb_comSetError( 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 ); +#else + int TODO_TIOCOUTQ; + hb_comSetError( 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_comSetError( 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) +*/ + +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; + + 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; + + 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_comSetError( 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_comSetError( 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 ) + { + /* NOTE: there is no support to read the Line Status Register (LSR) + */ + hb_comSetError( 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 ); + 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 ); + + iResult = tcsendbreak( pCom->fd, 0 ); + hb_comSetOsError( pCom, iResult == -1 ); + } + 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( 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_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( 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 ) + /* Raw input from device */ + cfmakeraw( &tio ); + /* Reset data bits ( cfmakeraw() puts it to CS8 ) */ + tia.c_cflag &= ~CSIZE; +#else + tio.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP | + INLCR | IGNCR | ICRNL | IXON ); + tio.c_oflag &= ~OPOST; + tio.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN ); + tio.c_cflag &= ~( CSIZE | PARENB ); +#endif + /* Enable the receiver and set local mode... */ + tio.c_cflag |= ( CLOCAL | CREAD ); + + tio.c_cc[ VTIME ] = 0; /* inter-character timer in 1/10 sec. */ + tio.c_cc[ VMIN ] = 0; /* minimum number of characters for read */ + + 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 + 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_comSetError( 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 ) + { +#if defined( TIOCNXCL ) + ioctl( pCom->fd, TIOCNXCL ); +#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; + } + } + + 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_comClose( iPort ); + + if( ( pCom->status & HB_COM_OPEN ) == 0 ) + { + char buffer[ HB_COM_DEV_NAME_MAX ]; + const char * name = hb_comGetName( pCom, buffer, sizeof( buffer ) ); + + pCom->fd = open( name, O_RDWR | O_NOCTTY ); + if( pCom->fd != -1 ) + { +#if defined( TIOCEXCL ) /* TIOCNXCL */ + iResult = ioctl( pCom->fd, TIOCEXCL ); + if( iResult != 0 ) + { + close( pCom->fd ); + pCom->fd = -1; + hb_comSetError( pCom, HB_COM_ERR_BUSY ); + } + else +#else + iResult = 0; +#endif + pCom->status |= HB_COM_OPEN; + } + hb_comSetOsError( pCom, iResult == -1 ); + } + } + + 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; + pCom->error = pCom->oserr ? HB_COM_ERR_OTHER : 0; +} + +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_comSetError( 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_OUT_1, MCR_OUT_2, 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 ) + { + fResult = SetCommBreak( pCom->hComm ); + if( fResult ) + { + Sleep( iDurationInMilliSecs ); + fResult = ClearCommBreak( pCom->hComm ); + } + hb_comSetOsError( pCom, !fResult ); + } + 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_DISABLE; + 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_DISABLE; + 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_comSetError( 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 = iXONchar; + if( iXOFFchar >= 0 ) + dcb.XoffChar = 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_comSetError( 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 = 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; +} + +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 ) + { + COMMTIMEOUTS timeouts; + + if( pCom->rdtimeout == 0 ) + { + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + } + else + { + timeouts.ReadIntervalTimeout = 0; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = ( DWORD ) pCom->rdtimeout; + } + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = ( DWORD ) HB_MAX( timeout, 1 ); + + if( SetCommTimeouts( pCom->hComm, &timeouts ) ) + { + pCom->wrtimeout = timeout; + lSent = 0; + } + else + hb_comSetOsError( pCom, HB_TRUE ); + } + else + lSent = 0; + + if( lSent >= 0 ) + { + DWORD dwWritten = 0;; + BOOL fResult; + + fResult = WriteFile( pCom->hComm, data, ( DWORD ) len, &dwWritten, NULL ); + lSent = fResult ? ( long ) dwWritten : -1; + hb_comSetOsError( pCom, !fResult ); + } + + 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 ) + { + COMMTIMEOUTS timeouts; + + if( timeout == 0 ) + { + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + } + else + { + timeouts.ReadIntervalTimeout = 0; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = ( DWORD ) timeout; + } + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = ( DWORD ) HB_MAX( pCom->wrtimeout, 1 ); + + if( SetCommTimeouts( pCom->hComm, &timeouts ) ) + { + pCom->rdtimeout = timeout; + lReceived = 0; + } + else + hb_comSetOsError( pCom, HB_TRUE ); + } + else + lReceived = 0; + + if( lReceived >= 0 ) + { + DWORD dwToRead = ( DWORD ) len; + DWORD dwRead = 0;; + BOOL fResult; + + fResult = ReadFile( pCom->hComm, data, dwToRead, &dwRead, NULL ); + lReceived = fResult ? ( long ) dwRead : -1; + hb_comSetOsError( pCom, !fResult ); + } + + 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; + else + iBaud = ( int ) dcb.BaudRate; + dcb.fBinary = 1; + dcb.fParity = 0; + dcb.fOutxCtsFlow = 0; + dcb.fOutxDsrFlow = 0; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + dcb.fDsrSensitivity = 0; + dcb.fTXContinueOnXoff = 1; + dcb.fOutX = 0; + dcb.fInX = 0; + dcb.fErrorChar = 0; + dcb.fNull = 0; + dcb.fRtsControl = RTS_CONTROL_DISABLE; + 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 ) + { + COMMTIMEOUTS timeouts; + + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 1; + + fResult = SetCommTimeouts( pCom->hComm, &timeouts ); + pCom->rdtimeout = pCom->wrtimeout = 0; + } + hb_comSetOsError( pCom, !fResult ); + } + else + hb_comSetError( 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 ) + { + /* FlushFileBuffers( pCom->hComm ); */ + fResult = CloseHandle( pCom->hComm ); + pCom->hComm = INVALID_HANDLE_VALUE; + pCom->status &= ~HB_COM_OPEN; + hb_comSetOsError( pCom, !fResult ); + } + + 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_comClose( iPort ); + + if( ( pCom->status & HB_COM_OPEN ) == 0 ) + { + char buffer[ HB_COM_DEV_NAME_MAX ]; + const char * szName = hb_comGetName( pCom, buffer, sizeof( buffer ) ); + TCHAR lpName[ HB_COM_DEV_NAME_MAX ]; + + HB_TCHAR_COPYTO( lpName, szName, HB_SIZEOFARRAY( lpName ) - 1 ); + + 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 ); + } + } + + 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; + pCom->error = rc != NO_ERROR ? HB_COM_ERR_OTHER : 0; +} + +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_OUT_1, MCR_OUT_2, 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; + + 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 ); + } + 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 | MODE_DCD_HANDSHAKE ); + 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_comSetError( 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_comSetError( 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_comSetError( 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; + } + + 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; + } + + 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 ) + { + /* DosResetBuffer( pCom->hFile ); */ + rc = DosClose( pCom->hFile ); + pCom->hFile = 0; + pCom->status &= ~HB_COM_OPEN; + hb_comSetOsError( pCom, rc ); + } + + 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_comClose( iPort ); + + if( ( pCom->status & HB_COM_OPEN ) == 0 ) + { + char buffer[ HB_COM_DEV_NAME_MAX ]; + const char * pszName = hb_comGetName( pCom, buffer, sizeof( buffer ) ); + ULONG ulAction = 0; + + rc = DosOpen( ( PSZ ) pszName, + &pCom->hFile, + &ulAction, + 0L, + FILE_NORMAL, + OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYREADWRITE, + 0L ); + if( rc == NO_ERROR ) + pCom->status |= HB_COM_OPEN; + + hb_comSetOsError( pCom, rc ); + } + } + + return ( rc == NO_ERROR ) ? 0 : -1; +} + +/* end of HB_OS_OS2 */ + +#else + +int hb_comInputCount( int iPort ) +{ + PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); + + if( pCom ) + hb_comSetError( pCom, HB_COM_ERR_NOSUPPORT ); + + return -1; +} + +int hb_comOutputCount( int iPort ) +{ + PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); + + if( pCom ) + hb_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( pCom, HB_COM_ERR_NOSUPPORT ); + + return -1; +} + +int hb_comOutputState( int iPort ) +{ + PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); + + if( pCom ) + hb_comSetError( pCom, HB_COM_ERR_NOSUPPORT ); + + return -1; +} + +int hb_comInputState( int iPort ) +{ + PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); + + if( pCom ) + hb_comSetError( 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_comSetError( 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_comSetError( 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_comSetError( pCom, HB_COM_ERR_NOSUPPORT ); + + return -1; +} + +int hb_comClose( int iPort ) +{ + PHB_COM pCom = hb_comGetPort( iPort, HB_COM_OPEN ); + + if( pCom ) + hb_comSetError( 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_comSetError( 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