view src/gpf2/tst/drv/usart.c @ 581:a0a45c5eb3ef

gsmcomp.c: bumping trace partition size to 220 like in gprscomp.c This change is safe in terms of RAM usage because all of these partition pools have already been moved from XRAM to IRAM earlier, and our IRAM usage in VO configs is currently quite low - the one near the limit is XRAM on C11x.
author Mychaela Falconia <falcon@freecalypso.org>
date Tue, 29 Jan 2019 03:52:49 +0000
parents cd37d228dae0
children
line wrap: on
line source

/* 
+------------------------------------------------------------------------------
|  File:       usart.c
+------------------------------------------------------------------------------
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 The receipt of or possession of this file does not convey 
|                 any rights to reproduce or disclose its contents or to 
|                 manufacture, use, or sell anything it may describe, in 
|                 whole, or in part, without the specific written consent of 
|                 Texas Instruments Berlin, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  This Modul defines functions for actual or simulated 
|             USART comunication between two PS-Frames.
|             Use US_set_mode() to select actual USART under windows95 or 
|             under windowsNT, or to select simulated USART under win95/NT
+----------------------------------------------------------------------------- 
*/ 



#ifndef __USART_C__
#define __USART_C__
#endif

/*==== INCLUDES ===================================================*/

 #include <windows.h>
#ifndef _VXWORKS_
  #include <stdarg.h>
#endif
#include <stdio.h>
#include "typedefs.h"
#include "usart.h"
#include "printtofile.h"

/*==== CONSTANTS ==================================================*/

#define COM_ERROR		(CE_FRAME | CE_IOE | CE_OVERRUN)
#define XON				0x11
#define XOFF			0x13

#define READER_THREAD_EXIT_CODE 4711
#define USART_BUFFER_SIZE       0x10000   /* 65536 */
#define FILE_MAX_CHUNK          0x0ffff
#define FILE_SLOW_DOWN          0x01

#ifdef _TOOLS_ 
  #define USART_SEND_TIMEOUT 60000
  #define USART_RCV_TIMEOUT 120000
#else  /* _TOOLS_ */
  #define USART_SEND_TIMEOUT INFINITE
  #define USART_RCV_TIMEOUT INFINITE
#endif /* _TOOLS_ */

/*==== TYPES ======================================================*/
typedef struct
{
  UBYTE  Connects;
  UBYTE  Type;
  USHORT CH1_numOfBytes;
  USHORT CH2_numOfBytes;
  UBYTE  CH1_CTS;
  UBYTE  CH2_CTS;
  UBYTE  CH1_data[USART_BUFFER_SIZE];
  UBYTE  CH2_data[USART_BUFFER_SIZE];
} T_USARTStream;

/*==== EXPORT =====================================================*/
/*==== PRIVATE ====================================================*/
/*==== VARIABLES ==================================================*/

static int       m_mode=UT_MODE_NT;
static long int  m_send_timeout=(long int)USART_SEND_TIMEOUT;
static long int  m_rcv_timeout =(long int)USART_RCV_TIMEOUT;
static int first_ut_init = 1;
static FILE*     m_file=NULL;

static OVERLAPPED gWriteOverLap;
static OVERLAPPED gReadOverLap;

static  int   ReaderThreadExitRequest = FALSE;


LOCAL   void  (*ReceiveCallback)(void) = NULL;
static  int   initialized = FALSE;

#ifdef COM_AUTOSEARCH
static  int   P  = 0;
#endif

#ifdef DEBUG_USART
static  int   usart_in, usart_out;
#endif

T_USARTStream *Stream;

HANDLE         SemCH1_full;
HANDLE         SemCH2_full;
HANDLE         SemCH1_empty;
HANDLE         SemCH2_empty;
HANDLE         USARTMemHandle;
HANDLE         *semRCVFull=0, *semRCVEmpty=0;
HANDLE         *semSNDFull=0, *semSNDEmpty=0;
HANDLE         ut_sema_handle;

UBYTE          *InBuffer, *OutBuffer, *readPointer;
USHORT         *InCounter, *OutCounter;
UBYTE          *CTS = NULL;


static HANDLE hComDev = INVALID_HANDLE_VALUE;
static HANDLE hThread = INVALID_HANDLE_VALUE;
static int mem_closed = TRUE;
static int cls_cnt = 0;
static int snd_cnt = 0;

/*==== FUNCTIONS ==================================================*/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USART                  |
| STATE   : code                    ROUTINE : US_set_mode            |
+--------------------------------------------------------------------+

  PURPOSE : With this function you can select the UART mode 
                #define US_MODE_95         1
                #define US_MODE_NT         2
                #define US_MODE_SIM        3  
                #define US_MODE_FILE       4
  
*/
void US_set_mode(int mode)
{
  m_mode=mode;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USART                  |
| STATE   : code                    ROUTINE : US_set_mode            |
+--------------------------------------------------------------------+

  PURPOSE : With this function get the seleced UART mode  
                #define US_MODE_95         1
                #define US_MODE_NT         2
                #define US_MODE_SIM        3  
                #define US_MODE_FILE       4
*/
int US_get_mode()
{
  return m_mode;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USARTSIM               |
| STATE   : code                    ROUTINE : unlockUSARTMemory      |
+--------------------------------------------------------------------+

  PURPOSE : unlocks the previously locked shared memory area.
  
*/
LOCAL void markRCVBufferEmpty (void)
{
  ReleaseSemaphore (*semRCVEmpty,
                    1,
                    NULL);
}

LOCAL void markSNDBufferFull (void)
{
  ReleaseSemaphore (*semSNDFull,
                    1,
                    NULL);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USARTSIM               |
| STATE   : code                    ROUTINE : waitForSNDBufferEmpty  |
+--------------------------------------------------------------------+

  PURPOSE : waits for send buffer becoming empty

  RETURNS :  0 .. send buffer is empty
            -1 .. given up

*/
LOCAL int waitForSNDBufferEmpty (void)
{
  if (WaitForSingleObject (*semSNDEmpty, m_send_timeout) NEQ WAIT_OBJECT_0)
  {
    int err = GetLastError();
    PrintToFile("USART: error code %d\n", err);
    PrintToFile("USART: giving up sending with %d ms timeout :-(\n", m_send_timeout);
    return -1; /* give up */
  }
  return 0;
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USARTSIM               |
| STATE   : code                    ROUTINE : createUSARTMemory      |
+--------------------------------------------------------------------+

  PURPOSE : Create two pipes for byte oriented data exchange
            between two win32 processes

*/

LOCAL void *createUSARTMemory (char *name, ULONG size)
{
  char newname[40];

  /*
   * create two Semaphores pairs to protect the send data to be
   * overwritten before they have read by the receiver
   */

  sprintf (newname, "%s_CH1empty", name);
  
  SemCH1_empty = CreateSemaphore (NULL,
                                  1,                               
                                  1,                           
                                  newname);
     
  if (SemCH1_empty EQ NULL)
    return NULL;

  sprintf (newname, "%s_CH1full", name);
  
  SemCH1_full = CreateSemaphore (NULL,
                                 0,                               
                                 1,                           
                                 newname);
     
  if (SemCH1_full EQ NULL)
    return NULL;

  sprintf (newname, "%s_CH2empty", name);
  
  SemCH2_empty = CreateSemaphore (NULL,
                                  1,                               
                                  1,                           
                                  newname);
     
  if (SemCH2_empty EQ NULL)
    return NULL;

  sprintf (newname, "%s_CH2full", name);
  
  SemCH2_full = CreateSemaphore (NULL,
                                 0,                               
                                 1,                           
                                 newname);
     
  if (SemCH2_full EQ NULL)
    return NULL;

  /*
   * create a shared memory area
   */
  sprintf (newname, "UT_Mem_%s", name);

  USARTMemHandle
      = CreateFileMapping (
                           (HANDLE) 0xffffffff,  /* memory-mapped     */
                            NULL,                /* no security       */
                            PAGE_READWRITE,      /* read/write access */
                           (DWORD) 0,
     /* memory size     */ (DWORD) size,
                           newname           /* name of sh. mem */
                          ); 
  
  if (USARTMemHandle EQ NULL)
    return NULL;
 
  /*
   * map the shared memory area into the address space of the process
   * and return the startaddress.
   */
  
  return MapViewOfFile (USARTMemHandle,
                        FILE_MAP_WRITE,
                        0,
                        0,
                        0);
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USARTSIM               |
| STATE   : code                    ROUTINE : openUSARTMemory        |
+--------------------------------------------------------------------+

  PURPOSE : open a shared memory area for character exchange
            between two WIN32 processes

*/

LOCAL void *openUSARTMemory (char *name, ULONG size)
{
  char newname[30];

  /*
   * open the Semaphores
   */

  sprintf (newname, "%s_CH1empty", name);

  SemCH1_empty = OpenSemaphore (SEMAPHORE_MODIFY_STATE
                                | SYNCHRONIZE,
                                FALSE,
                                newname);
     
  if (SemCH1_empty EQ NULL)
    return NULL;

  sprintf (newname, "%s_CH1full", name);

  SemCH1_full =  OpenSemaphore (SEMAPHORE_MODIFY_STATE
                                | SYNCHRONIZE,
                                FALSE,
                                newname);
     
  if (SemCH1_full EQ NULL)
    return NULL;

  sprintf (newname, "%s_CH2empty", name);

  SemCH2_empty = OpenSemaphore (SEMAPHORE_MODIFY_STATE
                                | SYNCHRONIZE,
                                FALSE,
                                newname);
     
  if (SemCH2_empty EQ NULL)
    return NULL;

  sprintf (newname, "%s_CH2full", name);

  SemCH2_full =  OpenSemaphore (SEMAPHORE_MODIFY_STATE
                                | SYNCHRONIZE,
                                FALSE,
                                newname);
     
  if (SemCH2_full EQ NULL)
    return NULL;

  /*
   * open the shared memory area
   */
  
  sprintf (newname, "UT_Mem_%s", name);

  USARTMemHandle =
    OpenFileMapping (FILE_MAP_WRITE,
                     FALSE,
                     newname);  /* name of sh. mem */
                 
  
  if (USARTMemHandle EQ NULL)
    return NULL;
 
  /*
   * map the shared memory area into the address space of the process
   * and return the startaddress.
   */
  
  return MapViewOfFile (USARTMemHandle,
                        FILE_MAP_WRITE,
                        0,
                        0,
                        0);
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USART                  |
| STATE   : code                    ROUTINE : waitForRCVBufferFull   |
+--------------------------------------------------------------------+

  PURPOSE : This function waits until an incoming character
            is signaled with the EV_RXCHAR Event 
  
*/

LOCAL void waitForRCVBufferFull (void)
{
  switch (m_mode) {
    case US_MODE_95: {
      static COMSTAT stComStat;
      static DWORD   dwErrors;
      static DWORD   EvtMask = 0;
      BOOL    validReceive = FALSE;

      do
      {
        SetCommMask (hComDev, EV_RXCHAR) ;
        WaitCommEvent (hComDev, &EvtMask, NULL);
        ClearCommError (hComDev, &dwErrors, &stComStat);
  
        if (dwErrors & COM_ERROR)
          PurgeComm (hComDev, PURGE_RXCLEAR|PURGE_RXABORT);
        else
          validReceive = TRUE;

      } while (!validReceive);
      break;
    }
    case US_MODE_NT: {
      static COMSTAT stComStat;
      static DWORD   dwErrors;
      static DWORD   EvtMask = 0;
      BOOL    validReceive = FALSE;

      do
      {
        SetCommMask (hComDev, EV_RXCHAR) ;
        WaitCommEvent (hComDev, &EvtMask, NULL);
        ClearCommError (hComDev, &dwErrors, &stComStat);

        if (dwErrors & COM_ERROR)
          PurgeComm (hComDev, PURGE_RXCLEAR|PURGE_RXABORT);
        else
          validReceive = TRUE;

      } while (!validReceive && !ReaderThreadExitRequest);
      break;
    }
    case US_MODE_SIM: {
      if (WaitForSingleObject (*semRCVFull, m_rcv_timeout) NEQ WAIT_OBJECT_0)
      {
        PrintToFile("USART: no stack connected\n");
      }
      break;
    }
    default:
      break;
  }
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USART                  |
| STATE   : code                    ROUTINE : _readerThread          |
+--------------------------------------------------------------------+

  PURPOSE : This function is the central signal handling function. It is
            installed as a thread and waits for the occurance of an
            event and then calls the installed callback function
            of the application.
  
*/

LOCAL void _readerThread (void)
{
  while (ReaderThreadExitRequest == FALSE)
  {
    waitForRCVBufferFull ();
    ReceiveCallback ();
  } 
  ReaderThreadExitRequest = FALSE;
  ExitThread(READER_THREAD_EXIT_CODE);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USART                  |
| STATE   : code                    ROUTINE : convertBaudrate        |
+--------------------------------------------------------------------+

  PURPOSE : This function convert the constants for the baudrates in
            usart.h into the equvalent constants for WIN32 comm.
        
*/
LOCAL DWORD convertBaudrate (DWORD br)
{   
  switch (br)
  {
    case US_BAUD_256000:
      return CBR_256000;

    case US_BAUD_128000:
      return CBR_128000;

    case US_BAUD_115200:
      return CBR_115200;

    case US_BAUD_57600:
      return CBR_57600;

    case US_BAUD_38400:
      return CBR_38400;
    
    case US_BAUD_19200:
      return CBR_19200;

    case US_BAUD_14400:
      return CBR_14400;

    case US_BAUD_9600:
      return CBR_9600;

    case US_BAUD_4800:
      return CBR_4800;

    case US_BAUD_2400:
      return CBR_2400;

    case US_BAUD_1200:
      return CBR_1200;

    case US_BAUD_600:
      return CBR_600;

    case US_BAUD_300:
      return CBR_300;

    default:
      /* no CBR_xxx constant found -> return value itsself */
      return br;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)           MODULE  : USART                  |
| STATE   : code                    ROUTINE : sioInit                |
+--------------------------------------------------------------------+

  PURPOSE : This function opens the given comm port and initiializes
            the DCB with baudrate and flowcontrol parameters.
        
*/

LOCAL BOOL sioInit (int  portNr,
                    unsigned int  baudrate,
                    unsigned int  bufSize,
                    char flowCtrl)
{
  char         szPort[10];
  DCB          stDCB;
  COMMTIMEOUTS stTimeout ;
  DWORD        dwErrorFlags;
  COMSTAT      stComStat;

  sprintf (szPort, "\\\\.\\COM%d", portNr) ;

  // ------------------------------------
  // open the communication device
  // ------------------------------------
  if (m_mode==UT_MODE_NT) {
    hComDev = CreateFile
            ( 
              szPort,
              GENERIC_READ | GENERIC_WRITE,
              0,                       /* exclusive access  */
              NULL,                    /* no security attrs */
              OPEN_EXISTING,
              FILE_FLAG_OVERLAPPED,
              NULL
            );
  } else {
    hComDev = CreateFile
            ( 
              szPort,
              GENERIC_READ | GENERIC_WRITE,
              0,                       // exclusive access
              NULL,                    // no security attrs
              OPEN_EXISTING,
              0,
              NULL
            );
  }

  if (hComDev EQ INVALID_HANDLE_VALUE)
    return FALSE;   // device not available

  if (m_mode==UT_MODE_NT) {
    gReadOverLap.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
    if (!gReadOverLap.hEvent)
	    return ( FALSE );

    gReadOverLap.Offset = 0;
    gReadOverLap.OffsetHigh = 0;

    gWriteOverLap.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
    if (!(gWriteOverLap.hEvent))
	    return ( FALSE );

    gWriteOverLap.Offset = 0;
    gWriteOverLap.OffsetHigh = 0;
  }

  // ------------------------------------
  // get any early notifications
  // ------------------------------------
  SetCommMask (hComDev, EV_RXCHAR);

  // ------------------------------------
  // setup device buffers
  // ------------------------------------
  SetupComm (hComDev,
             bufSize,
             bufSize
            );

  // ------------------------------------
  // purge any information in the buffer
  // ------------------------------------
  PurgeComm (hComDev,
             PURGE_TXABORT | PURGE_RXABORT |
             PURGE_TXCLEAR | PURGE_RXCLEAR
            );

  // ------------------------------------
  // setup up and enable communication
  // device. If not possible close
  // communication and abort function.
  // ------------------------------------
  if (!GetCommState (hComDev, &stDCB))
  {
    SetCommMask (hComDev, 0);
    CloseHandle (hComDev);
    return FALSE;
  }

  stDCB.DCBlength = sizeof (stDCB);  // sizeof(DCB) 

  switch (flowCtrl)
  {
    case 'N':
      stDCB.fOutxCtsFlow = FALSE;
      stDCB.fOutxDsrFlow = FALSE;
      stDCB.fDtrControl = DTR_CONTROL_DISABLE;
      stDCB.fRtsControl = RTS_CONTROL_DISABLE;
      break;
    case 'D':
      stDCB.fOutxCtsFlow = FALSE;
      stDCB.fOutxDsrFlow = TRUE;
      stDCB.fDtrControl = DTR_CONTROL_HANDSHAKE;
      stDCB.fRtsControl = RTS_CONTROL_DISABLE;
      stDCB.XonLim  = 0;
      stDCB.XoffLim = 50;
      break;
    case 'R':
      stDCB.fOutxCtsFlow = TRUE;
      stDCB.fOutxDsrFlow = FALSE;
      stDCB.fDtrControl = DTR_CONTROL_DISABLE;
      stDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
      stDCB.XonLim  = 0;
      stDCB.XoffLim = 50;
      break;
    case 'P':
      stDCB.fOutxCtsFlow = FALSE;
      stDCB.fOutxDsrFlow = FALSE;
      stDCB.fDtrControl = DTR_CONTROL_ENABLE;
      stDCB.fRtsControl = RTS_CONTROL_DISABLE;
      break;
    case 'V':
      if (m_mode==US_MODE_NT) {
        stDCB.fOutxCtsFlow = FALSE;
        stDCB.fOutxDsrFlow = FALSE;
        stDCB.fDtrControl = DTR_CONTROL_ENABLE;
        stDCB.fRtsControl = RTS_CONTROL_ENABLE;
        break;
      }
      /*lint -fallthrough*/
      /* go on if not US_MODE_NT */
    default:
      return FALSE;
  }
  fprintf (stdout,"flow control: %c ...", flowCtrl);

  stDCB.BaudRate          = baudrate;  // current baud rate 
  stDCB.fBinary           = TRUE;      // binary mode, no EOF check 
  stDCB.fParity           = FALSE;     // enable parity checking 
  stDCB.fDsrSensitivity   = FALSE;     // DSR sensitivity 
  stDCB.fTXContinueOnXoff = FALSE;     // XOFF continues Tx 
  stDCB.fOutX             = FALSE;     // XON/XOFF out flow control 
  stDCB.fInX              = FALSE;     // XON/XOFF in flow control 
  stDCB.fErrorChar        = FALSE;     // enable error replacement 
  stDCB.fNull             = FALSE;     // enable null stripping 
  stDCB.fAbortOnError     = FALSE;     // abort reads/writes on error 
  stDCB.ByteSize          = 8;         // number of bits/byte, 4-8 
  stDCB.Parity            = NOPARITY;  // 0-4=no,odd,even,mark,space 
  stDCB.StopBits          = ONESTOPBIT;// 0,1,2 = 1, 1.5, 2 
  stDCB.XonChar           = 0;         // Tx and Rx XON character 
  stDCB.XoffChar          = 0;         // Tx and Rx XOFF character 
  stDCB.ErrorChar         = 0;         // error replacement character 
  stDCB.EofChar           = 0;         // end of input character 
  stDCB.EvtChar           = 0;         // received event character 

  if (!SetCommState (hComDev, &stDCB))
  {
    SetCommMask (hComDev, 0);
    CloseHandle (hComDev);
    return FALSE;
  }

  if (!GetCommTimeouts (hComDev, &stTimeout))
    return FALSE;

  stTimeout.WriteTotalTimeoutConstant   = 0xffff;
  stTimeout.WriteTotalTimeoutMultiplier = 0xffff;
  stTimeout.ReadTotalTimeoutConstant    = 0xffff;
  stTimeout.ReadIntervalTimeout         = 0;
  stTimeout.ReadTotalTimeoutMultiplier  = 0xffff;

  if (!SetCommTimeouts (hComDev, &stTimeout))
    return FALSE;

  PurgeComm (hComDev, PURGE_RXCLEAR
                     |PURGE_TXCLEAR
                     |PURGE_TXABORT
                     |PURGE_RXABORT);

  ClearCommError (hComDev, &dwErrorFlags, &stComStat);

  return TRUE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : sioRead                    |
+--------------------------------------------------------------------+

  PURPOSE : 

*/

LOCAL BOOL sioRead (BYTE  *bpRXBuffer, // RX Buffer
                    DWORD *pdwLength)  // IN:  Bytes to read
{
  DWORD   dwBytesToRead = *pdwLength ;
  DWORD   dwErrorFlags;
  COMSTAT stComStat;

  if (hComDev == INVALID_HANDLE_VALUE
    OR *pdwLength == 0) 
    return FALSE;  // device not available

  if (m_mode==US_MODE_NT) {
    if (!ReadFile (hComDev,
                 bpRXBuffer,
                 dwBytesToRead,
                 pdwLength,
                 &gReadOverLap))
    {
      // if there was a problem
		  if (GetLastError() == ERROR_IO_PENDING)
   	  {
	  	  /* asynchronous i/o is still in progress         */
		
   			/* do something else for a while                 */
	   		/* check on the results of the asynchronous read */
	    	if (GetOverlappedResult(gReadOverLap.hEvent, &gReadOverLap, 
	    		pdwLength, TRUE))
			    return TRUE;
      }

      ClearCommError(hComDev, &dwErrorFlags, &stComStat);
      return FALSE;
    } else {
      ClearCommError(hComDev, &dwErrorFlags, &stComStat);
    }
  } else {
    if (!ReadFile (hComDev,
                 bpRXBuffer,
                 dwBytesToRead,
                 pdwLength,
                 NULL))
    {
      // if there was a problem
      ClearCommError(hComDev, &dwErrorFlags, &stComStat);
      return FALSE;
    }
  }
#ifdef DEBUG_USART
  {
    char traceBuf[255];
    unsigned int  i;

    traceBuf[0] = '\0';

    if (bpRXBuffer[0] EQ 0xff)
    {
      Sleep(1);
    }

    for (i=0; i<*pdwLength; i++)
    {
      if (!isprint (bpRXBuffer[i]))
      {
        sprintf (traceBuf+strlen(traceBuf),
                 "[%02x]%c",
                 (USHORT) bpRXBuffer[i],
                 ((bpRXBuffer[i] EQ '\n') ? '\n' : ' ')
                 );
      }
      else
        sprintf (traceBuf+strlen(traceBuf),
                 "%c",
                 bpRXBuffer[i]);
      if (strlen (traceBuf) > 200)
      {
        write (usart_in, traceBuf, strlen (traceBuf));
        traceBuf[0] = '\0';
      }
    }
    /*
     * write the string to the tracefile
     */
    write (usart_in, traceBuf, strlen (traceBuf));
  }
#endif
  return TRUE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : sioWrite                   |
+--------------------------------------------------------------------+

  PURPOSE : 

*/

LOCAL BOOL sioWrite (BYTE  *bpTXBuffer, // TX   Buffer
                     DWORD *pdwLength)  // IN:  Bytes to read
{
  DWORD   dwBytesToSend = *pdwLength, toSend, realySend;
  int     ret;
  DWORD   dwErrorFlags;
  COMSTAT stComStat;
  DWORD   dwNumberOfBytesTransferred;   /* Windows 95:                                       */
                                        /* The number of transferred bytes returned by the   */
                                        /* GetOverlappedResult function is always zero, also */
                                        /* if there are bytes received by the communication  */ 
                                        /* partner via the serial line.                      */

  if (hComDev EQ INVALID_HANDLE_VALUE
    OR !bpTXBuffer
    OR *pdwLength ==0)
     return FALSE; // device not available

  realySend = 0;
  toSend    = dwBytesToSend;

  while (toSend > 0)
  {
    if (m_mode==US_MODE_NT) {
    	if (toSend > 20) {
	    	ret = WriteFile (hComDev,
                       bpTXBuffer+realySend,
                       20,
                       pdwLength,
                       &gWriteOverLap);
		    dwNumberOfBytesTransferred = 20;     
  	  } else {
  		  ret = WriteFile (hComDev,
                       bpTXBuffer+realySend,
                       toSend,
                       pdwLength,
                       &gWriteOverLap);
		    dwNumberOfBytesTransferred = toSend;
	    }
    	/* if there was a problem, or the async. operation's still pending ... */
	    if (!ret)
  	  {
  	  	/* deal with the error code */
	  	  if (GetLastError() == ERROR_IO_PENDING)
  	  	{
	  	  	/* asynchronous i/o is still in progress         */
		
  		  	/* do something else for a while                 */
	  		  /* check on the results of the asynchronous read */
  		  	while (!GetOverlappedResult(gWriteOverLap.hEvent, &gWriteOverLap, pdwLength, TRUE))
	    		{
			    	if(GetLastError() == ERROR_IO_INCOMPLETE) {
    					continue;
            } else {
				    	break ;
            }
      		}
		    } else {
			    ClearCommError(hComDev, &dwErrorFlags, &stComStat);
    			return FALSE;
		    }
      }
    } else {
      if (toSend > 20) {
        ret = WriteFile (hComDev,
                       bpTXBuffer+realySend,
                       20,
                       pdwLength,
                       NULL);
        dwNumberOfBytesTransferred = 20; /* US_MODE_NT */
      } else {
        ret = WriteFile (hComDev,
                       bpTXBuffer+realySend,
                       toSend,
                       pdwLength,
                       NULL);
  	    dwNumberOfBytesTransferred = toSend; /* US_MODE_NT */
      }
    }

#ifdef DEBUG_USART
    {
      char traceBuf[255];
      unsigned int  i;

      traceBuf[0] = '\0';

      for (i=0; i<*pdwLength; i++)
      {
        if (!isprint (bpTXBuffer[realySend+i]))
        {
          sprintf (traceBuf+strlen(traceBuf),
                   "[%02x]%c",
                   (USHORT) bpTXBuffer[realySend+i],
                   ((bpTXBuffer[realySend+i] EQ '\n') ? '\n': ' ')
                   );
        }
        else
          sprintf (traceBuf+strlen(traceBuf),
                   "%c",
                   bpTXBuffer[realySend+i]);
        if (strlen (traceBuf) > 200)
        {
          write (usart_out, traceBuf, strlen (traceBuf));
          traceBuf[0] = '\0';
        }
      }
      /*
       * write the string to the tracefile
       */
      write (usart_out, traceBuf, strlen (traceBuf));
    }
#endif

    switch (m_mode) {
      case US_MODE_NT:
       	realySend += dwNumberOfBytesTransferred;
      	toSend    -= dwNumberOfBytesTransferred;
        break;
      case US_MODE_95:
        realySend += *pdwLength;
        toSend    -= *pdwLength;
        break;
      default:
        break;
    }
  }

  *pdwLength = dwBytesToSend;

  return TRUE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : UT_Init                    |
+--------------------------------------------------------------------+

  PURPOSE : initializes the USART driver

  RETURNS : 0 ... initialization succeeded
           -1 ... error

*/


int UT_Init (unsigned int baudRate, int fifoSize, char flow_ctrl, void (func(void)), const char* fname )
{
  if (initialized == TRUE)
  {
		return 0;
  }

  switch (m_mode) 
  {
    case US_MODE_FILE:
      if (!fname || !strlen(fname) || (m_file=fopen(fname,"rb"))==NULL)
      {
        fprintf (stdout, "USART: failed to open %s :-(\n",fname);
        return -1;
      }
      fprintf (stdout, "USART: \"%s\" opened\n",fname);
      break;
    case US_MODE_95:
    case US_MODE_NT: {
      BOOL   ret;
      DWORD  dwThreadID;
#ifdef COM_AUTOSEARCH
      int    from, to;
      int portNr;
#else
      EXTERN int extPort;
#endif

      ReceiveCallback = func;

#ifdef COM_AUTOSEARCH
      if (P NEQ 0) {
        from = to = P;
      } else {
        from = 1;
        to = 4;
      }

      /*
       * try COMn: to COMm: where n is from and m is to
      */
      for (portNr = from; portNr <= to; portNr++)
      {
        fprintf (stdout,"USART: Trying COM%d ... ", portNr);

        if ((ret = sioInit (portNr,
                        convertBaudrate (baudRate),
                        10000 /*fifoSize*/,
                        flow_ctrl)) EQ FALSE) {
          fprintf (stdout, "fail\n");
        } else {
          fprintf (stdout, "success!\n");
          break;
        }
      }

#else
      fprintf (stdout, "USART: Trying COM%d ... ", extPort);

      if ((ret = sioInit (extPort,
                        convertBaudrate (baudRate),
                        10000 /*fifoSize*/,
                        flow_ctrl)) EQ FALSE) {
        fprintf (stdout, "fail\n");
      }
#endif

      if (ret)
      {
        fprintf (stdout, "success!\n");

        if (ReceiveCallback NEQ NULL)
        {
          hThread = CreateThread ((LPSECURITY_ATTRIBUTES) NULL,
                              0,
                              (LPTHREAD_START_ROUTINE) _readerThread,
                              (LPVOID) NULL,
                               0,
                              &dwThreadID
                             );
        }
        initialized = TRUE;
      }
      else {
        fprintf (stdout, "USART: COM-port not free or baudrate not supported !\n");
        return -1;
      }
      break;  
    }

    case US_MODE_SIM: {
      int    i;

      if ( first_ut_init )
      {
        if ( (ut_sema_handle = OpenSemaphore (SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, FALSE, "UT_SIM_SEMA")) == NULL )
        {
          ut_sema_handle = CreateSemaphore (NULL, 1, 1, "UT_SIM_SEMA");
        }
        first_ut_init = 0;
      }

      WaitForSingleObject (ut_sema_handle, INFINITE);

      if ((Stream = (T_USARTStream *) openUSARTMemory
                                      (
                                        (char*)"GSM",
                                        sizeof (T_USARTStream)
                                      )) EQ NULL)
      {
        if ((Stream = (T_USARTStream *) createUSARTMemory
                                      (
                                        (char*)"GSM",
                                        sizeof (T_USARTStream)
                                      )) EQ NULL)
        {
          PrintToFile ("USART: simulation could not create a shared memory area\n");
          return -1;
        }
        PrintToFile ("USART: shared memory area created\n");
  
        Stream->CH1_numOfBytes = 0;
        Stream->CH2_numOfBytes = 0;

        Stream->CH1_CTS = 0;
        Stream->CH2_CTS = 0;
  
        for (i=0; i<USART_BUFFER_SIZE; i++)
        {
          Stream->CH1_data[i] = 0;
          Stream->CH2_data[i] = 0;
        }

        Stream->Connects = 0;  /* init connection counter (!! CURRENTLY NOT USED !!) */
        Stream->Type=1;        /* signaling new type */ 
      }
      else
      {
        PrintToFile ("USART: shared memory area opened\n");
      }

      /* set pointers to semaphores and data buffers */
#ifdef _TOOLS_
      if (Stream->Type==0) // shared mem created by old stack
      {
        PrintToFile ("USART: connecting to old stack !\n");

        Stream->CH1_CTS = 1; // (baudRate NEQ -1); removed because baudrate never negative

        InBuffer      = Stream->CH1_data;
        OutBuffer     = Stream->CH2_data;
        InCounter     = &Stream->CH1_numOfBytes;
        OutCounter    = &Stream->CH2_numOfBytes;
        semRCVFull    = &SemCH1_full;
        semRCVEmpty   = &SemCH1_empty;
        semSNDFull    = &SemCH2_full;
        semSNDEmpty   = &SemCH2_empty;
        CTS           = &Stream->CH2_CTS;
      }
      else // shared mem created by us or new stack
      {
        Stream->CH2_CTS  = 1;  // (baudRate NEQ -1); removed because baudrate never negative 

        InBuffer      = Stream->CH2_data;
        OutBuffer     = Stream->CH1_data;
        InCounter     = &Stream->CH2_numOfBytes;
        OutCounter    = &Stream->CH1_numOfBytes;
        semRCVFull    = &SemCH2_full;
        semRCVEmpty   = &SemCH2_empty;
        semSNDFull    = &SemCH1_full;
        semSNDEmpty   = &SemCH1_empty;
        CTS           = &Stream->CH1_CTS;
      }
#else  /* _TOOLS_ */
      Stream->CH1_CTS = 1;  // (baudRate NEQ -1); removed because baudrate never negative 

      InBuffer      = Stream->CH1_data;
      OutBuffer     = Stream->CH2_data;
      InCounter     = &Stream->CH1_numOfBytes;
      OutCounter    = &Stream->CH2_numOfBytes;
      semRCVFull    = &SemCH1_full;
      semRCVEmpty   = &SemCH1_empty;
      semSNDFull    = &SemCH2_full;
      semSNDEmpty   = &SemCH2_empty;
      CTS           = &Stream->CH2_CTS;
#endif /* _TOOLS_ */

      readPointer = InBuffer;

      ReceiveCallback = func;

      Stream->Connects++;      /* mark connection (!! CURRENTLY NOT USED !!) */
      }
        
      ReleaseSemaphore (ut_sema_handle, 1, NULL);

      break;
    default:
      break;
  }
  initialized = TRUE;
  mem_closed = FALSE;

#ifdef DEBUG_USART
  /*
   * Open protocol file and initialize
   */

  usart_in  = open ("USART.IN", O_WRONLY| O_TEXT| O_TRUNC| O_CREAT, 0666);
  usart_out = open ("USART.OUT", O_WRONLY| O_TEXT| O_TRUNC| O_CREAT, 0666);
#endif

  return 0;
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USARTSIM                   |
| STATE   : code                ROUTINE : UT_Close                   |
+--------------------------------------------------------------------+

  PURPOSE : 

*/

GLOBAL BOOL UT_Close(void)
{

  if (initialized == FALSE)
		return FALSE;

  switch (m_mode) {
    case US_MODE_FILE:
      if (m_file)
      {
        fclose(m_file);
        m_file=NULL;
      }
      break;
    case US_MODE_95:
    case US_MODE_NT: {
    	DWORD ExitCode;
    
      if (ReceiveCallback != NULL) {
    	  /* Initialize stop _readerThread */
    	  ReaderThreadExitRequest = TRUE;
    	  while (ReaderThreadExitRequest == TRUE)
		      SetCommMask (hComDev, 0);
      }

    	/* Close Communication port. */
    	PurgeComm (hComDev,
			   PURGE_TXABORT | PURGE_RXABORT |
			   PURGE_TXCLEAR | PURGE_RXCLEAR ) ;
      if (m_mode==UT_MODE_NT) {
      	CloseHandle (gReadOverLap.hEvent);
    	  gReadOverLap.hEvent = INVALID_HANDLE_VALUE ;
    	  CloseHandle (gWriteOverLap.hEvent);
    	  gWriteOverLap.hEvent = INVALID_HANDLE_VALUE ;
      }
    	CloseHandle (hComDev);
    	hComDev = INVALID_HANDLE_VALUE;
	
      if (ReceiveCallback != NULL) {
      	/* Stop _readerThread */
      	do {
		      GetExitCodeThread(hThread, (LPDWORD) &ExitCode);
    	  }
    	  while (ExitCode == STILL_ACTIVE);
      	CloseHandle (hThread);
      	hThread = INVALID_HANDLE_VALUE;
      }
    
      break;
    }
    case US_MODE_SIM: {
      PrintToFile("USART: shared memory closed (%d)\n",cls_cnt);
      mem_closed = TRUE;
     /* mark disconnection  */
      Stream->Connects=(Stream->Connects>1) ? 1 : 0; /* (!! CURRENTLY NOT USED !!) */

#ifdef _TOOLS_
      if (Stream->Type==0) /* shared mem created by old stack */
      {
        fprintf (stdout, "USART: disconnecting from old stack !\n");
        Stream->CH1_CTS = 0; 
      }
      else /* shared mem created by us or new stack */
      {
        Stream->CH2_CTS = 0; 
      }
#else /* _TOOLS_ */
      Stream->CH1_CTS = 0; 
#endif /* _TOOLS_ */

      CTS = NULL;
      /* close all handles */
      UnmapViewOfFile((void*)Stream);
      CloseHandle(USARTMemHandle);
      CloseHandle(SemCH1_full);
      CloseHandle(SemCH2_full);
      CloseHandle(SemCH1_empty);
      CloseHandle(SemCH2_empty);
      cls_cnt++;
      break;
    default:
      break;
    }
  }

#ifdef DEBUG_USART
 	/* close tracefiles for usart-in and out */
 	close(usart_in);
 	close(usart_out);
#endif

	/* Deinitialize */
	ReceiveCallback = NULL;
  initialized     = FALSE;

	return TRUE;
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : UT_InitBlk                 |
+--------------------------------------------------------------------+

  PURPOSE : Initialize the USART for reading blocks

*/

int UT_InitBlk ( unsigned int baudRate, int fifoSize, char flow_ctrl, void *hP)
{
  return UT_Init (baudRate, fifoSize, flow_ctrl, NULL, NULL);
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : UT_IsChar                  |
+--------------------------------------------------------------------+

  PURPOSE : 

*/

GLOBAL int UT_IsChar (void)
{
  int ret;

  switch (m_mode) {
    case US_MODE_FILE:
      Sleep(FILE_SLOW_DOWN);
      while (feof(m_file))
      {
        Sleep(1000);
        fseek(m_file,0,SEEK_CUR);
      }
      ret=1;
      break;
    case US_MODE_95:
    case US_MODE_NT: {
      static COMSTAT stComStat;
      static DWORD   dwErrors;

      if (!initialized)
        return FALSE;

      waitForRCVBufferFull ();

      ClearCommError (hComDev, &dwErrors, &stComStat);

      ret= (stComStat.cbInQue > 0);
      break;
    }
    
    case US_MODE_SIM: {
      waitForRCVBufferFull ();
      ret = (*InCounter NEQ 0);

      if (ret EQ 0)
        readPointer = InBuffer;
      break;
    default: 
      ret = 0;
      break;
    }
  }
 
  return ret;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : UT_ReadChar                |
+--------------------------------------------------------------------+

  PURPOSE : 

*/

GLOBAL BYTE UT_ReadChar (void)
{
  BYTE ret=0;

  switch (m_mode) {
    case US_MODE_95:
    case US_MODE_NT: {

      BYTE  buffer[1];
      ULONG bytesRead;

      if (!initialized)
        return 0;

      sioRead (buffer, &bytesRead);

      if (!bytesRead)
        buffer[0] = 0xff;

      ret=buffer[0];
      break;
    }

    case US_MODE_SIM: {
      if (*InCounter NEQ 0)
      {
        ret = *readPointer++;

#ifdef DEBUG_USART
        {
          BYTE buf[20];
          sprintf (buf, "R[1 of %d]: ", *InCounter);
          write (usart_in,
            buf,
            strlen (buf));
          if (isprint (ret))
          {
            sprintf (buf, "%c\n", ret);
          }
          else
          {
            sprintf (buf, "(%02X)\n", ret);
          }
          write (usart_in,
            buf,
            strlen (buf));
		    }
#endif

        (*InCounter)--;

        if (*InCounter EQ 0)
        {
          readPointer = InBuffer;
          markRCVBufferEmpty ();
        }
      }
      break;
    default:
      break;
    }
  }
  return ret;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : UT_ReadNChars              |
+--------------------------------------------------------------------+

  PURPOSE : Called from the HISR - Reads a block of characters
            Parameters : buffer for holding received characters,
                         max. size of buffer
            Returns the number of characters read

*/

GLOBAL ULONG UT_ReadNChars (int usart_id, BYTE *buffer, ULONG bufferSize)
{
  ULONG   bytes;

  switch (m_mode) {
    case US_MODE_FILE:
      if (bufferSize>FILE_MAX_CHUNK)
      {
        bufferSize=FILE_MAX_CHUNK;
      }
      bytes=fread(buffer,1,bufferSize,m_file);
      break;
    case US_MODE_95:
    case US_MODE_NT: {

      COMSTAT stComStat;
      DWORD   dwErrors;

      if (!initialized)
        return 0L;

      ClearCommError (hComDev, &dwErrors, &stComStat);
  
      bytes = MINIMUM (stComStat.cbInQue, bufferSize);

      if (bytes EQ 0)
        return 0L;

      sioRead (buffer, &bytes);
      break;
    }

    case US_MODE_SIM: {
      if ((bytes = MINIMUM (*InCounter, bufferSize)) NEQ 0)
      {
#ifdef DEBUG_USART
        unsigned int i;
        char buf[50];
#endif
    
        memcpy (buffer, readPointer, bytes);

#ifdef DEBUG_USART
        sprintf (buf, "R[%d of %d]: ", bytes, *InCounter);
        write (usart_in, buf, strlen (buf));

        for (i=0; i<bytes; i++)
        {
          if (isprint (buffer[i]))
            sprintf (buf, "%c", buffer[i]);
          else
            sprintf (buf, "(%02X)", buffer[i]);
          write (usart_in,
             buf,
             strlen (buf));
        }
        write (usart_in, "\n", 1);
#endif

        (*InCounter) -= (USHORT)bytes;

        if (*InCounter EQ 0)
        {
          readPointer = InBuffer;
          markRCVBufferEmpty ();
        }
        else {
          readPointer += bytes;
        }
      }
      else {
        markRCVBufferEmpty ();
      }
      break;
    default: bytes = 0;
      break;
    }
  }

  return bytes;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : UT_WriteChar               |
+--------------------------------------------------------------------+

  PURPOSE : 

*/

GLOBAL void UT_WriteChar (int usart_id, char ch)
{
  switch (m_mode) {
    case US_MODE_95:
    case US_MODE_NT: {
      BYTE  buffer[1];
      ULONG bytesWritten = 1;

      if (!initialized)
        return;

      buffer[0] = (BYTE)ch;

      sioWrite (buffer, &bytesWritten);
      break;
    }

    case US_MODE_SIM: {
#ifdef DEBUG_USART
      char buf[50];
#endif

      if ( CTS == NULL || !*CTS)  /* no testtools connected */
      {
        return;
      }

      if (waitForSNDBufferEmpty () != 0)
      {
        markSNDBufferFull ();
        return;   /* we gave up sending to avoid dead lock */
      }
      
#ifdef DEBUG_USART
      sprintf (buf, "W[1]: %02X", ch);
      write (usart_out, buf, strlen (buf));
#endif

      *OutBuffer  = (UBYTE)ch;
      *OutCounter = 1;
   
      markSNDBufferFull ();
      break;
    default:
      break;
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : UT_WriteString             |
+--------------------------------------------------------------------+

  PURPOSE : 

*/

GLOBAL void UT_WriteString (int usart_id, char *s)
{
  switch (m_mode) {
    case US_MODE_95:
    case US_MODE_NT: {
      ULONG bytesWritten = strlen (s);

      if (!initialized)
        return;

      sioWrite ((BYTE *) s, &bytesWritten);
      break;
    }

    case US_MODE_SIM: {
      unsigned int numOfChars;
#ifdef DEBUG_USART
      int i;
      char buf[50];
#endif

      if ( CTS == NULL || !*CTS)  /* no testtools connected */
      {
        return;
      }

      if (waitForSNDBufferEmpty () != 0)
      {
        markSNDBufferFull ();
        return;   /* we gave up sending to avoid dead lock */
      }

      numOfChars = strlen (s);

      memcpy (OutBuffer, s, numOfChars);
      *OutCounter = numOfChars;

#ifdef DEBUG_USART
      sprintf (buf, "W[%d]:", numOfChars);
      write (usart_out, buf, strlen (buf));

      for (i=0; i<numOfChars; i++)
      {
        if (isprint (OutBuffer[i]))
          sprintf (buf, "%c", OutBuffer[i]);
        else
          sprintf (buf, "(%02X)", OutBuffer[i]);
        write (usart_out,
               buf,
               strlen (buf));

      }
      write (usart_out,"\n", 1);
#endif

      markSNDBufferFull ();
      break;
    default:
      break;
    }
  }
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : UT_WriteNChars             |
+--------------------------------------------------------------------+

  PURPOSE : 

*/

GLOBAL void UT_WriteNChars (int usart_id, BYTE *s, unsigned int n)
{
  switch (m_mode) {
    case US_MODE_95:
    case US_MODE_NT: {
      ULONG bytesWritten = (ULONG) n;

      if (!initialized)
        return;

      if (!sioWrite ((BYTE *) s, &bytesWritten))
        fprintf (stderr, "USART: Error1\n");
      if (bytesWritten NEQ (ULONG) n)
        fprintf (stderr, "USART: Error2\n");
      break;
    }

    case US_MODE_SIM: {
#ifdef DEBUG_USART
      int i;
      char buf[50];
#endif
      
      if ( CTS == NULL || !*CTS)  /* no testtools connected */
      {
#ifdef DEBUG_USART
        printf("-");
#endif
        snd_cnt++;
        return;
      }

      if ( mem_closed == TRUE )
      {
        PrintToFile("USART:tried to write on closed memory (%d)\n",snd_cnt);
        return;
      }
      if (waitForSNDBufferEmpty () != 0)
      {
        markSNDBufferFull ();
        PrintToFile("USART: gave up sending\n");
        snd_cnt++;
        return;   /* we gave up sending to avoid dead lock */
      }
      memcpy (OutBuffer, s, n);
      *OutCounter = n;

#ifdef DEBUG_USART
      sprintf (buf, "W[%d]:", n);
      write (usart_out, buf, strlen (buf));

      for (i=0; i<n; i++)
      {
        if (isprint (OutBuffer[i]))
          sprintf (buf, "%c", OutBuffer[i]);
        else
          sprintf (buf, "(%02X)", OutBuffer[i]);
        write (usart_out,
               buf,
               strlen (buf));
      }
      write (usart_out,"\n", 1);
#endif

      if ( mem_closed == TRUE )
      {
        PrintToFile("USART: written on closed memory (%d)\n",snd_cnt);
        snd_cnt++;
        return;
      }
#ifdef DEBUG_USART
      printf("+");
#endif
      markSNDBufferFull ();
      snd_cnt++;
      break;
    default:
      break;
    }
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : USART                      |
| STATE   : code                ROUTINE : UT_SetFlowCtrl             |
+--------------------------------------------------------------------+

  PURPOSE : 

*/

GLOBAL void UT_SetFlowCtrl (char flowCtrl)
{
  switch (m_mode) {
    case US_MODE_95:
    case US_MODE_NT: {
      DCB stDCB;

      if (!GetCommState (hComDev, &stDCB))
        return;

      stDCB.DCBlength = sizeof (stDCB);  // sizeof(DCB) 

      switch (flowCtrl)
      {
        case 'N':
          stDCB.fOutxCtsFlow = FALSE;
          stDCB.fOutxDsrFlow = FALSE;
          stDCB.fDtrControl = DTR_CONTROL_DISABLE;
          stDCB.fRtsControl = RTS_CONTROL_DISABLE;
          break;
        case 'D':
          stDCB.fOutxCtsFlow = FALSE;
          stDCB.fOutxDsrFlow = TRUE;
          stDCB.fDtrControl = DTR_CONTROL_HANDSHAKE;
          stDCB.fRtsControl = RTS_CONTROL_DISABLE;
          stDCB.XonLim  = 0;
          stDCB.XoffLim = 50;
          break;
        case 'R':
          stDCB.fOutxCtsFlow = TRUE;
          stDCB.fOutxDsrFlow = FALSE;
          stDCB.fDtrControl = DTR_CONTROL_DISABLE;
          stDCB.fRtsControl = RTS_CONTROL_HANDSHAKE;
          stDCB.XonLim  = 0;
          stDCB.XoffLim = 50;
          break;
        case 'P':
          stDCB.fOutxCtsFlow = FALSE;
          stDCB.fOutxDsrFlow = FALSE;
          stDCB.fDtrControl = DTR_CONTROL_ENABLE;
          stDCB.fRtsControl = RTS_CONTROL_DISABLE;
          break;
        default:
          break;
      }

      SetCommState (hComDev, &stDCB);
      break;
    }

    case US_MODE_SIM:
      break;
    default:
      break;
  }
}