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