From: Leopold Gerlinger Date: Wed, 3 Dec 2008 11:48:37 +0000 (+0100) Subject: Provide support for the FTDI serial properties. X-Git-Url: http://privyetmir.co.uk/gitweb?a=commitdiff_plain;h=ff57a4670708813188734fd49b3f191cba423ab1;p=tclftd2xx Provide support for the FTDI serial properties. This patch makes it possible to use -mode, -handshake and -xchar in the fconfigure command similar to using direct serial lines. Additionally I extended the open procedure to set the defaults to 19200,n,8,1 no handshake and standard xon/xoff chars. If you know about another way of doing these things please let me know. The -xchar option is currently only supporting chars in the range from 1 .. 127 dec, maybe you know of a way how to extend this to at least the full ASCII charset (I'm obviously no expert in encodings ;-). Signed-off-by: Leopold Gerlinger Signed-off-by: Pat Thoyts --- diff --git a/tclftd2xx.c b/tclftd2xx.c index 1185d2b..f025f11 100644 --- a/tclftd2xx.c +++ b/tclftd2xx.c @@ -15,6 +15,8 @@ #include #include "ftd2xx.h" +#define PACKAGE_VERSION "1.0.0" + typedef FT_STATUS (WINAPI FT_CloseProc)(FT_HANDLE); typedef FT_STATUS (WINAPI FT_CreateDeviceInfoListProc)(LPDWORD); typedef FT_STATUS (WINAPI FT_GetDeviceInfoListProc) @@ -31,6 +33,10 @@ typedef FT_STATUS (WINAPI FT_SetTimeoutsProc)(FT_HANDLE,ULONG,ULONG); typedef FT_STATUS (WINAPI FT_WriteProc)(FT_HANDLE,LPVOID,DWORD,LPDWORD); typedef FT_STATUS (WINAPI FT_GetLibraryVersionProc)(LPDWORD); typedef FT_STATUS (WINAPI FT_RescanProc)(VOID); +typedef FT_STATUS (WINAPI FT_SetBaudRateProc)(FT_HANDLE,ULONG); +typedef FT_STATUS (WINAPI FT_SetDataCharacteristicsProc) + (FT_HANDLE,UCHAR,UCHAR,UCHAR); +typedef FT_STATUS (WINAPI FT_SetFlowControlProc)(FT_HANDLE,USHORT,UCHAR,UCHAR); typedef struct FTDIPROCS { FT_CloseProc *FT_Close; @@ -48,6 +54,9 @@ typedef struct FTDIPROCS { FT_WriteProc *FT_Write; FT_GetLibraryVersionProc *FT_GetLibraryVersion; FT_RescanProc *FT_Rescan; + FT_SetBaudRateProc *FT_SetBaudRate; + FT_SetDataCharacteristicsProc *FT_SetDataCharacteristics; + FT_SetFlowControlProc *FT_SetFlowControl; } FTDIPROCS; static FTDIPROCS procs; @@ -64,6 +73,13 @@ typedef struct Channel { int flags; int watchmask; int validmask; + int baudrate; + unsigned char parity; + unsigned short handshake; + char xonchar; + char xoffchar; + unsigned char databits; + unsigned char stopbits; unsigned long rxtimeout; unsigned long txtimeout; FT_HANDLE handle; @@ -271,11 +287,92 @@ ChannelSetOption(ClientData instance, Tcl_Interp *interp, } } } else if (!strcmp("-latency", optionName)) { - int tmp = 1; - r = Tcl_GetInt(interp, newValue, &tmp); - if (r == TCL_OK) { - fts = procs.FT_SetLatencyTimer(instPtr->handle, (UCHAR)tmp); - } + int tmp = 1; + r = Tcl_GetInt(interp, newValue, &tmp); + if (r == TCL_OK) { + fts = procs.FT_SetLatencyTimer(instPtr->handle, (UCHAR)tmp); + } + } else if (!strcmp("-mode", optionName)) { + int baudrate, databits, stopbits; + char parity; + int args; + + if ((args = sscanf(newValue, "%d,%c,%d,%d", &baudrate, &parity, &databits, &stopbits)) != 4) { + Tcl_AppendResult(interp, "error setting mode: ", NULL); + return TCL_ERROR; + } + + switch (databits) { + case 8: databits = FT_BITS_8; break; + case 7: databits = FT_BITS_7; break; + case 6: databits = FT_BITS_6; break; + case 5: databits = FT_BITS_5; break; + default: + Tcl_AppendResult(interp, "error setting mode: databit count not supported", NULL); + return TCL_ERROR; + } + + switch (stopbits) { + case 1: stopbits = FT_STOP_BITS_1; break; + case 2: stopbits = FT_STOP_BITS_2; break; + default: + Tcl_AppendResult(interp, "error setting mode: stopbit count not supported", NULL); + return TCL_ERROR; + } + + switch (parity) { + case 'n': parity = FT_PARITY_NONE; break; + case 'o': parity = FT_PARITY_ODD; break; + case 'e': parity = FT_PARITY_EVEN; break; + case 'm': parity = FT_PARITY_MARK; break; + case 's': parity = FT_PARITY_SPACE; break; + default: + Tcl_AppendResult(interp, "error setting mode: parity not supported", NULL); + return TCL_ERROR; + } + + if ((fts = procs.FT_SetBaudRate(instPtr->handle, baudrate)) != FT_OK) { + Tcl_AppendResult(interp, "failed set baudrate: \"", + ConvertError(fts), NULL); + return TCL_ERROR; + } + + if ((fts = procs.FT_SetDataCharacteristics(instPtr->handle, databits, stopbits, parity)) != FT_OK) { + Tcl_AppendResult(interp, "failed set data characteristics: \"", + ConvertError(fts), NULL); + return TCL_ERROR; + } + + instPtr->baudrate = baudrate; + instPtr->databits = databits; + instPtr->stopbits = stopbits; + instPtr->parity = parity; + } else if (!strcmp("-handshake", optionName)) { + unsigned short handshake = 0xFFFF; + if (!strcmp(newValue,"none")) { + handshake = FT_FLOW_NONE; + } else if (!strcmp(newValue,"rtscts")) { + handshake = FT_FLOW_RTS_CTS; + } else if (!strcmp(newValue,"dtrdsr")) { + handshake = FT_FLOW_DTR_DSR; + } else if (!strcmp(newValue,"xonxoff")) { + handshake = FT_FLOW_XON_XOFF; + } else { + Tcl_AppendResult(interp, "error setting handshake: handshake not supported", NULL); + return TCL_ERROR; + } + if ((fts = procs.FT_SetFlowControl(instPtr->handle, handshake, instPtr->xonchar, instPtr->xoffchar)) == FT_OK) + instPtr->handshake = handshake; + } else if (!strcmp("-xchar", optionName)) { + if (strlen(newValue) != 3) { + Tcl_AppendResult(interp, "error setting xon/xoff characters: values < 1 and > 127 not supported", NULL); + return TCL_ERROR; + } + + if ((fts = procs.FT_SetFlowControl(instPtr->handle, FT_FLOW_NONE, newValue[0], newValue[2])) == FT_OK) { + instPtr->xonchar = newValue[0]; + instPtr->xoffchar = newValue[2]; + } } if (fts != FT_OK) { @@ -284,7 +381,7 @@ ChannelSetOption(ClientData instance, Tcl_Interp *interp, r = TCL_ERROR; } - return TCL_OK; + return r; } /** @@ -298,7 +395,7 @@ ChannelGetOption(ClientData instance, Tcl_Interp *interp, const char *optionName, Tcl_DString *optionValue) { Channel *instPtr = instance; - const char *options[] = {"readtimeout", "writetimeout", "latency", NULL}; + const char *options[] = {"readtimeout", "writetimeout", "latency", "mode", "handshake", "xchar", NULL}; int r = TCL_OK; if (optionName == NULL) { @@ -339,6 +436,35 @@ ChannelGetOption(ClientData instance, Tcl_Interp *interp, ConvertError(fts), NULL); r = TCL_ERROR; } + } else if (!strcmp("-mode", optionName)) { + char parity = 0; + switch (instPtr->parity) { + case FT_PARITY_NONE: parity = 'n'; break; + case FT_PARITY_ODD: parity = 'o'; break; + case FT_PARITY_EVEN: parity = 'e'; break; + case FT_PARITY_MARK: parity = 'm'; break; + case FT_PARITY_SPACE: parity = 's'; break; + default: parity = '?'; + } + Tcl_DStringSetLength(&ds, 64); + sprintf(Tcl_DStringValue(&ds), "%d,%c,%d,%d", + instPtr->baudrate, parity, instPtr->databits, + instPtr->stopbits == FT_STOP_BITS_1 ? 1 : 2); + } else if (!strcmp("-handshake", optionName)) { + switch (instPtr->handshake) { + case FT_FLOW_NONE: Tcl_DStringAppend(&ds, "none", 4); break; + case FT_FLOW_RTS_CTS: Tcl_DStringAppend(&ds, "rtscts", 6); break; + case FT_FLOW_DTR_DSR: Tcl_DStringAppend(&ds, "dtrdsr", 6); break; + case FT_FLOW_XON_XOFF: Tcl_DStringAppend(&ds, "xonxoff", 7); break; + default : Tcl_DStringAppend(&ds, "unknown", 7); + } + } else if (!strcmp("-xchar", optionName)) { + char cbuf[2]; + cbuf[1] = 0; + cbuf[0] = instPtr->xonchar; + Tcl_DStringAppendElement(&ds, cbuf); + cbuf[0] = instPtr->xoffchar; + Tcl_DStringAppendElement(&ds, cbuf); } else { const char **p; for (p = options; *p != NULL; ++p) { @@ -611,6 +737,25 @@ OpenCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv devname, "\": ", ConvertError(fts), NULL); return TCL_ERROR; } + + if ((fts = procs.FT_SetBaudRate(handle, 19200)) != FT_OK) { + Tcl_AppendResult(interp, "failed set baudrate: \"", + ConvertError(fts), NULL); + return TCL_ERROR; + } + + if ((fts = procs.FT_SetDataCharacteristics(handle, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE)) != FT_OK) { + Tcl_AppendResult(interp, "failed set data characteristics: \"", + ConvertError(fts), NULL); + return TCL_ERROR; + } + + if ((fts = procs.FT_SetFlowControl(handle, FT_FLOW_NONE, 0x11, 0x13)) != FT_OK) { + Tcl_AppendResult(interp, "failed set flowcontrol: \"", + ConvertError(fts), NULL); + return TCL_ERROR; + } + if ((fts = procs.FT_SetTimeouts(handle, rxtimeout, txtimeout)) != FT_OK) { procs.FT_Close(handle); Tcl_AppendResult(interp, "failed initialize timeouts: ", @@ -631,6 +776,13 @@ OpenCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv instPtr->flags = 0; instPtr->watchmask = 0; instPtr->validmask = TCL_READABLE | TCL_WRITABLE; + instPtr->baudrate = 19200; + instPtr->parity = FT_PARITY_NONE; + instPtr->databits = FT_BITS_8; + instPtr->stopbits = FT_STOP_BITS_1; + instPtr->handshake = FT_FLOW_NONE; + instPtr->xonchar = 0x11; + instPtr->xoffchar = 0x13; instPtr->rxtimeout = rxtimeout; instPtr->txtimeout = txtimeout; instPtr->handle = handle; @@ -913,7 +1065,11 @@ Ftd2xx_Init(Tcl_Interp *interp) || LOADPROC(FT_SetTimeouts) || LOADPROC(FT_Write) || LOADPROC(FT_GetLibraryVersion) - || LOADPROC(FT_Rescan) ) + || LOADPROC(FT_Rescan) + || LOADPROC(FT_SetBaudRate) + || LOADPROC(FT_SetDataCharacteristics) + || LOADPROC(FT_SetFlowControl) + ) { Tcl_SetResult(interp, "invalid ftd2xx.dll library!", TCL_STATIC); Tcl_SetErrorCode(interp, "DLL_INVALID", szDllName, NULL);