diff options
Diffstat (limited to 'win/tclWinSerial.c')
| -rw-r--r-- | win/tclWinSerial.c | 559 |
1 files changed, 258 insertions, 301 deletions
diff --git a/win/tclWinSerial.c b/win/tclWinSerial.c index 635e978..83f1866 100644 --- a/win/tclWinSerial.c +++ b/win/tclWinSerial.c @@ -4,7 +4,7 @@ * This file implements the Windows-specific serial port functions, and * the "serial" channel driver. * - * Copyright © 1999 Scriptics Corp. + * Copyright (c) 1999 by Scriptics Corp. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -44,15 +44,6 @@ TCL_DECLARE_MUTEX(serialMutex) #define SERIAL_ERROR (1<<4) /* - * Bit masks used for noting whether to drain or discard output on close. They - * are disjoint from each other; at most one may be set at a time. - */ - -#define SERIAL_CLOSE_DRAIN (1<<6) /* Drain all output on close. */ -#define SERIAL_CLOSE_DISCARD (1<<7) /* Discard all output on close. */ -#define SERIAL_CLOSE_MASK (3<<6) /* Both two bits above. */ - -/* * Default time to block between checking status on the serial port. */ @@ -85,7 +76,7 @@ typedef struct SerialInfo { int readable; /* Flag that the channel is readable. */ int writable; /* Flag that the channel is writable. */ int blockTime; /* Maximum blocktime in msec. */ - unsigned long long lastEventTime; /* Time in milliseconds since last readable + unsigned int lastEventTime; /* Time in milliseconds since last readable * event. */ /* Next readable event only after blockTime */ DWORD error; /* pending error code returned by @@ -102,12 +93,17 @@ typedef struct SerialInfo { * threads. */ OVERLAPPED osRead; /* OVERLAPPED structure for read operations. */ OVERLAPPED osWrite; /* OVERLAPPED structure for write operations */ - TclPipeThreadInfo *writeTI; /* Thread info structure of writer worker. */ HANDLE writeThread; /* Handle to writer thread. */ CRITICAL_SECTION csWrite; /* Writer thread synchronisation. */ HANDLE evWritable; /* Manual-reset event to signal when the * writer thread has finished waiting for the * current buffer to be written. */ + HANDLE evStartWriter; /* Auto-reset event used by the main thread to + * signal when the writer thread should + * attempt to write to the serial. */ + HANDLE evStopWriter; /* Auto-reset event used by the main thread to + * signal when the writer thread should close. + */ DWORD writeError; /* An error caused by the last background * write. Set to 0 if no error has been * detected. This word is shared with the @@ -124,7 +120,7 @@ typedef struct SerialInfo { * [fconfigure -queue] */ } SerialInfo; -typedef struct { +typedef struct ThreadSpecificData { /* * The following pointer refers to the head of the list of serials that * are being watched for file events. @@ -140,7 +136,7 @@ static Tcl_ThreadDataKey dataKey; * events are generated. */ -typedef struct { +typedef struct SerialEvent { Tcl_Event header; /* Information that is standard for all * events. */ SerialInfo *infoPtr; /* Pointer to serial info structure. Note that @@ -165,30 +161,30 @@ static COMMTIMEOUTS no_timeout = { * Declarations for functions used only in this file. */ -static int SerialBlockProc(void *instanceData, int mode); -static void SerialCheckProc(void *clientData, int flags); -static int SerialCloseProc(void *instanceData, - Tcl_Interp *interp, int flags); +static int SerialBlockProc(ClientData instanceData, int mode); +static void SerialCheckProc(ClientData clientData, int flags); +static int SerialCloseProc(ClientData instanceData, + Tcl_Interp *interp); static int SerialEventProc(Tcl_Event *evPtr, int flags); -static void SerialExitHandler(void *clientData); -static int SerialGetHandleProc(void *instanceData, - int direction, void **handlePtr); +static void SerialExitHandler(ClientData clientData); +static int SerialGetHandleProc(ClientData instanceData, + int direction, ClientData *handlePtr); static ThreadSpecificData *SerialInit(void); -static int SerialInputProc(void *instanceData, char *buf, +static int SerialInputProc(ClientData instanceData, char *buf, int toRead, int *errorCode); -static int SerialOutputProc(void *instanceData, - const char *buf, int toWrite, int *errorCode); -static void SerialSetupProc(void *clientData, int flags); -static void SerialWatchProc(void *instanceData, int mask); -static void ProcExitHandler(void *clientData); -static int SerialGetOptionProc(void *instanceData, - Tcl_Interp *interp, const char *optionName, +static int SerialOutputProc(ClientData instanceData, + CONST char *buf, int toWrite, int *errorCode); +static void SerialSetupProc(ClientData clientData, int flags); +static void SerialWatchProc(ClientData instanceData, int mask); +static void ProcExitHandler(ClientData clientData); +static int SerialGetOptionProc(ClientData instanceData, + Tcl_Interp *interp, CONST char *optionName, Tcl_DString *dsPtr); -static int SerialSetOptionProc(void *instanceData, - Tcl_Interp *interp, const char *optionName, - const char *value); +static int SerialSetOptionProc(ClientData instanceData, + Tcl_Interp *interp, CONST char *optionName, + CONST char *value); static DWORD WINAPI SerialWriterThread(LPVOID arg); -static void SerialThreadActionProc(void *instanceData, +static void SerialThreadActionProc(ClientData instanceData, int action); static int SerialBlockingRead(SerialInfo *infoPtr, LPVOID buf, DWORD bufSize, LPDWORD lpRead, LPOVERLAPPED osPtr); @@ -201,10 +197,10 @@ static int SerialBlockingWrite(SerialInfo *infoPtr, LPVOID buf, * based IO. */ -static const Tcl_ChannelType serialChannelType = { +static Tcl_ChannelType serialChannelType = { "serial", /* Type name. */ TCL_CHANNEL_VERSION_5, /* v5 channel */ - TCL_CLOSE2PROC, /* Close proc. */ + SerialCloseProc, /* Close proc. */ SerialInputProc, /* Input proc. */ SerialOutputProc, /* Output proc. */ NULL, /* Seek proc. */ @@ -212,13 +208,13 @@ static const Tcl_ChannelType serialChannelType = { SerialGetOptionProc, /* Get option proc. */ SerialWatchProc, /* Set up notifier to watch the channel. */ SerialGetHandleProc, /* Get an OS handle from channel. */ - SerialCloseProc, /* close2proc. */ + NULL, /* close2proc. */ SerialBlockProc, /* Set blocking or non-blocking mode.*/ NULL, /* flush proc. */ NULL, /* handler proc. */ NULL, /* wide seek proc */ SerialThreadActionProc, /* thread action proc */ - NULL /* truncate */ + NULL, /* truncate */ }; /* @@ -285,7 +281,7 @@ SerialInit(void) static void SerialExitHandler( - TCL_UNUSED(void *)) + ClientData clientData) /* Old window proc */ { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); SerialInfo *infoPtr; @@ -323,7 +319,7 @@ SerialExitHandler( static void ProcExitHandler( - TCL_UNUSED(void *)) + ClientData clientData) /* Old window proc */ { Tcl_MutexLock(&serialMutex); initialized = 0; @@ -335,7 +331,7 @@ ProcExitHandler( * * SerialBlockTime -- * - * Wrapper to set Tcl's block time in msec. + * Wrapper to set Tcl's block time in msec * * Results: * None. @@ -373,14 +369,14 @@ SerialBlockTime( *---------------------------------------------------------------------- */ -static unsigned long long +static unsigned int SerialGetMilliseconds(void) { Tcl_Time time; - Tcl_GetTime(&time); + TclpGetTime(&time); - return ((unsigned long long)time.sec * 1000 + (unsigned long)time.usec / 1000); + return (time.sec * 1000 + time.usec / 1000); } /* @@ -400,13 +396,9 @@ SerialGetMilliseconds(void) *---------------------------------------------------------------------- */ -#ifdef __cplusplus -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif - void SerialSetupProc( - TCL_UNUSED(void *), + ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { SerialInfo *infoPtr; @@ -461,7 +453,7 @@ SerialSetupProc( static void SerialCheckProc( - TCL_UNUSED(void *), + ClientData data, /* Not used. */ int flags) /* Event flags as passed to Tcl_DoOneEvent. */ { SerialInfo *infoPtr; @@ -469,7 +461,7 @@ SerialCheckProc( int needEvent; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); COMSTAT cStat; - unsigned long long time; + unsigned int time; if (!(flags & TCL_FILE_EVENTS)) { return; @@ -519,8 +511,8 @@ SerialCheckProc( (infoPtr->error & SERIAL_READ_ERRORS)) { infoPtr->readable = 1; time = SerialGetMilliseconds(); - if ((time - infoPtr->lastEventTime) - >= (unsigned long long) infoPtr->blockTime) { + if ((unsigned int) (time - infoPtr->lastEventTime) + >= (unsigned int) infoPtr->blockTime) { needEvent = 1; infoPtr->lastEventTime = time; } @@ -535,7 +527,7 @@ SerialCheckProc( if (needEvent) { infoPtr->flags |= SERIAL_PENDING; - evPtr = (SerialEvent *)ckalloc(sizeof(SerialEvent)); + evPtr = (SerialEvent *) ckalloc(sizeof(SerialEvent)); evPtr->header.proc = SerialEventProc; evPtr->infoPtr = infoPtr; Tcl_QueueEvent((Tcl_Event *) evPtr, TCL_QUEUE_TAIL); @@ -561,7 +553,7 @@ SerialCheckProc( static int SerialBlockProc( - void *instanceData, /* Instance data for channel. */ + ClientData instanceData, /* Instance data for channel. */ int mode) /* TCL_MODE_BLOCKING or * TCL_MODE_NONBLOCKING. */ { @@ -600,19 +592,16 @@ SerialBlockProc( static int SerialCloseProc( - void *instanceData, /* Pointer to SerialInfo structure. */ - TCL_UNUSED(Tcl_Interp *), - int flags) + ClientData instanceData, /* Pointer to SerialInfo structure. */ + Tcl_Interp *interp) /* For error reporting. */ { SerialInfo *serialPtr = (SerialInfo *) instanceData; - int errorCode = 0, result = 0; + int errorCode, result = 0; SerialInfo *infoPtr, **nextPtrPtr; ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); + DWORD exitCode; - if ((flags & (TCL_CLOSE_READ | TCL_CLOSE_WRITE)) != 0) { - return EINVAL; - } - + errorCode = 0; if (serialPtr->validMask & TCL_READABLE) { PurgeComm(serialPtr->handle, PURGE_RXABORT | PURGE_RXCLEAR); @@ -620,12 +609,56 @@ SerialCloseProc( } serialPtr->validMask &= ~TCL_READABLE; - if (serialPtr->writeThread) { - TclPipeThreadStop(&serialPtr->writeTI, serialPtr->writeThread); + if (serialPtr->validMask & TCL_WRITABLE) { + /* + * Generally we cannot wait for a pending write operation because it + * may hang due to handshake + * WaitForSingleObject(serialPtr->evWritable, INFINITE); + */ + /* + * The thread may have already closed on it's own. Check it's exit + * code. + */ + + GetExitCodeThread(serialPtr->writeThread, &exitCode); + + if (exitCode == STILL_ACTIVE) { + /* + * Set the stop event so that if the writer thread is blocked in + * SerialWriterThread on WaitForMultipleEvents, it will exit + * cleanly. + */ + + SetEvent(serialPtr->evStopWriter); + + /* + * Wait at most 20 milliseconds for the writer thread to close. + */ + + if (WaitForSingleObject(serialPtr->writeThread, + 20) == WAIT_TIMEOUT) { + /* + * Forcibly terminate the background thread as a last resort. + * Note that we need to guard against terminating the thread + * while it is in the middle of Tcl_ThreadAlert because it + * won't be able to release the notifier lock. + */ + + Tcl_MutexLock(&serialMutex); + + /* BUG: this leaks memory */ + TerminateThread(serialPtr->writeThread, 0); + + Tcl_MutexUnlock(&serialMutex); + } + } + + CloseHandle(serialPtr->writeThread); CloseHandle(serialPtr->osWrite.hEvent); CloseHandle(serialPtr->evWritable); - CloseHandle(serialPtr->writeThread); + CloseHandle(serialPtr->evStartWriter); + CloseHandle(serialPtr->evStopWriter); serialPtr->writeThread = NULL; PurgeComm(serialPtr->handle, PURGE_TXABORT | PURGE_TXCLEAR); @@ -645,7 +678,7 @@ SerialCloseProc( && (GetStdHandle(STD_OUTPUT_HANDLE) != serialPtr->handle) && (GetStdHandle(STD_ERROR_HANDLE) != serialPtr->handle))) { if (CloseHandle(serialPtr->handle) == FALSE) { - Tcl_WinConvertError(GetLastError()); + TclWinConvertError(GetLastError()); errorCode = errno; } } @@ -673,7 +706,7 @@ SerialCloseProc( ckfree(serialPtr->writeBuf); serialPtr->writeBuf = NULL; } - ckfree(serialPtr); + ckfree((char*) serialPtr); if (errorCode == 0) { return result; @@ -855,7 +888,7 @@ SerialBlockingWrite( static int SerialInputProc( - void *instanceData, /* Serial state. */ + ClientData instanceData, /* Serial state. */ char *buf, /* Where to store data read. */ int bufSize, /* How much space is available in the * buffer? */ @@ -899,12 +932,12 @@ SerialInputProc( bufSize = cStat.cbInQue; } } else { - errno = *errorCode = EWOULDBLOCK; + errno = *errorCode = EAGAIN; return -1; } } else { /* - * BLOCKING mode: Tcl tries to read a full buffer of 4 kBytes here. + * BLOCKING mode: Tcl trys to read a full buffer of 4 kBytes here. */ if (cStat.cbInQue > 0) { @@ -918,7 +951,7 @@ SerialInputProc( } if (bufSize == 0) { - return 0; + return bytesRead = 0; } /* @@ -928,7 +961,7 @@ SerialInputProc( if (SerialBlockingRead(infoPtr, (LPVOID) buf, (DWORD) bufSize, &bytesRead, &infoPtr->osRead) == FALSE) { - Tcl_WinConvertError(GetLastError()); + TclWinConvertError(GetLastError()); *errorCode = errno; return -1; } @@ -962,8 +995,8 @@ SerialInputProc( static int SerialOutputProc( - void *instanceData, /* Serial state. */ - const char *buf, /* The data buffer. */ + ClientData instanceData, /* Serial state. */ + CONST char *buf, /* The data buffer. */ int toWrite, /* How many bytes to write? */ int *errorCode) /* Where to store error code. */ { @@ -973,9 +1006,9 @@ SerialOutputProc( *errorCode = 0; /* - * At EXIT Tcl tries to flush all open channels in blocking mode. We avoid + * At EXIT Tcl trys to flush all open channels in blocking mode. We avoid * blocking output after ExitProc or CloseHandler(chan) has been called by - * checking the corresponding variables. + * checking the corrresponding variables. */ if (!initialized || TclInExit()) { @@ -1010,7 +1043,7 @@ SerialOutputProc( */ if (infoPtr->writeError) { - Tcl_WinConvertError(infoPtr->writeError); + TclWinConvertError(infoPtr->writeError); infoPtr->writeError = 0; goto error1; } @@ -1038,12 +1071,12 @@ SerialOutputProc( ckfree(infoPtr->writeBuf); } infoPtr->writeBufLen = toWrite; - infoPtr->writeBuf = (char *)ckalloc(toWrite); + infoPtr->writeBuf = ckalloc((unsigned int) toWrite); } - memcpy(infoPtr->writeBuf, buf, toWrite); + memcpy(infoPtr->writeBuf, buf, (size_t) toWrite); infoPtr->toWrite = toWrite; ResetEvent(infoPtr->evWritable); - TclPipeThreadSignal(&infoPtr->writeTI); + SetEvent(infoPtr->evStartWriter); bytesWritten = (DWORD) toWrite; } else { @@ -1069,7 +1102,7 @@ SerialOutputProc( return (int) bytesWritten; writeError: - Tcl_WinConvertError(GetLastError()); + TclWinConvertError(GetLastError()); error: /* @@ -1192,7 +1225,7 @@ SerialEventProc( static void SerialWatchProc( - void *instanceData, /* Serial state. */ + ClientData instanceData, /* Serial state. */ int mask) /* What events to watch for, OR-ed combination * of TCL_READABLE, TCL_WRITABLE and * TCL_EXCEPTION. */ @@ -1249,13 +1282,13 @@ SerialWatchProc( static int SerialGetHandleProc( - void *instanceData, /* The serial state. */ - TCL_UNUSED(int) /*direction*/, - void **handlePtr) /* Where to store the handle. */ + ClientData instanceData, /* The serial state. */ + int direction, /* TCL_READABLE or TCL_WRITABLE */ + ClientData *handlePtr) /* Where to store the handle. */ { SerialInfo *infoPtr = (SerialInfo *) instanceData; - *handlePtr = (void *)infoPtr->handle; + *handlePtr = (ClientData) infoPtr->handle; return TCL_OK; } @@ -1280,26 +1313,39 @@ static DWORD WINAPI SerialWriterThread( LPVOID arg) { - TclPipeThreadInfo *pipeTI = (TclPipeThreadInfo *)arg; - SerialInfo *infoPtr = NULL; /* access info only after success init/wait */ - DWORD bytesWritten, toWrite; + SerialInfo *infoPtr = (SerialInfo *)arg; + DWORD bytesWritten, toWrite, waitResult; char *buf; OVERLAPPED myWrite; /* Have an own OVERLAPPED in this thread. */ + HANDLE wEvents[2]; + + /* + * The stop event takes precedence by being first in the list. + */ + + wEvents[0] = infoPtr->evStopWriter; + wEvents[1] = infoPtr->evStartWriter; for (;;) { /* * Wait for the main thread to signal before attempting to write. */ - if (!TclPipeThreadWaitForSignal(&pipeTI)) { - /* exit */ + + waitResult = WaitForMultipleObjects(2, wEvents, FALSE, INFINITE); + + if (waitResult != (WAIT_OBJECT_0 + 1)) { + /* + * The start event was not signaled. It might be the stop event or + * an error, so exit. + */ + break; } - infoPtr = (SerialInfo *) pipeTI->clientData; buf = infoPtr->writeBuf; toWrite = infoPtr->toWrite; - myWrite.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + myWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* * Loop until all of the bytes are written or an error occurs. @@ -1358,27 +1404,6 @@ SerialWriterThread( Tcl_MutexUnlock(&serialMutex); } - /* - * We're about to close, so do any drain or discard required. - */ - - if (infoPtr) { - switch (infoPtr->flags & SERIAL_CLOSE_MASK) { - case SERIAL_CLOSE_DRAIN: - FlushFileBuffers(infoPtr->handle); - break; - case SERIAL_CLOSE_DISCARD: - PurgeComm(infoPtr->handle, PURGE_TXABORT | PURGE_TXCLEAR); - break; - } - } - - /* - * Worker exit, so inform the main thread or free TI-structure (if owned). - */ - - TclPipeThreadExit(&pipeTI); - return 0; } @@ -1390,7 +1415,7 @@ SerialWriterThread( * Opens or Reopens the serial port with the OVERLAPPED FLAG set * * Results: - * Returns the new handle, or INVALID_HANDLE_VALUE. + * Returns the new handle, or INVALID_HANDLE_VALUE. * If an existing channel is specified it is closed and reopened. * * Side effects: @@ -1402,7 +1427,7 @@ SerialWriterThread( HANDLE TclWinSerialOpen( HANDLE handle, - const WCHAR *name, + CONST TCHAR *name, DWORD access) { SerialInit(); @@ -1411,7 +1436,7 @@ TclWinSerialOpen( * If an open channel is specified, close it */ - if (handle != INVALID_HANDLE_VALUE && CloseHandle(handle) == FALSE) { + if ( handle != INVALID_HANDLE_VALUE && CloseHandle(handle) == FALSE) { return INVALID_HANDLE_VALUE; } @@ -1421,8 +1446,8 @@ TclWinSerialOpen( * finished */ - handle = CreateFileW(name, access, 0, 0, OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, 0); + handle = (*tclWinProcs->createFileProc)(name, access, 0, 0, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); return handle; } @@ -1452,13 +1477,14 @@ TclWinOpenSerialChannel( int permissions) { SerialInfo *infoPtr; + DWORD id; SerialInit(); - infoPtr = (SerialInfo *)ckalloc(sizeof(SerialInfo)); + infoPtr = (SerialInfo *) ckalloc((unsigned) sizeof(SerialInfo)); memset(infoPtr, 0, sizeof(SerialInfo)); - infoPtr->validMask = permissions & (TCL_READABLE|TCL_WRITABLE); + infoPtr->validMask = permissions; infoPtr->handle = handle; infoPtr->channel = (Tcl_Channel) NULL; infoPtr->readable = 0; @@ -1476,9 +1502,10 @@ TclWinOpenSerialChannel( * are shared between multiple channels (stdin/stdout). */ - TclWinGenerateChannelName(channelName, "file", infoPtr); + sprintf(channelName, "file%" TCL_I_MODIFIER "x", (size_t)infoPtr); + infoPtr->channel = Tcl_CreateChannel(&serialChannelType, channelName, - infoPtr, permissions); + (ClientData) infoPtr, permissions); SetupComm(handle, infoPtr->sysBufRead, infoPtr->sysBufWrite); @@ -1493,18 +1520,19 @@ TclWinOpenSerialChannel( InitializeCriticalSection(&infoPtr->csWrite); if (permissions & TCL_READABLE) { - infoPtr->osRead.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + infoPtr->osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); } if (permissions & TCL_WRITABLE) { /* * Initially the channel is writable and the writeThread is idle. */ - infoPtr->osWrite.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); - infoPtr->evWritable = CreateEventW(NULL, TRUE, TRUE, NULL); + infoPtr->osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + infoPtr->evWritable = CreateEvent(NULL, TRUE, TRUE, NULL); + infoPtr->evStartWriter = CreateEvent(NULL, FALSE, FALSE, NULL); + infoPtr->evStopWriter = CreateEvent(NULL, FALSE, FALSE, NULL); infoPtr->writeThread = CreateThread(NULL, 256, SerialWriterThread, - TclPipeThreadCreateTI(&infoPtr->writeTI, infoPtr, - infoPtr->evWritable), 0, NULL); + infoPtr, 0, &id); } /* @@ -1513,7 +1541,7 @@ TclWinOpenSerialChannel( */ Tcl_SetChannelOption(NULL, infoPtr->channel, "-translation", "auto"); - Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\x1A {}"); + Tcl_SetChannelOption(NULL, infoPtr->channel, "-eofchar", "\032 {}"); return infoPtr->channel; } @@ -1563,7 +1591,7 @@ SerialErrorStr( if (error & ~((DWORD) (SERIAL_READ_ERRORS | SERIAL_WRITE_ERRORS))) { char buf[TCL_INTEGER_SPACE + 1]; - snprintf(buf, sizeof(buf), "%ld", error); + wsprintfA(buf, "%d", error); Tcl_DStringAppendElement(dsPtr, buf); } } @@ -1618,19 +1646,19 @@ SerialModemStatusStr( static int SerialSetOptionProc( - void *instanceData, /* File state. */ + ClientData instanceData, /* File state. */ Tcl_Interp *interp, /* For error reporting - can be NULL. */ - const char *optionName, /* Which option to set? */ - const char *value) /* New value for option. */ + CONST char *optionName, /* Which option to set? */ + CONST char *value) /* New value for option. */ { SerialInfo *infoPtr; DCB dcb; BOOL result, flag; size_t len, vlen; Tcl_DString ds; - const WCHAR *native; - Tcl_Size argc; - const char **argv; + CONST TCHAR *native; + int argc; + CONST char **argv; infoPtr = (SerialInfo *) instanceData; @@ -1643,50 +1671,24 @@ SerialSetOptionProc( vlen = strlen(value); /* - * Option -closemode drain|discard|default - */ - - if ((len > 2) && (strncmp(optionName, "-closemode", len) == 0)) { - if (strncasecmp(value, "DEFAULT", vlen) == 0) { - infoPtr->flags &= ~SERIAL_CLOSE_MASK; - } else if (strncasecmp(value, "DRAIN", vlen) == 0) { - infoPtr->flags &= ~SERIAL_CLOSE_MASK; - infoPtr->flags |= SERIAL_CLOSE_DRAIN; - } else if (strncasecmp(value, "DISCARD", vlen) == 0) { - infoPtr->flags &= ~SERIAL_CLOSE_MASK; - infoPtr->flags |= SERIAL_CLOSE_DISCARD; - } else { - if (interp) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad mode \"%s\" for -closemode: must be" - " default, discard, or drain", value)); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", "FCONFIGURE", - "VALUE", (char *)NULL); - } - return TCL_ERROR; - } - return TCL_OK; - } - - /* * Option -mode baud,parity,databits,stopbits */ if ((len > 2) && (strncmp(optionName, "-mode", len) == 0)) { if (!GetCommState(infoPtr->handle, &dcb)) { - goto getStateFailed; + if (interp != NULL) { + Tcl_AppendResult(interp, "can't get comm state", NULL); + } + return TCL_ERROR; } - Tcl_DStringInit(&ds); - native = Tcl_UtfToWCharDString(value, TCL_INDEX_NONE, &ds); - result = BuildCommDCBW(native, &dcb); + native = Tcl_WinUtfToTChar(value, -1, &ds); + result = (*tclWinProcs->buildCommDCBProc)(native, &dcb); Tcl_DStringFree(&ds); if (result == FALSE) { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad value \"%s\" for -mode: should be baud,parity,data,stop", - value)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "SERIALMODE", (char *)NULL); + Tcl_AppendResult(interp, "bad value \"", value, + "\" for -mode: should be baud,parity,data,stop", NULL); } return TCL_ERROR; } @@ -1701,7 +1703,10 @@ SerialSetOptionProc( dcb.fAbortOnError = FALSE; if (!SetCommState(infoPtr->handle, &dcb)) { - goto setStateFailed; + if (interp != NULL) { + Tcl_AppendResult(interp, "can't set comm state", NULL); + } + return TCL_ERROR; } return TCL_OK; } @@ -1712,7 +1717,10 @@ SerialSetOptionProc( if ((len > 1) && (strncmp(optionName, "-handshake", len) == 0)) { if (!GetCommState(infoPtr->handle, &dcb)) { - goto getStateFailed; + if (interp != NULL) { + Tcl_AppendResult(interp, "can't get comm state", NULL); + } + return TCL_ERROR; } /* @@ -1747,16 +1755,18 @@ SerialSetOptionProc( dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; } else { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad value \"%s\" for -handshake: must be one of" - " xonxoff, rtscts, dtrdsr or none", value)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "HANDSHAKE", (char *)NULL); + Tcl_AppendResult(interp, "bad value \"", value, + "\" for -handshake: must be one of xonxoff, rtscts, " + "dtrdsr or none", NULL); } return TCL_ERROR; } if (!SetCommState(infoPtr->handle, &dcb)) { - goto setStateFailed; + if (interp != NULL) { + Tcl_AppendResult(interp, "can't set comm state", NULL); + } + return TCL_ERROR; } return TCL_OK; } @@ -1767,7 +1777,10 @@ SerialSetOptionProc( if ((len > 1) && (strncmp(optionName, "-xchar", len) == 0)) { if (!GetCommState(infoPtr->handle, &dcb)) { - goto getStateFailed; + if (interp != NULL) { + Tcl_AppendResult(interp, "can't get comm state", NULL); + } + return TCL_ERROR; } if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { @@ -1776,12 +1789,11 @@ SerialSetOptionProc( if (argc != 2) { badXchar: if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "bad value for -xchar: should be a list of" - " two elements with each a single 8-bit character", TCL_INDEX_NONE)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "XCHAR", (char *)NULL); + Tcl_AppendResult(interp, "bad value for -xchar: should be " + "a list of two elements with each a single character", + NULL); } - ckfree(argv); + ckfree((char *) argv); return TCL_ERROR; } @@ -1798,24 +1810,27 @@ SerialSetOptionProc( dcb.XonChar = argv[0][0]; dcb.XoffChar = argv[1][0]; if (argv[0][0] & 0x80 || argv[1][0] & 0x80) { - Tcl_UniChar character = 0; + Tcl_UniChar character; int charLen; - charLen = TclUtfToUniChar(argv[0], &character); - if ((character > 0xFF) || argv[0][charLen]) { + charLen = Tcl_UtfToUniChar(argv[0], &character); + if (argv[0][charLen]) { goto badXchar; } dcb.XonChar = (char) character; - charLen = TclUtfToUniChar(argv[1], &character); - if ((character > 0xFF) || argv[1][charLen]) { + charLen = Tcl_UtfToUniChar(argv[1], &character); + if (argv[1][charLen]) { goto badXchar; } dcb.XoffChar = (char) character; } - ckfree(argv); + ckfree((char *) argv); if (!SetCommState(infoPtr->handle, &dcb)) { - goto setStateFailed; + if (interp != NULL) { + Tcl_AppendResult(interp, "can't set comm state", NULL); + } + return TCL_ERROR; } return TCL_OK; } @@ -1825,79 +1840,66 @@ SerialSetOptionProc( */ if ((len > 4) && (strncmp(optionName, "-ttycontrol", len) == 0)) { - Tcl_Size i; - int res = TCL_OK; + int i, result = TCL_OK; if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; } if ((argc % 2) == 1) { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad value \"%s\" for -ttycontrol: should be " - "a list of signal,value pairs", value)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTYCONTROL", (char *)NULL); + Tcl_AppendResult(interp, "bad value \"", value, + "\" for -ttycontrol: should be a list of " + "signal,value pairs", NULL); } - ckfree(argv); + ckfree((char *) argv); return TCL_ERROR; } for (i = 0; i < argc - 1; i += 2) { if (Tcl_GetBoolean(interp, argv[i+1], &flag) == TCL_ERROR) { - res = TCL_ERROR; + result = TCL_ERROR; break; } if (strncasecmp(argv[i], "DTR", strlen(argv[i])) == 0) { if (!EscapeCommFunction(infoPtr->handle, (DWORD) (flag ? SETDTR : CLRDTR))) { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "can't set DTR signal", TCL_INDEX_NONE)); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", - "FCONFIGURE", "TTY_SIGNAL", (char *)NULL); + Tcl_AppendResult(interp, "can't set DTR signal", NULL); } - res = TCL_ERROR; + result = TCL_ERROR; break; } } else if (strncasecmp(argv[i], "RTS", strlen(argv[i])) == 0) { if (!EscapeCommFunction(infoPtr->handle, (DWORD) (flag ? SETRTS : CLRRTS))) { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "can't set RTS signal", TCL_INDEX_NONE)); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", - "FCONFIGURE", "TTY_SIGNAL", (char *)NULL); + Tcl_AppendResult(interp, "can't set RTS signal", NULL); } - res = TCL_ERROR; + result = TCL_ERROR; break; } } else if (strncasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) { if (!EscapeCommFunction(infoPtr->handle, (DWORD) (flag ? SETBREAK : CLRBREAK))) { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_NewStringObj( - "can't set BREAK signal", TCL_INDEX_NONE)); - Tcl_SetErrorCode(interp, "TCL", "OPERATION", - "FCONFIGURE", "TTY_SIGNAL", (char *)NULL); + Tcl_AppendResult(interp,"can't set BREAK signal",NULL); } - res = TCL_ERROR; + result = TCL_ERROR; break; } } else { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad signal name \"%s\" for -ttycontrol: must be" - " DTR, RTS or BREAK", argv[i])); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "TTY_SIGNAL", - (char *)NULL); + Tcl_AppendResult(interp, "bad signal name \"", argv[i], + "\" for -ttycontrol: must be DTR, RTS or BREAK", + NULL); } - res = TCL_ERROR; + result = TCL_ERROR; break; } } - ckfree(argv); - return res; + ckfree((char *) argv); + return result; } /* @@ -1910,7 +1912,7 @@ SerialSetOptionProc( * -sysbuffer 4096 or -sysbuffer {64536 4096} */ - int inSize = -1, outSize = -1; + size_t inSize = (size_t) -1, outSize = (size_t) -1; if (Tcl_SplitList(interp, value, &argc, &argv) == TCL_ERROR) { return TCL_ERROR; @@ -1922,24 +1924,20 @@ SerialSetOptionProc( inSize = atoi(argv[0]); outSize = atoi(argv[1]); } - ckfree(argv); + ckfree((char *) argv); if ((argc < 1) || (argc > 2) || (inSize <= 0) || (outSize <= 0)) { if (interp != NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad value \"%s\" for -sysbuffer: should be " - "a list of one or two integers > 0", value)); - Tcl_SetErrorCode(interp, "TCL", "VALUE", "SYS_BUFFER", (char *)NULL); + Tcl_AppendResult(interp, "bad value \"", value, + "\" for -sysbuffer: should be a list of one or two " + "integers > 0", NULL); } return TCL_ERROR; } if (!SetupComm(infoPtr->handle, inSize, outSize)) { if (interp != NULL) { - Tcl_WinConvertError(GetLastError()); - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't setup comm buffers: %s", - Tcl_PosixError(interp))); + Tcl_AppendResult(interp, "can't setup comm buffers", NULL); } return TCL_ERROR; } @@ -1952,12 +1950,18 @@ SerialSetOptionProc( */ if (!GetCommState(infoPtr->handle, &dcb)) { - goto getStateFailed; + if (interp != NULL) { + Tcl_AppendResult(interp, "can't get comm state", NULL); + } + return TCL_ERROR; } dcb.XonLim = (WORD) (infoPtr->sysBufRead*1/2); dcb.XoffLim = (WORD) (infoPtr->sysBufRead*1/4); if (!SetCommState(infoPtr->handle, &dcb)) { - goto setStateFailed; + if (interp != NULL) { + Tcl_AppendResult(interp, "can't set comm state", NULL); + } + return TCL_ERROR; } return TCL_OK; } @@ -1987,10 +1991,7 @@ SerialSetOptionProc( tout.ReadTotalTimeoutConstant = msec; if (!SetCommTimeouts(infoPtr->handle, &tout)) { if (interp != NULL) { - Tcl_WinConvertError(GetLastError()); - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't set comm timeouts: %s", - Tcl_PosixError(interp))); + Tcl_AppendResult(interp, "can't set comm timeouts", NULL); } return TCL_ERROR; } @@ -1999,24 +2000,7 @@ SerialSetOptionProc( } return Tcl_BadChannelOption(interp, optionName, - "closemode mode handshake pollinterval sysbuffer timeout " - "ttycontrol xchar"); - - getStateFailed: - if (interp != NULL) { - Tcl_WinConvertError(GetLastError()); - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't get comm state: %s", Tcl_PosixError(interp))); - } - return TCL_ERROR; - - setStateFailed: - if (interp != NULL) { - Tcl_WinConvertError(GetLastError()); - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't set comm state: %s", Tcl_PosixError(interp))); - } - return TCL_ERROR; + "mode handshake pollinterval sysbuffer timeout ttycontrol xchar"); } /* @@ -2042,9 +2026,9 @@ SerialSetOptionProc( static int SerialGetOptionProc( - void *instanceData, /* File state. */ + ClientData instanceData, /* File state. */ Tcl_Interp *interp, /* For error reporting - can be NULL. */ - const char *optionName, /* Option to get. */ + CONST char *optionName, /* Option to get. */ Tcl_DString *dsPtr) /* Where to store value(s). */ { SerialInfo *infoPtr; @@ -2061,27 +2045,6 @@ SerialGetOptionProc( } /* - * Get option -closemode - */ - - if (len == 0) { - Tcl_DStringAppendElement(dsPtr, "-closemode"); - } - if (len==0 || (len>1 && strncmp(optionName, "-closemode", len)==0)) { - switch (infoPtr->flags & SERIAL_CLOSE_MASK) { - case SERIAL_CLOSE_DRAIN: - Tcl_DStringAppendElement(dsPtr, "drain"); - break; - case SERIAL_CLOSE_DISCARD: - Tcl_DStringAppendElement(dsPtr, "discard"); - break; - default: - Tcl_DStringAppendElement(dsPtr, "default"); - break; - } - } - - /* * Get option -mode */ @@ -2090,14 +2053,12 @@ SerialGetOptionProc( } if (len==0 || (len>2 && (strncmp(optionName, "-mode", len) == 0))) { char parity; - const char *stop; + char *stop; char buf[2 * TCL_INTEGER_SPACE + 16]; if (!GetCommState(infoPtr->handle, &dcb)) { if (interp != NULL) { - Tcl_WinConvertError(GetLastError()); - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't get comm state: %s", Tcl_PosixError(interp))); + Tcl_AppendResult(interp, "can't get comm state", NULL); } return TCL_ERROR; } @@ -2110,7 +2071,7 @@ SerialGetOptionProc( stop = (dcb.StopBits == ONESTOPBIT) ? "1" : (dcb.StopBits == ONE5STOPBITS) ? "1.5" : "2"; - snprintf(buf, sizeof(buf), "%ld,%c,%d,%s", dcb.BaudRate, parity, + wsprintfA(buf, "%d,%c,%d,%s", dcb.BaudRate, parity, dcb.ByteSize, stop); Tcl_DStringAppendElement(dsPtr, buf); } @@ -2126,7 +2087,7 @@ SerialGetOptionProc( char buf[TCL_INTEGER_SPACE + 1]; valid = 1; - snprintf(buf, sizeof(buf), "%d", infoPtr->blockTime); + wsprintfA(buf, "%d", infoPtr->blockTime); Tcl_DStringAppendElement(dsPtr, buf); } @@ -2142,9 +2103,9 @@ SerialGetOptionProc( char buf[TCL_INTEGER_SPACE + 1]; valid = 1; - snprintf(buf, sizeof(buf), "%ld", infoPtr->sysBufRead); + wsprintfA(buf, "%d", infoPtr->sysBufRead); Tcl_DStringAppendElement(dsPtr, buf); - snprintf(buf, sizeof(buf), "%ld", infoPtr->sysBufWrite); + wsprintfA(buf, "%d", infoPtr->sysBufWrite); Tcl_DStringAppendElement(dsPtr, buf); } if (len == 0) { @@ -2165,15 +2126,13 @@ SerialGetOptionProc( if (!GetCommState(infoPtr->handle, &dcb)) { if (interp != NULL) { - Tcl_WinConvertError(GetLastError()); - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't get comm state: %s", Tcl_PosixError(interp))); + Tcl_AppendResult(interp, "can't get comm state", NULL); } return TCL_ERROR; } - buf[Tcl_UniCharToUtf(UCHAR(dcb.XonChar), buf)] = '\0'; + sprintf(buf, "%c", dcb.XonChar); Tcl_DStringAppendElement(dsPtr, buf); - buf[Tcl_UniCharToUtf(UCHAR(dcb.XoffChar), buf)] = '\0'; + sprintf(buf, "%c", dcb.XoffChar); Tcl_DStringAppendElement(dsPtr, buf); } if (len == 0) { @@ -2225,9 +2184,9 @@ SerialGetOptionProc( count = (int) cStat.cbOutQue + infoPtr->writeQueue; LeaveCriticalSection(&infoPtr->csWrite); - snprintf(buf, sizeof(buf), "%ld", inBuffered + cStat.cbInQue); + wsprintfA(buf, "%d", inBuffered + cStat.cbInQue); Tcl_DStringAppendElement(dsPtr, buf); - snprintf(buf, sizeof(buf), "%d", outBuffered + count); + wsprintfA(buf, "%d", outBuffered + count); Tcl_DStringAppendElement(dsPtr, buf); } @@ -2243,9 +2202,7 @@ SerialGetOptionProc( if (!GetCommModemStatus(infoPtr->handle, &status)) { if (interp != NULL) { - Tcl_WinConvertError(GetLastError()); - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "can't get tty status: %s", Tcl_PosixError(interp))); + Tcl_AppendResult(interp, "can't get tty status", NULL); } return TCL_ERROR; } @@ -2255,10 +2212,10 @@ SerialGetOptionProc( if (valid) { return TCL_OK; + } else { + return Tcl_BadChannelOption(interp, optionName, + "mode pollinterval lasterror queue sysbuffer ttystatus xchar"); } - return Tcl_BadChannelOption(interp, optionName, - "closemode mode pollinterval lasterror queue sysbuffer ttystatus " - "xchar"); } /* @@ -2279,7 +2236,7 @@ SerialGetOptionProc( static void SerialThreadActionProc( - void *instanceData, + ClientData instanceData, int action) { SerialInfo *infoPtr = (SerialInfo *) instanceData; @@ -2287,7 +2244,7 @@ SerialThreadActionProc( /* * We do not access firstSerialPtr in the thread structures. This is not * for all serials managed by the thread, but only those we are watching. - * Removal of the fileevent handlers before transfer thus takes care of + * Removal of the filevent handlers before transfer thus takes care of * this structure. */ |
