summaryrefslogtreecommitdiffstats
path: root/win/tclWinSerial.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinSerial.c')
-rw-r--r--win/tclWinSerial.c559
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.
*/