--- /dev/null
+/*
+ * serial interface threads for gnokii on win32
+ * Based on the MS sample program 'tty.c'
+ *
+ * Roger Willcocks 16 Sept 99
+ *
+ * compile with:
+ * cl -Zi -DWIN32 -DVERSION=\"win32\" -DMODEL=\"6110\" -DPORT=\"COM1\" \
+ * gnokii.c winserial.c fbus-6110.c getopt.c gsm-api.c fbus-6110-auth.c \
+ * fbus-6110-ringtones.c gsm-networks.c cfgreader.c
+ */
+
+#ifdef WIN32
+
+#define USECOMM // yes, we need the COMM API
+
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+#include <io.h>
+#include <memory.h>
+
+#include "devices/winserial.h"
+
+#define sleep(x) Sleep((x) * 1000)
+#define usleep(x) Sleep(((x) < 1000) ? 1 : ((x) / 1000))
+
+#define BAUDRATE CBR_115200
+
+DWORD FAR PASCAL CommWatchProc(LPSTR lpData);
+DWORD FAR PASCAL KeepAliveProc(LPSTR lpData);
+BOOL SetupConnection();
+#define MAXBLOCK 1024
+
+//---------------------------------------------------------------------------
+// BOOL OpenConnection(char *szPort)
+//
+// Description:
+// Opens communication port.
+// It also sets the CommState and notifies the window via
+// the fConnected flag.
+//
+// Parameters:
+// - szPort - name of com port eg "com1"
+//
+//---------------------------------------------------------------------------
+
+OVERLAPPED osWrite, osRead;
+HANDLE hPhone, hThread, hKAThread;
+BOOL isConnected;
+DWORD ThreadID, KAThreadID;
+
+BOOL OpenConnection(char *szPort, sigcallback fn, keepalive ka)
+{
+ BOOL fRetVal;
+ HANDLE hCommWatchThread;
+ DWORD dwThreadID;
+ COMMTIMEOUTS CommTimeOuts;
+
+ if ((hPhone =
+ CreateFile(szPort, GENERIC_READ | GENERIC_WRITE,
+ 0, // exclusive access
+ NULL, // no security attrs
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL |
+ FILE_FLAG_OVERLAPPED, // overlapped I/O
+ NULL)) == (HANDLE) -1)
+ return (FALSE);
+ else {
+ // get any early notifications
+
+ SetCommMask(hPhone, EV_RXCHAR);
+
+ // setup device buffers
+
+ SetupComm(hPhone, 4096, 4096);
+
+ // purge any information in the buffer
+
+ PurgeComm(hPhone, PURGE_TXABORT | PURGE_RXABORT |
+ PURGE_TXCLEAR | PURGE_RXCLEAR);
+
+ // set up for overlapped I/O
+
+ CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
+ CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
+ CommTimeOuts.ReadTotalTimeoutConstant = 1000;
+#if 0
+ // CBR_9600 is approximately 1byte/ms. For our purposes, allow
+ // double the expected time per character for a fudge factor.
+ CommTimeOuts.WriteTotalTimeoutMultiplier = 2*CBR_9600/BAUDRATE;
+#else
+ CommTimeOuts.WriteTotalTimeoutMultiplier = 10;
+#endif
+ CommTimeOuts.WriteTotalTimeoutConstant = 0;
+ SetCommTimeouts(hPhone, &CommTimeOuts);
+ }
+
+ fRetVal = SetupConnection();
+
+ if (fRetVal) {
+ isConnected = TRUE;
+
+ // Create a secondary thread to issue keepAlive packets
+
+/* Marcin Wiacek. In this moment there is NO method of communication,
+ which require keepalive packets. I comment this thread, because it
+ makes only CPU time (100%) and makes it more hot */
+// hKAThread = CreateThread((LPSECURITY_ATTRIBUTES) NULL,
+// 0,
+// (LPTHREAD_START_ROUTINE) KeepAliveProc,
+// (LPVOID) ka,
+// 0, &KAThreadID );
+// if (!hKAThread)
+// {
+// isConnected = FALSE;
+// CloseHandle(hPhone);
+// return FALSE;
+// }
+
+ // Create a secondary thread
+ // to watch for an event.
+
+ hCommWatchThread = CreateThread((LPSECURITY_ATTRIBUTES) NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE) CommWatchProc,
+ (LPVOID) fn,
+ 0, &dwThreadID);
+ if (!hCommWatchThread)
+ {
+ isConnected = FALSE;
+ CloseHandle(hPhone);
+ fRetVal = FALSE;
+ }
+ else {
+ ThreadID = dwThreadID;
+ hThread = hCommWatchThread;
+
+ // assert DTR
+
+ EscapeCommFunction(hPhone, SETDTR);
+ }
+ }
+ else {
+ isConnected = FALSE;
+ CloseHandle(hPhone);
+ }
+
+ return (fRetVal);
+
+} // end of OpenConnection()
+
+//---------------------------------------------------------------------------
+// BOOL SetupConnection()
+//
+// Description:
+// This routines sets up the DCB based on settings in the
+// TTY info structure and performs a SetCommState().
+//
+// Parameters:
+//
+//---------------------------------------------------------------------------
+
+BOOL SetupConnection()
+{
+ BOOL fRetVal;
+ DCB dcb;
+
+ dcb.DCBlength = sizeof(DCB);
+
+ GetCommState(hPhone, &dcb);
+
+ dcb.BaudRate = BAUDRATE;
+ dcb.ByteSize = 8;
+ dcb.Parity = NOPARITY;
+ dcb.StopBits = ONESTOPBIT;
+
+ // set DTS
+
+ dcb.fOutxDsrFlow = 0;
+ dcb.fDtrControl = DTR_CONTROL_ENABLE;
+
+ // clear RTS
+
+ dcb.fOutxCtsFlow = 0;
+ dcb.fRtsControl = RTS_CONTROL_DISABLE;
+
+ // no software flow control
+
+ dcb.fInX = dcb.fOutX = 0;
+
+ fRetVal = SetCommState(hPhone, &dcb);
+
+ if (fRetVal == 0)
+ fRetVal = GetLastError();
+
+ return (fRetVal);
+
+} // end of SetupConnection()
+
+//---------------------------------------------------------------------------
+// BOOL CloseConnection()
+//
+// Description:
+// Closes the connection to the port. Resets the connect flag
+//
+// Parameters:
+//
+//---------------------------------------------------------------------------
+
+BOOL CloseConnection()
+{
+ isConnected = FALSE;
+
+ // block until keepalive thread terminates (should wake it really)
+
+/* Marcin Wiacek. In this moment there is NO method of communication,
+ which require keepalive packets. I comment this thread, because it
+ makes only CPU time (100%) and makes it more hot */
+// WaitForSingleObject( hKAThread, INFINITE );
+#ifdef _NEVER_SAY_NEVER_AGAIN_
+// while (KAThreadID != 0)
+// Sleep(250);
+#endif
+
+ // disable event notification and wait for thread
+ // to halt
+
+ SetCommMask(hPhone, 0);
+
+ // block until thread has been halted
+
+ WaitForSingleObject( hThread, INFINITE );
+#ifdef _NEVER_SAY_NEVER_AGAIN_
+ while(ThreadID != 0)
+ Sleep(250);
+#endif
+
+ // drop DTR
+
+ EscapeCommFunction(hPhone, CLRDTR);
+
+ // purge any outstanding reads/writes and close device handle
+
+ PurgeComm(hPhone, PURGE_TXABORT | PURGE_RXABORT |
+ PURGE_TXCLEAR | PURGE_RXCLEAR);
+
+ CloseHandle(hPhone);
+ return (TRUE);
+
+} // end of CloseConnection()
+
+//---------------------------------------------------------------------------
+// int ReadCommBlock(LPSTR lpszBlock, int nMaxLength)
+//
+// Description:
+// Reads a block from the COM port and stuffs it into
+// the provided buffer.
+//
+// Parameters:
+//
+// LPSTR lpszBlock
+// block used for storage
+//
+// int nMaxLength
+// max length of block to read
+//
+//---------------------------------------------------------------------------
+
+int ReadCommBlock(LPSTR lpszBlock, int nMaxLength)
+{
+ BOOL fReadStat;
+ COMSTAT ComStat;
+ DWORD dwErrorFlags;
+ DWORD dwLength;
+ DWORD dwError;
+
+ // only try to read number of bytes in queue
+ ClearCommError(hPhone, &dwErrorFlags, &ComStat);
+ dwLength = min((DWORD) nMaxLength, ComStat.cbInQue);
+
+ if (dwLength > 0) {
+ fReadStat = ReadFile(hPhone, lpszBlock,
+ dwLength, &dwLength, &osRead);
+ if (!fReadStat) {
+ if (GetLastError() == ERROR_IO_PENDING) {
+ fprintf(stderr, "\n\rIO Pending");
+ // We have to wait for read to complete.
+ // This function will timeout according to the
+ // CommTimeOuts.ReadTotalTimeoutConstant variable
+ // Every time it times out, check for port errors
+ while(!GetOverlappedResult(hPhone,
+ &osRead, &dwLength, TRUE)) {
+ dwError = GetLastError();
+ if(dwError == ERROR_IO_INCOMPLETE)
+ // normal result if not finished
+ continue;
+ else {
+ // an error occurred, try to recover
+ fprintf(stderr, "<CE-%u>", dwError);
+ ClearCommError(hPhone, &dwErrorFlags, &ComStat);
+ if (dwErrorFlags > 0)
+ fprintf(stderr, "<CE-%u>", dwErrorFlags);
+ break;
+ }
+
+ }
+
+ }
+ else {
+ // some other error occurred
+ dwLength = 0;
+ ClearCommError(hPhone, &dwErrorFlags, &ComStat);
+ if (dwErrorFlags > 0)
+ fprintf(stderr, "<CE-%u>", dwErrorFlags);
+ }
+ }
+ }
+
+ return (dwLength);
+
+} // end of ReadCommBlock()
+
+//---------------------------------------------------------------------------
+// BOOL WriteCommBlock(BYTE *pByte, DWORD dwBytesToWrite)
+//
+// Description:
+// Writes a block of data to the COM port specified in the associated
+// TTY info structure.
+//
+// Parameters:
+//
+// BYTE *pByte
+// pointer to data to write to port
+//
+//---------------------------------------------------------------------------
+
+BOOL WriteCommBlock(LPSTR lpByte , DWORD dwBytesToWrite)
+{
+
+ BOOL fWriteStat;
+ DWORD dwBytesWritten;
+ DWORD dwErrorFlags;
+ DWORD dwError;
+ DWORD dwBytesSent=0;
+ COMSTAT ComStat;
+
+ fWriteStat = WriteFile(hPhone, lpByte, dwBytesToWrite,
+ &dwBytesWritten, &osWrite);
+
+ // Note that normally the code will not execute the following
+ // because the driver caches write operations. Small I/O requests
+ // (up to several thousand bytes) will normally be accepted
+ // immediately and WriteFile will return true even though an
+ // overlapped operation was specified
+
+ if (!fWriteStat) {
+ if(GetLastError() == ERROR_IO_PENDING) {
+ // We should wait for the completion of the write operation
+ // so we know if it worked or not
+
+ // This is only one way to do this. It might be beneficial to
+ // place the write operation in a separate thread
+ // so that blocking on completion will not negatively
+ // affect the responsiveness of the UI
+
+ // If the write takes too long to complete, this
+ // function will timeout according to the
+ // CommTimeOuts.WriteTotalTimeoutMultiplier variable.
+ // This code logs the timeout but does not retry
+ // the write.
+
+ while(!GetOverlappedResult(hPhone,
+ &osWrite, &dwBytesWritten, TRUE)) {
+ dwError = GetLastError();
+ if(dwError == ERROR_IO_INCOMPLETE)
+ {
+ // normal result if not finished
+ dwBytesSent += dwBytesWritten;
+ continue;
+ }
+ else {
+ // an error occurred, try to recover
+ fprintf(stderr, "<CE-%u>", dwError);
+ ClearCommError(hPhone, &dwErrorFlags, &ComStat);
+ if (dwErrorFlags > 0)
+ fprintf(stderr, "<CE-%u>", dwErrorFlags);
+ break;
+ }
+ }
+
+ dwBytesSent += dwBytesWritten;
+#if 0
+ if(dwBytesSent != dwBytesToWrite)
+ fprintf(stderr, "\nProbable Write Timeout: Total of %ld bytes sent (%ld)", dwBytesSent, dwBytesToWrite);
+ else
+ fprintf(stderr, "\n%ld bytes written", dwBytesSent);
+#endif
+ }
+ else {
+ // some other error occurred
+ ClearCommError(hPhone, &dwErrorFlags, &ComStat);
+ if (dwErrorFlags > 0)
+ fprintf(stderr, "<CE-%u>", dwErrorFlags);
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+
+} // end of WriteCommBlock()
+
+
+//************************************************************************
+// DWORD FAR PASCAL CommWatchProc(LPSTR lpData)
+//
+// Description:
+// A secondary thread that will watch for COMM events.
+//
+// Parameters:
+// LPSTR lpData
+// 32-bit pointer argument
+//
+//************************************************************************
+
+DWORD FAR PASCAL CommWatchProc(LPSTR lpData)
+{
+ DWORD dwEvtMask;
+ OVERLAPPED os;
+ int nLength;
+ BYTE abIn[ MAXBLOCK + 1];
+
+ sigcallback fn = (sigcallback)lpData;
+
+ memset(&os, 0, sizeof(OVERLAPPED));
+
+ // create I/O event used for overlapped read
+
+ os.hEvent = CreateEvent(NULL, // no security
+ TRUE, // explicit reset req
+ FALSE, // initial event reset
+ NULL); // no name
+ if (os.hEvent == NULL)
+ return (FALSE);
+
+ if (!SetCommMask(hPhone, EV_RXCHAR))
+ return (FALSE);
+
+ while (isConnected) {
+ dwEvtMask = 0;
+
+ WaitCommEvent(hPhone, &dwEvtMask, NULL);
+
+ if ((dwEvtMask & EV_RXCHAR) == EV_RXCHAR) {
+ do {
+ if ((nLength = ReadCommBlock((LPSTR) abIn, MAXBLOCK))) {
+ int i;
+
+ for (i = 0; i < nLength; i++)
+ (*fn)(abIn[i]);
+ }
+ }
+ while (nLength > 0);
+ }
+ }
+
+ // get rid of event handle
+
+ CloseHandle(os.hEvent);
+
+ // clear information in structure (kind of a "we're done flag")
+
+ ThreadID = 0;
+ hThread = NULL;
+
+ return(TRUE);
+
+} // end of CommWatchProc()
+
+
+DWORD FAR PASCAL KeepAliveProc(LPSTR lpData)
+{
+/* Marcin Wiacek. In this moment there is NO method of communication,
+ which require keepalive packets. I comment this thread, because it
+ makes only CPU time (100%) and makes it more hot */
+// keepalive ka = (keepalive)lpData;
+// while (isConnected)
+// (*ka)();
+// KAThreadID = 0;
+ return 0;
+}
+
+#endif
+/* end */