|
|
/* ComSend -- Text sending routines for HyperACCESS
* * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI * All rights reserved * * $Revision: 8 $ * $Date: 7/12/02 10:45a $ */ #include <windows.h>
#pragma hdrstop
// #define DEBUGSTR
#include "stdtyp.h"
#include <tdll\assert.h>
#include "com.h"
#include "comdev.h"
#include "com.hh"
/* --- Internal prototypes --- */
static int ComSendCheck(const HCOM pstCom, const int fDataWaiting);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendChar * * DESCRIPTION: * Adds a character to the send buffer to be transmitted. The * character will not actually be transferred to the transmit * routines until the buffer fills up or a call to ComSendCharNow * is made or a call to ComSendPush is made while the transmitter * is not busy. * * ARGUMENTS: * pstCom -- handle to comm session * uchCode -- The character to be transmitted. * * RETURNS: * COM_OK if the character is successfully buffered. * COM_INVALID_HANDLE if invalid com handle * COM_SEND_BUFFER_FULL if the buffer is full and the * caller-supplied handshake function returns a code * indicating that waiting data should be discarded. */ int ComSendChar(const HCOM pstCom, const TCHAR chCode) { assert(ComValidHandle(pstCom));
while (pstCom->nSBufrSize > 0 && (pstCom->nSendCount >= pstCom->nSBufrSize)) { /* wait until there is room in buffer or we're told to give up. */ if (ComSendCheck(pstCom, TRUE) != COM_OK) return FALSE; if (pstCom->nSendCount >= pstCom->nSBufrSize) (void)ComSndBufrWait(pstCom, 2); }
/* Place char in buffer and assume it will get launched later. */
if(pstCom && &pstCom->puchSendPut) { *pstCom->puchSendPut++ = chCode; ++pstCom->nSendCount; } return TRUE; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendCharNow * * DESCRIPTION: Adds a character to the send buffer and then waits to make * sure the send buffer gets passed to the transmission routine. * This function does NOT wait until the character is actually * transmitted. Handshaking may still delay actual transmission * but no subsequent calls to any ComSend??? routines are needed * to get the character on its way. ComSendWait can be used to * wait until all characters are actually out the port. * * ARGUMENTS: pstCom -- handle to comm session * chCode -- The character to be transmitted. * * RETURNS: COM_OK if the character is successfully buffered and passed to * the transmission routines. * COM_INVALID_HANDLE if invalid com handle * COM_SEND_QUEUE_STUCK if the caller-supplied handshake function * returns a code indicating that waiting data should be * discarded before the buffer can be queued for transmission. */ int ComSendCharNow(const HCOM pstCom, const TCHAR chCode) { assert(ComValidHandle(pstCom));
while (pstCom->nSBufrSize > 0 && (pstCom->nSendCount >= pstCom->nSBufrSize)) { /* buffer is full, wait until there is room or we are
* told to give up */ if (ComSendCheck(pstCom, TRUE) != COM_OK) return FALSE; if (pstCom->nSendCount >= pstCom->nSBufrSize) ComSndBufrWait(pstCom, 2); }
if(pstCom && pstCom->puchSendPut) { *pstCom->puchSendPut++ = chCode; ++pstCom->nSendCount;
/* wait until local buffer is passed to SndBufr or we are
* told to give up */ while (pstCom->nSendCount > 0) { // This will pass buffer to SndBufr as soon as possible
if (ComSendCheck(pstCom, TRUE) != COM_OK) return FALSE; if (pstCom->nSendCount > 0) ComSndBufrWait(pstCom, 2); } } return TRUE; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendPush * * DESCRIPTION: This routine should be called periodically by any code that * uses ComSendChar() when there are no characters to be * transmitted immediately. Calling this function accomplishes * two things. * 1. It will cause any buffered send characters to be passed to the actual * transmission routines as soon as they are not busy. * 2. It will cause the caller-registered handshake handler function to be * called if transmission is suspended by handshaking. * * ARGUMENTS: pstCom -- handle to comm session * * RETURNS: same as ComSendCheck() */ int ComSendPush(const HCOM pstCom) { return ComSendCheck(pstCom, FALSE); }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendWait * * DESCRIPTION: This function waits until all buffered send data is actually * passed to the transmit hardware or until the handshake handling * function returns a code indicating that data should be discared. * * ARGUMENTS: pstCom -- handle to comm session * none * * RETURNS: COM_OK if all data has been transmitted. * COM_SEND_QUEUE_STUCK if a handshake handling function * indicated that data should be discarded. */ int ComSendWait(const HCOM pstCom) { assert(ComValidHandle(pstCom));
while (pstCom->nSendCount > 0 || ComSndBufrWait(pstCom, 2) != COM_OK) { if (ComSendCheck(pstCom, FALSE) != COM_OK) { return COM_SEND_QUEUE_STUCK; } } return COM_OK; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendClear * * DESCRIPTION: Clears all data waiting for tranmission, both in the local * ComSend buffer and the SndBufr buffer currently being * transmitted. * * ARGUMENTS: pstCom -- handle to comm session * * RETURNS: always returns COM_OK */ int ComSendClear(const HCOM pstCom) { assert(ComValidHandle(pstCom));
ComSndBufrClear(pstCom); pstCom->puchSendPut = pstCom->puchSendBufr; pstCom->nSendCount = 0; return COM_OK; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendSetStatusFunction * * DESCRIPTION: Registers a function to be called to handle handshaking status * displays, timeouts, etc. while sending. * * The registered function is called when it is registered, when it is being * replaced, and during sending when a handshaking suspension is detected. * Normally, the function is not called if transmission is not suspended. * After being called one or more times with a suspension, though, it will * be called one additional time after the suspension clears to allow the * function to clear any visible indicators. * * The registered function is passed the following arguments * usReason -- Contains a code indicating the reason the function * was called. It will be one of: * COMSEND_FIRSTCALL -- if function is being installed * COMSEND_LASTCALL -- if function is being replaced * COMSEND_DATA_WAITING -- if there is data waiting * that will not fit in the send buffer. * COMSEND_NORMAL -- if called due to handshake * condition but no data is in danger of being lost. * fusHsStatus -- A value contining bits which indicate what transmission * is waiting for. The bits are defined in com.h as * COMSB_WAIT_XXX. * lDelay -- The amount of time in tenths of seconds since * transmission was suspended. This time will not * begin incrementing until there is data to transmit. * * The registered function should return a value indicating what action the * ComSend routines should take regarding handshake suspensions: * COMSEND_OK no action, if data is waiting, keep waiting * COMSEND_GIVEUP if data is waiting, discard it and return * from ComSend??? call. * COMSEND_CLEAR_DATA discard all transmit buffers, this discards * any data waiting in a ComSend command * AND any data previously buffered. * COMSEND_FORCE_CONTINUATION force data to be transmitted, if waiting * for XON, pretend it was received. If * waiting for hardware handshake, disable * it. ComSend routine will continue trying * to send any waiting data. * * ARGUMENTS: pstCom -- handle to comm session * pfNewStatusFunct -- A pointer to a function matching the specs * described above or NULL if a default, do-nothing function * should be used. If the default function is used, ComSend * commands will essentially wait forever to send data. * ppfOldStatusFunct -- Address of pointer to put the pointer to * the previously registered function * * RETURNS: COM_OK if everything went ok * COM_INVALID_HANDLE if invalid com handle */ int ComSendSetStatusFunction(const HCOM pstCom, STATUSFUNCT pfNewStatusFunct, STATUSFUNCT *ppfOldStatusFunct) {
STATUSFUNCT pfHold = pstCom->pfUserFunction; unsigned afXmitStatus; long lHandshakeDelay;
assert(ComValidHandle(pstCom));
/* If user want's no status function, use an internal function to
* avoid constant checks for null */ if (pfNewStatusFunct == NULL) { pfNewStatusFunct = ComSendDefaultStatusFunction; }
if (pfNewStatusFunct != pfHold) { ComSndBufrQuery(pstCom, &afXmitStatus, &lHandshakeDelay);
/* call old function to give it a change to clear up details */ (void)(*pfHold)(COMSEND_LASTCALL, afXmitStatus, lHandshakeDelay);
/* call new function so it can initialize */ pstCom->pfUserFunction = pfNewStatusFunct; (void)(*(pstCom->pfUserFunction))(COMSEND_FIRSTCALL, afXmitStatus, lHandshakeDelay); }
if (ppfOldStatusFunct) *ppfOldStatusFunct = pfHold;
return COM_OK; }
/* * * * * * * * * * * *
* Private functions * * * * * * * * * * * * */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendDefaultStatusFunction * * DESCRIPTION: This function is used as the handshake handling function when * no caller-supplied function is available, that is, at program * start up or when the caller registeres the NULL function. * * ARGUMENTS: See description of handler in ComSendSetStatusFunction * * RETURNS: See description of handler in ComSendSetStatusFunction */ int ComSendDefaultStatusFunction(int iReason, unsigned afHsStatus, long lDelay) { /* suppress complaints from lint and the compiler */ iReason = iReason; afHsStatus = afHsStatus; lDelay = lDelay;
/* This function does nothing, it is here to have something to point
* pfUserFunction to when ComSendSetStatusFunction is called with * NULL argument. */ return COM_OK; }
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendCheck * * DESCRIPTION: This function is used internally to keep the flow of * transmitted data moving. It handles setting up and calling the * handshake handling functions and getting the local transmit * buffer passed to the SndBufr routines when they are ready. * * ARGUMENTS: pstCom -- handle to comm session * fDataWaiting -- TRUE if being called by a function that has * data to place in the send buffer when the buffer is full. * * RETURNS: COM_OK if the calling function should continue waiting for * space in the transmit buffer. * COM_INVALID_HANDLE if invalid com handle * COM_SEND_QUEUE_STUCK if the calling function should discard * any unbuffered data and return. */ static int ComSendCheck(const HCOM pstCom, const int fDataWaiting) { int fResult = TRUE; unsigned afXmitStatus; long lHandshakeDelay;
if (ComSndBufrBusy(pstCom) != COM_OK) { ComSndBufrQuery(pstCom, &afXmitStatus, &lHandshakeDelay);
if (afXmitStatus != 0) { switch((*(pstCom->pfUserFunction))(fDataWaiting ? COMSEND_DATA_WAITING : COMSEND_NORMAL, afXmitStatus, lHandshakeDelay)) { case COMSEND_OK: break;
case COMSEND_GIVEUP: fResult = FALSE; break;
case COMSEND_CLEAR_DATA: ComSendClear(pstCom); fResult = FALSE; break;
#if 0 //* this should be replaced with a more general mechanism
case COMSEND_FORCE_CONTINUATION: if (bittest(afXmitStatus, COMSB_WAIT_XON)) ComSendXon(pstCom); else if (bittest(afXmitStatus, (COMSB_WAIT_CTS | COMSB_WAIT_DSR | COMSB_WAIT_DCD))) { // TODO: this will be replaced by ComSndBufrForce or such
// (VOID)ComDisableHHS(pstCom);
} else if (bittest(afXmitStatus, COMSB_WAIT_BUSY)) { ComSendClear(pstCom); fResult = FALSE; } break; #endif
default: assert(FALSE); break; }
pstCom->fUserCalled = TRUE; } else if (pstCom->fUserCalled) { (void)(*(pstCom->pfUserFunction))(COMSEND_NORMAL, 0, 0L); pstCom->fUserCalled = FALSE; } } else { int rc = COM_OK;
if (pstCom->nSendCount > 0) { rc = ComSndBufrSend(pstCom, pstCom->puchSendBufr, pstCom->nSendCount, 1);
assert(rc == COM_OK);
if (rc == COM_OK) { pstCom->puchSendBufr = pstCom->puchSendPut = ((pstCom->puchSendBufr == pstCom->puchSendBufr1) ? pstCom->puchSendBufr2 : pstCom->puchSendBufr1); pstCom->nSendCount = 0; } else if (rc == COM_PORT_NOT_OPEN) { #if !defined(NDEBUG)
MessageBox(NULL, "Attempting to send data when not connected. Unable to send data.", NULL, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL); #endif // !defined(NDEBUG)
//
// TODO:REV 4/26/2002 We need to disconnect here with loss of carrier.
//
//NotifyClient(pstCom->hSession, EVENT_LOST_CONNECTION,
// CNCT_LOSTCARRIER | (sessQueryExit(pstCom->hSession) ? DISCNCT_EXIT : 0 ));
ComSendClear(pstCom); fResult = FALSE; } }
if (pstCom->fUserCalled) { (void)(*(pstCom->pfUserFunction))(COMSEND_NORMAL, 0, 0L); pstCom->fUserCalled = FALSE; } }
return(fResult ? COM_OK : COM_SEND_QUEUE_STUCK); }
/********************** end of comsend.c ***********************/
|