|
|
@@ -0,0 +1,1190 @@
|
|
|
+/*
|
|
|
+ * Copyright (c) 2011 Petr Stetiar <ynezz@true.cz>, Gaben Ltd.
|
|
|
+ *
|
|
|
+ * Permission is hereby granted, free of charge, to any person
|
|
|
+ * obtaining a copy of this software and associated documentation
|
|
|
+ * files (the "Software"), to deal in the Software without
|
|
|
+ * restriction, including without limitation the rights to use,
|
|
|
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
+ * copies of the Software, and to permit persons to whom the
|
|
|
+ * Software is furnished to do so, subject to the following
|
|
|
+ * conditions:
|
|
|
+ *
|
|
|
+ * The above copyright notice and this permission notice shall be
|
|
|
+ * included in all copies or substantial portions of the Software.
|
|
|
+ *
|
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
|
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
|
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
|
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
+ * OTHER DEALINGS IN THE SOFTWARE.
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+#include <ctype.h>
|
|
|
+#include <assert.h>
|
|
|
+
|
|
|
+#ifndef UNDER_CE
|
|
|
+#include <errno.h>
|
|
|
+#endif
|
|
|
+
|
|
|
+#include "librs232/rs232.h"
|
|
|
+
|
|
|
+typedef DWORD monotonic_time_t;
|
|
|
+typedef DWORD monotonic_diff_t;
|
|
|
+
|
|
|
+static monotonic_time_t GetMonotonicTime(){
|
|
|
+ return GetTickCount();
|
|
|
+}
|
|
|
+
|
|
|
+static monotonic_diff_t GetMonotonicDelta(monotonic_time_t StartTime, monotonic_time_t EndTime){
|
|
|
+ if(StartTime > EndTime)
|
|
|
+ return (MAXDWORD - StartTime) + EndTime;
|
|
|
+ return EndTime - StartTime;
|
|
|
+}
|
|
|
+
|
|
|
+#define READ_EVENTS (EV_RXCHAR | EV_ERR | EV_BREAK)
|
|
|
+#define READ_LATENTENCY 500
|
|
|
+#define R_BUFFER_SIZE 1024
|
|
|
+#define W_BUFFER_SIZE 1024
|
|
|
+
|
|
|
+#define USE_OVERLAPPED
|
|
|
+
|
|
|
+static wchar_t *
|
|
|
+a2w(const char *astr)
|
|
|
+{
|
|
|
+ size_t len = 0;
|
|
|
+ wchar_t *ret = NULL;
|
|
|
+
|
|
|
+ if (astr == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ len = strlen(astr);
|
|
|
+ if (len > 0) {
|
|
|
+ ret = (wchar_t*)malloc((len*2)+1 * sizeof(wchar_t*));
|
|
|
+ memset(ret, 0, (len*2));
|
|
|
+ MultiByteToWideChar(CP_ACP, 0, astr, -1, ret, (int)len);
|
|
|
+ ret[len] = '\0';
|
|
|
+ } else
|
|
|
+ ret = NULL;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef RS232_DEBUG
|
|
|
+static char * last_error(void)
|
|
|
+{
|
|
|
+ DWORD err = 0;
|
|
|
+ DWORD ret = 0;
|
|
|
+ char errbuf[MAX_PATH+1] = {0};
|
|
|
+ static char retbuf[MAX_PATH+1] = {0};
|
|
|
+
|
|
|
+ err = GetLastError();
|
|
|
+ ret = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, errbuf, MAX_PATH, NULL);
|
|
|
+ if (ret != 0) {
|
|
|
+ /* CRLF fun */
|
|
|
+ errbuf[ret-2] = 0;
|
|
|
+ snprintf(retbuf, MAX_PATH, "LastError: %s (%ld)", errbuf, ret);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ snprintf(retbuf, MAX_PATH, "LastError: %ld (FormatMessageA failed)", ret);
|
|
|
+
|
|
|
+ return retbuf;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+RS232_LIB struct rs232_port_t *
|
|
|
+rs232_init(void)
|
|
|
+{
|
|
|
+ struct rs232_port_t *p = NULL;
|
|
|
+ struct rs232_windows_t *wx = NULL;
|
|
|
+ p = (struct rs232_port_t *) malloc(sizeof(struct rs232_port_t));
|
|
|
+ if (p == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ p->pt = (struct rs232_windows_t *) malloc(sizeof(struct rs232_windows_t));
|
|
|
+ if (p->pt == NULL) {
|
|
|
+ free(p);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p\n", (void *)p, p->pt);
|
|
|
+
|
|
|
+ memset(p->dev, 0, RS232_STRLEN_DEVICE+1);
|
|
|
+ strncpyz(p->dev, RS232_PORT_WIN32, RS232_STRLEN_DEVICE);
|
|
|
+
|
|
|
+ p->baud = RS232_BAUD_115200;
|
|
|
+ p->data = RS232_DATA_8;
|
|
|
+ p->parity = RS232_PARITY_NONE;
|
|
|
+ p->stop = RS232_STOP_1;
|
|
|
+ p->flow = RS232_FLOW_OFF;
|
|
|
+ p->status = RS232_PORT_CLOSED;
|
|
|
+ p->dtr = RS232_DTR_OFF;
|
|
|
+ p->rts = RS232_RTS_OFF;
|
|
|
+
|
|
|
+ wx = (struct rs232_windows_t *) p->pt;
|
|
|
+ wx->r_timeout = READ_LATENTENCY;
|
|
|
+ wx->w_timeout = READ_LATENTENCY;
|
|
|
+ wx->r_buffer = R_BUFFER_SIZE;
|
|
|
+ wx->w_buffer = W_BUFFER_SIZE;
|
|
|
+
|
|
|
+ return p;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+port_buffers(struct rs232_port_t *p, unsigned int rb, unsigned int wb)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p rb=%d wb=%d\n", (void *)p, p->pt, rb, wb);
|
|
|
+
|
|
|
+ if (!SetupComm(wx->fd, rb, wb)) {
|
|
|
+ DBG("SetupComm() %s\n", last_error());
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ wx->r_buffer = rb;
|
|
|
+ wx->w_buffer = wb;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+port_timeout(struct rs232_port_t *p, unsigned int rt, unsigned int wt)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+ COMMTIMEOUTS t;
|
|
|
+
|
|
|
+ GET_PORT_TIMEOUTS(wx->fd, &t);
|
|
|
+
|
|
|
+ t.ReadIntervalTimeout = 0;
|
|
|
+ t.ReadTotalTimeoutMultiplier = 0;
|
|
|
+ t.ReadTotalTimeoutConstant = rt;
|
|
|
+ t.WriteTotalTimeoutMultiplier = 0;
|
|
|
+ t.WriteTotalTimeoutConstant = wt;
|
|
|
+
|
|
|
+ SET_PORT_TIMEOUTS(wx->fd, &t);
|
|
|
+
|
|
|
+ wx->w_timeout = wt;
|
|
|
+ wx->r_timeout = rt;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB void
|
|
|
+rs232_end(struct rs232_port_t *p)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p\n", (void *)p, p->pt);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p)) {
|
|
|
+ free(p->pt);
|
|
|
+ free(p);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ rs232_flush(p);
|
|
|
+
|
|
|
+ if (!SetCommState(wx->fd, &wx->old_dcb)) {
|
|
|
+ DBG("SetCommState() %s\n", last_error());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!SetCommTimeouts(wx->fd, &wx->old_tm)) {
|
|
|
+ DBG("SetCommTimeouts() %s\n", last_error());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ rs232_close(p);
|
|
|
+ free(p->pt);
|
|
|
+ free(p);
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_in_queue(struct rs232_port_t *p, unsigned int *in_bytes)
|
|
|
+{
|
|
|
+ COMSTAT cs;
|
|
|
+ unsigned long errmask = 0;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p\n", (void *)p, p->pt);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ if (!ClearCommError(wx->fd, &errmask, &cs)) {
|
|
|
+ DBG("ClearCommError() %s\n", last_error());
|
|
|
+ return RS232_ERR_IOCTL;
|
|
|
+ }
|
|
|
+
|
|
|
+ *in_bytes = cs.cbInQue;
|
|
|
+ DBG("in_bytes=%d\n", cs.cbInQue);
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+/* some USB<->RS232 converters buffer a lot, so this function tries to discard
|
|
|
+ this buffer - useful mainly after rs232_open() */
|
|
|
+RS232_LIB void
|
|
|
+rs232_in_queue_clear(struct rs232_port_t *p)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p\n", (void *)p, p->pt);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!PurgeComm(wx->fd, PURGE_RXABORT | PURGE_RXCLEAR)) {
|
|
|
+ DBG("PurgeComm() %s\n", last_error());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+//{ Non overlapped IO
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_read_impl(struct rs232_port_t *p, unsigned char *buf, unsigned int buf_len,
|
|
|
+ unsigned int *read_len)
|
|
|
+{
|
|
|
+ DWORD r = 0;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ if (!ReadFile(wx->fd, buf, buf_len, &r, NULL)) {
|
|
|
+ *read_len = 0;
|
|
|
+ DBG("ReadFile() %s\n", last_error());
|
|
|
+ return RS232_ERR_READ;
|
|
|
+ }
|
|
|
+
|
|
|
+ *read_len = r;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_read_timeout_impl(struct rs232_port_t *p, unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *read_len,
|
|
|
+ unsigned int timeout)
|
|
|
+{
|
|
|
+ DWORD r = 0;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+ unsigned int rt = wx->r_timeout;
|
|
|
+
|
|
|
+ *read_len = 0;
|
|
|
+
|
|
|
+ if (port_timeout(p, timeout, wx->w_timeout))
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+
|
|
|
+ if (!ReadFile(wx->fd, buf, buf_len, &r, NULL)) {
|
|
|
+ *read_len = 0;
|
|
|
+ DBG("ReadFile() %s\n", last_error());
|
|
|
+ return RS232_ERR_READ;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (port_timeout(p, rt, wx->w_timeout))
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+
|
|
|
+ *read_len = r;
|
|
|
+
|
|
|
+ /* TODO - This is lame, since we rely on the fact, that if we read 0 bytes,
|
|
|
+ * that the read probably timeouted. So we should rather measure the reading
|
|
|
+ * interval or rework it using overlapped I/O */
|
|
|
+ return *read_len == 0 ? RS232_ERR_TIMEOUT : RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+/* this function waits either for timeout or buf_len bytes,
|
|
|
+ whatever happens first and doesn't return earlier */
|
|
|
+static unsigned int
|
|
|
+rs232_read_timeout_forced_impl(struct rs232_port_t *p, unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *read_len,
|
|
|
+ unsigned int timeout)
|
|
|
+{
|
|
|
+ monotonic_time_t started = GetMonotonicTime();
|
|
|
+
|
|
|
+ *read_len = 0;
|
|
|
+ while(*read_len < buf_len){
|
|
|
+ monotonic_diff_t elapsed = GetMonotonicDelta(started, GetMonotonicTime());
|
|
|
+ unsigned int ret, readed = 0;
|
|
|
+ if(elapsed >= timeout){
|
|
|
+ return RS232_ERR_TIMEOUT;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = rs232_read_timeout_impl(p, &buf[*read_len], buf_len - *read_len, &readed, timeout - elapsed);
|
|
|
+ if(ret == RS232_ERR_NOERROR){
|
|
|
+ *read_len += readed;
|
|
|
+ }
|
|
|
+ else if(ret != RS232_ERR_TIMEOUT){
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_write_impl(struct rs232_port_t *p, const unsigned char *buf, unsigned int buf_len,
|
|
|
+ unsigned int *write_len)
|
|
|
+{
|
|
|
+ DWORD w = 0;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ if (!WriteFile(wx->fd, buf, buf_len, &w, NULL)) {
|
|
|
+ *write_len = 0;
|
|
|
+ DBG("WriteFile() %s\n", last_error());
|
|
|
+ return RS232_ERR_WRITE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (buf_len != w)
|
|
|
+ DBG("WriteFile() %s\n", last_error());
|
|
|
+
|
|
|
+ *write_len = w;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_write_timeout_impl(struct rs232_port_t *p, const unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *write_len,
|
|
|
+ unsigned int timeout)
|
|
|
+{
|
|
|
+ DWORD w = 0;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+ unsigned int wt = wx->w_timeout;
|
|
|
+
|
|
|
+ if (port_timeout(p, wx->r_timeout, timeout))
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+
|
|
|
+ if (!WriteFile(wx->fd, buf, buf_len, &w, NULL)) {
|
|
|
+ *write_len = 0;
|
|
|
+ DBG("WriteFile() %s\n", last_error());
|
|
|
+ return RS232_ERR_WRITE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (port_timeout(p, wx->r_timeout, wt))
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+
|
|
|
+ *write_len = w;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+//}
|
|
|
+
|
|
|
+//{ Overlapped IO
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+poll_ovl(struct rs232_port_t *p, unsigned int timeout, DWORD events, DWORD *mask){
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+ DWORD ret;
|
|
|
+ monotonic_time_t started = GetMonotonicTime();
|
|
|
+
|
|
|
+ if(!SetCommMask(wx->fd, events))
|
|
|
+ return RS232_ERR_IOCTL;
|
|
|
+
|
|
|
+ *mask = 0;
|
|
|
+
|
|
|
+ while(1){
|
|
|
+ monotonic_diff_t elapsed = GetMonotonicDelta(started, GetMonotonicTime());
|
|
|
+ if(elapsed >= timeout)
|
|
|
+ return RS232_ERR_TIMEOUT;
|
|
|
+
|
|
|
+ if(!wx->wait_progress){
|
|
|
+ wx->wait_mask = 0;
|
|
|
+ if (WaitCommEvent(wx->fd, &wx->wait_mask, &wx->oWait))
|
|
|
+ goto readed;
|
|
|
+
|
|
|
+ if (GetLastError() != ERROR_IO_PENDING)
|
|
|
+ return RS232_ERR_IOCTL;
|
|
|
+ }
|
|
|
+
|
|
|
+ wx->wait_progress = 1;
|
|
|
+
|
|
|
+ ret = WaitForSingleObject(wx->oWait.hEvent, timeout - elapsed);
|
|
|
+ if(ret != WAIT_OBJECT_0)
|
|
|
+ return RS232_ERR_TIMEOUT;
|
|
|
+
|
|
|
+ if(!GetOverlappedResult(wx->fd, &wx->oWait, &ret, FALSE))
|
|
|
+ return RS232_ERR_IOCTL;
|
|
|
+
|
|
|
+readed:
|
|
|
+
|
|
|
+ wx->wait_progress = 0;
|
|
|
+
|
|
|
+ if(wx->wait_mask)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ *mask = wx->wait_mask;
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+read_n_ovl(struct rs232_port_t *p, unsigned char *buf, unsigned int buf_len,
|
|
|
+ DWORD *read_len, DWORD *ermask
|
|
|
+)
|
|
|
+{
|
|
|
+ /* read avaliable data without waiting */
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+ OVERLAPPED ovl = {0};
|
|
|
+ COMSTAT cs = {0};
|
|
|
+ DWORD readed, avaliable;
|
|
|
+
|
|
|
+ *read_len = 0;
|
|
|
+
|
|
|
+ if (!ClearCommError(wx->fd, ermask, &cs))
|
|
|
+ return RS232_ERR_IOCTL;
|
|
|
+
|
|
|
+ avaliable = cs.cbInQue > buf_len ? buf_len : cs.cbInQue;
|
|
|
+ if (avaliable) {
|
|
|
+ if (!ReadFile(wx->fd, buf, avaliable, &readed, &ovl)) {
|
|
|
+ if (GetLastError() != ERROR_IO_PENDING)
|
|
|
+ return RS232_ERR_READ;
|
|
|
+
|
|
|
+ if(!GetOverlappedResult(wx->fd, &ovl, &readed, TRUE))
|
|
|
+ return RS232_ERR_READ;
|
|
|
+ }
|
|
|
+ *read_len = readed;
|
|
|
+ }
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_read_ovl(struct rs232_port_t *p, unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *read_len,
|
|
|
+ unsigned int timeout, unsigned int lat,
|
|
|
+ DWORD events, unsigned int *evmask
|
|
|
+)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+ monotonic_time_t started = GetMonotonicTime();
|
|
|
+ unsigned char *ptr = buf;
|
|
|
+
|
|
|
+ *read_len = 0;
|
|
|
+
|
|
|
+ while (1) {
|
|
|
+ DWORD readed, error_mask, event_mask;
|
|
|
+ unsigned int ret;
|
|
|
+ monotonic_diff_t elapsed = GetMonotonicDelta(started, GetMonotonicTime());
|
|
|
+
|
|
|
+ if (elapsed > timeout)
|
|
|
+ return *read_len ? RS232_ERR_NOERROR : RS232_ERR_TIMEOUT;
|
|
|
+
|
|
|
+ ret = read_n_ovl(p, ptr, buf_len - *read_len, &readed, &error_mask);
|
|
|
+
|
|
|
+ if (error_mask) {
|
|
|
+ if (error_mask & CE_BREAK)
|
|
|
+ ret = RS232_ERR_BREAK;
|
|
|
+
|
|
|
+ if (error_mask & CE_RXOVER)
|
|
|
+ ret = RS232_ERR_RXOVERFLOW;
|
|
|
+
|
|
|
+ if (error_mask & CE_OVERRUN)
|
|
|
+ ret = RS232_ERR_OVERRUN;
|
|
|
+
|
|
|
+ if (error_mask & CE_FRAME)
|
|
|
+ ret = RS232_ERR_FRAME;
|
|
|
+
|
|
|
+ if (error_mask & CE_RXPARITY)
|
|
|
+ ret = RS232_ERR_PARITY;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret != RS232_ERR_NOERROR)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if(readed){/* reduce timeout to max latentency*/
|
|
|
+ if((timeout - elapsed) > lat)
|
|
|
+ timeout = elapsed + lat;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!readed){
|
|
|
+ ret = poll_ovl(p, timeout - elapsed, events, &event_mask);
|
|
|
+
|
|
|
+ if(evmask) *evmask = event_mask;
|
|
|
+
|
|
|
+ if(ret != RS232_ERR_NOERROR)
|
|
|
+ return *read_len ? RS232_ERR_NOERROR : RS232_ERR_TIMEOUT;
|
|
|
+
|
|
|
+ //! @todo check event_mask (e.g. (event_mask & EV_BREAK) || (event_mask & EV_ERR))
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ ptr += readed;
|
|
|
+ *read_len += readed;
|
|
|
+
|
|
|
+ assert(*read_len <= buf_len);
|
|
|
+
|
|
|
+ if(*read_len == buf_len)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_read_ovl_impl(struct rs232_port_t *p, unsigned char *buf, unsigned int buf_len,
|
|
|
+ unsigned int *read_len)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ return rs232_read_ovl(p, buf, buf_len, read_len, INFINITE, READ_LATENTENCY, READ_EVENTS, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+/* this function waits either for timeout or buf_len bytes,
|
|
|
+ whatever happens first and doesn't return earlier */
|
|
|
+static unsigned int
|
|
|
+rs232_read_timeout_forced_ovl_impl(struct rs232_port_t *p, unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *read_len,
|
|
|
+ unsigned int timeout)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ return rs232_read_ovl(p, buf, buf_len, read_len, timeout, timeout, READ_EVENTS, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_read_timeout_ovl_impl(struct rs232_port_t *p, unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *read_len,
|
|
|
+ unsigned int timeout)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ return rs232_read_ovl(p, buf, buf_len, read_len, timeout, READ_LATENTENCY, READ_EVENTS, NULL);
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_write_ovl(struct rs232_port_t *p, const unsigned char *buf, unsigned int buf_len,
|
|
|
+ unsigned int *write_len)
|
|
|
+{
|
|
|
+ OVERLAPPED oWrite = {0};
|
|
|
+ DWORD w = 0;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ *write_len = 0;
|
|
|
+
|
|
|
+ if(!WriteFile(wx->fd, buf, buf_len, &w, &oWrite)){
|
|
|
+ DWORD ret;
|
|
|
+ if(GetLastError() != ERROR_IO_PENDING){
|
|
|
+ DBG("WriteFile() %s\n", last_error());
|
|
|
+ return RS232_ERR_WRITE;
|
|
|
+ }
|
|
|
+ if(!GetOverlappedResult(wx->fd, &oWrite, &ret, TRUE)){
|
|
|
+ DBG("OverlappedResult() %s\n", last_error());
|
|
|
+ // wtf? If we get error how cancel current write operation?
|
|
|
+ return RS232_ERR_WRITE;
|
|
|
+ }
|
|
|
+ w = ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ *write_len = w;
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_write_ovl_impl(struct rs232_port_t *p, const unsigned char *buf, unsigned int buf_len,
|
|
|
+ unsigned int *write_len)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+ unsigned int ret;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p buf_len:%d\n", (void *)p, p->pt, buf_len);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ ret = rs232_write_ovl(p, buf, buf_len, write_len);
|
|
|
+ if (ret != RS232_ERR_NOERROR) {
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (buf_len != *write_len)
|
|
|
+ DBG("WriteFile() %s\n", last_error());
|
|
|
+
|
|
|
+ DBG("write_len=%d hex='%s' ascii='%s'\n", *write_len, rs232_hex_dump(buf, w),
|
|
|
+ rs232_ascii_dump(buf, w));
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned int
|
|
|
+rs232_write_timeout_ovl_impl(struct rs232_port_t *p, const unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *write_len,
|
|
|
+ unsigned int timeout)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+ unsigned int wt = wx->w_timeout;
|
|
|
+ unsigned int ret;
|
|
|
+
|
|
|
+ if (port_timeout(p, wx->r_timeout, timeout))
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+
|
|
|
+ ret = rs232_write_ovl(p, buf, buf_len, write_len);
|
|
|
+ if (ret != RS232_ERR_NOERROR)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (port_timeout(p, wx->r_timeout, wt))
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+//}
|
|
|
+
|
|
|
+//{ Public API IP
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_read(struct rs232_port_t *p, unsigned char *buf, unsigned int buf_len,
|
|
|
+ unsigned int *read_len)
|
|
|
+{
|
|
|
+ unsigned int ret;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p buf_len:%d\n", (void *)p, p->pt, buf_len);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+#ifdef USE_OVERLAPPED
|
|
|
+ ret = rs232_read_ovl_impl(p, buf, buf_len, read_len);
|
|
|
+#else
|
|
|
+ ret = rs232_read_impl(p, buf, buf_len, read_len);
|
|
|
+#endif
|
|
|
+
|
|
|
+ DBG("read_len=%d hex='%s' ascii='%s'\n", r, rs232_hex_dump(buf, *read_len),
|
|
|
+ rs232_ascii_dump(buf, *read_len));
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/* this function waits either for timeout or buf_len bytes,
|
|
|
+ whatever happens first and doesn't return earlier */
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_read_timeout_forced(struct rs232_port_t *p, unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *read_len,
|
|
|
+ unsigned int timeout)
|
|
|
+{
|
|
|
+ unsigned int ret;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p buf_len:%d timeout:%d\n", (void *)p, p->pt, buf_len, timeout);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+#ifdef USE_OVERLAPPED
|
|
|
+ ret = rs232_read_timeout_forced_ovl_impl(p, buf, buf_len, read_len, timeout);
|
|
|
+#else
|
|
|
+ ret = rs232_read_timeout_forced_impl(p, buf, buf_len, read_len, timeout);
|
|
|
+#endif
|
|
|
+
|
|
|
+ DBG("read_len=%d hex='%s' ascii='%s'\n", r, rs232_hex_dump(buf, *read_len),
|
|
|
+ rs232_ascii_dump(buf, *read_len));
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_read_timeout(struct rs232_port_t *p, unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *read_len,
|
|
|
+ unsigned int timeout)
|
|
|
+{
|
|
|
+ unsigned int ret;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p buf_len:%d timeout:%d\n", (void *)p, p->pt, buf_len, timeout);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+#ifdef USE_OVERLAPPED
|
|
|
+ ret = rs232_read_timeout_ovl_impl(p, buf, buf_len, read_len, timeout);
|
|
|
+#else
|
|
|
+ ret = rs232_read_timeout_impl(p, buf, buf_len, read_len, timeout);
|
|
|
+#endif
|
|
|
+
|
|
|
+ DBG("read_len=%d hex='%s' ascii='%s'\n", r, rs232_hex_dump(buf, *read_len),
|
|
|
+ rs232_ascii_dump(buf, *read_len));
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_write(struct rs232_port_t *p, const unsigned char *buf, unsigned int buf_len,
|
|
|
+ unsigned int *write_len)
|
|
|
+{
|
|
|
+ unsigned int ret;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p buf_len:%d\n", (void *)p, p->pt, buf_len);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+#ifdef USE_OVERLAPPED
|
|
|
+ ret = rs232_write_ovl_impl(p, buf, buf_len, write_len);
|
|
|
+#else
|
|
|
+ ret = rs232_write_impl(p, buf, buf_len, write_len);
|
|
|
+#endif
|
|
|
+
|
|
|
+ DBG("write_len=%d hex='%s' ascii='%s'\n", w, rs232_hex_dump(buf, *write_len),
|
|
|
+ rs232_ascii_dump(buf, *write_len));
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_write_timeout(struct rs232_port_t *p, const unsigned char *buf,
|
|
|
+ unsigned int buf_len, unsigned int *write_len,
|
|
|
+ unsigned int timeout)
|
|
|
+{
|
|
|
+ unsigned int ret;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p buf_len:%d timeout: %d\n", (void *)p, p->pt, buf_len, timeout);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+#ifdef USE_OVERLAPPED
|
|
|
+ ret = rs232_write_timeout_ovl_impl(p, buf, buf_len, write_len, timeout);
|
|
|
+#else
|
|
|
+ ret = rs232_write_timeout_impl(p, buf, buf_len, write_len, timeout);
|
|
|
+#endif
|
|
|
+
|
|
|
+ DBG("write_len=%d hex='%s' ascii='%s'\n", w, rs232_hex_dump(buf, *write_len),
|
|
|
+ rs232_ascii_dump(buf, *write_len));
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+//}
|
|
|
+
|
|
|
+static char *
|
|
|
+fix_device_name(char *device, char *ret)
|
|
|
+{
|
|
|
+ char *s = device;
|
|
|
+ /* meh, Windows CE is special and can't handle URN path, just COM1: format */
|
|
|
+
|
|
|
+ if((s[0] == '\\')&&(s[1] == '\\')&&(s[2] == '.')&&(s[3] == '\\')){
|
|
|
+#ifdef UNDER_CE
|
|
|
+ /* remove URN prefix */
|
|
|
+ snprintf(ret, RS232_STRLEN_DEVICE, "%s", s + 4);
|
|
|
+ return ret;
|
|
|
+#else
|
|
|
+ return s;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef UNDER_CE
|
|
|
+ return s;
|
|
|
+#else
|
|
|
+ snprintf(ret, RS232_STRLEN_DEVICE, "\\\\.\\%s", s);
|
|
|
+ return ret;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_open(struct rs232_port_t *p)
|
|
|
+{
|
|
|
+ char tmp[RS232_STRLEN_DEVICE+1] = {0};
|
|
|
+ wchar_t *wname = a2w(fix_device_name(p->dev, tmp));
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p name='%s' fix='%s'\n",
|
|
|
+ (void *)p, p->pt, p->dev, fix_device_name(p->dev, tmp));
|
|
|
+
|
|
|
+ if (wname == NULL)
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+
|
|
|
+ wx->fd = CreateFileW(wname, GENERIC_READ | GENERIC_WRITE,
|
|
|
+ 0, NULL, OPEN_EXISTING,
|
|
|
+#ifdef USE_OVERLAPPED
|
|
|
+ FILE_FLAG_OVERLAPPED,
|
|
|
+#else
|
|
|
+ 0,
|
|
|
+#endif
|
|
|
+ NULL);
|
|
|
+
|
|
|
+ if (wname)
|
|
|
+ free(wname);
|
|
|
+
|
|
|
+ if (wx->fd == INVALID_HANDLE_VALUE) {
|
|
|
+ DBG("CreateFile() %s\n", last_error());
|
|
|
+ return RS232_ERR_OPEN;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef USE_OVERLAPPED
|
|
|
+ memset(&wx->oWait, 0, sizeof(wx->oWait));
|
|
|
+ wx->oWait.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
+ if(wx->oWait.hEvent == NULL){
|
|
|
+ CloseHandle(wx->fd);
|
|
|
+ wx->fd = INVALID_HANDLE_VALUE;
|
|
|
+ return RS232_ERR_OPEN;
|
|
|
+ }
|
|
|
+ wx->wait_progress = 0;
|
|
|
+#endif
|
|
|
+
|
|
|
+ p->status = RS232_PORT_OPEN;
|
|
|
+ rs232_flush(p);
|
|
|
+
|
|
|
+ GET_PORT_STATE(wx->fd, &wx->old_dcb);
|
|
|
+ GET_PORT_TIMEOUTS(wx->fd, &wx->old_tm);
|
|
|
+
|
|
|
+ port_timeout(p, wx->r_timeout, wx->w_timeout);
|
|
|
+ port_buffers(p, wx->r_buffer, wx->w_buffer);
|
|
|
+
|
|
|
+ rs232_set_baud(p, p->baud);
|
|
|
+ rs232_set_data(p, p->data);
|
|
|
+ rs232_set_parity(p, p->parity);
|
|
|
+ rs232_set_stop(p, p->stop);
|
|
|
+ rs232_set_flow(p, p->flow);
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB void
|
|
|
+rs232_set_device(struct rs232_port_t *p, const char *device)
|
|
|
+{
|
|
|
+ DBG("p=%p old=%s new=%s\n", (void *)p, p->dev, device);
|
|
|
+ strncpyz(p->dev, device, RS232_STRLEN_DEVICE);
|
|
|
+
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_set_baud(struct rs232_port_t *p, enum rs232_baud_e baud)
|
|
|
+{
|
|
|
+ DCB pdcb;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p baud=%d (%s bauds)\n",
|
|
|
+ (void *)p, p->pt, baud, rs232_strbaud(baud));
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ GET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+
|
|
|
+ switch (baud) {
|
|
|
+ case RS232_BAUD_300:
|
|
|
+ pdcb.BaudRate = CBR_300;
|
|
|
+ break;
|
|
|
+ case RS232_BAUD_2400:
|
|
|
+ pdcb.BaudRate = CBR_2400;
|
|
|
+ break;
|
|
|
+ case RS232_BAUD_4800:
|
|
|
+ pdcb.BaudRate = CBR_4800;
|
|
|
+ break;
|
|
|
+ case RS232_BAUD_9600:
|
|
|
+ pdcb.BaudRate = CBR_9600;
|
|
|
+ break;
|
|
|
+ case RS232_BAUD_19200:
|
|
|
+ pdcb.BaudRate = CBR_19200;
|
|
|
+ break;
|
|
|
+ case RS232_BAUD_38400:
|
|
|
+ pdcb.BaudRate = CBR_38400;
|
|
|
+ break;
|
|
|
+ case RS232_BAUD_57600:
|
|
|
+ pdcb.BaudRate = CBR_57600;
|
|
|
+ break;
|
|
|
+ case RS232_BAUD_115200:
|
|
|
+ pdcb.BaudRate = CBR_115200;
|
|
|
+ break;
|
|
|
+ case RS232_BAUD_460800:
|
|
|
+ pdcb.BaudRate = CBR_460800;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ SET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+ p->baud = baud;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_set_dtr(struct rs232_port_t *p, enum rs232_dtr_e state)
|
|
|
+{
|
|
|
+ DCB pdcb;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p dtr=%d (dtr control %s)\n",
|
|
|
+ (void *)p, p->pt, state, rs232_strdtr(state));
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ GET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+
|
|
|
+ switch (state) {
|
|
|
+ case RS232_DTR_OFF:
|
|
|
+ pdcb.fDtrControl = DTR_CONTROL_DISABLE;
|
|
|
+ break;
|
|
|
+ case RS232_DTR_ON:
|
|
|
+ pdcb.fDtrControl = DTR_CONTROL_ENABLE;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ SET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+ p->dtr = state;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_set_rts(struct rs232_port_t *p, enum rs232_rts_e state)
|
|
|
+{
|
|
|
+ DCB pdcb;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p rts=%d (rts control %s)\n",
|
|
|
+ (void *)p, p->pt, state, rs232_strrts(state));
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ GET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+
|
|
|
+ switch (state) {
|
|
|
+ case RS232_RTS_OFF:
|
|
|
+ pdcb.fRtsControl = RTS_CONTROL_DISABLE;
|
|
|
+ break;
|
|
|
+ case RS232_RTS_ON:
|
|
|
+ pdcb.fRtsControl = RTS_CONTROL_ENABLE;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ SET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+ p->rts = state;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_set_parity(struct rs232_port_t *p, enum rs232_parity_e parity)
|
|
|
+{
|
|
|
+ DCB pdcb;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p parity=%d (parity %s)\n",
|
|
|
+ (void *)p, p->pt, parity, rs232_strparity(parity));
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ GET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+
|
|
|
+ switch (parity) {
|
|
|
+ case RS232_PARITY_NONE:
|
|
|
+ pdcb.Parity = NOPARITY;
|
|
|
+ break;
|
|
|
+ case RS232_PARITY_ODD:
|
|
|
+ pdcb.Parity = ODDPARITY;
|
|
|
+ break;
|
|
|
+ case RS232_PARITY_EVEN:
|
|
|
+ pdcb.Parity = EVENPARITY;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ SET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+ p->parity = parity;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_set_stop(struct rs232_port_t *p, enum rs232_stop_e stop)
|
|
|
+{
|
|
|
+ DCB pdcb;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p stop=%d (%s stop bits)\n",
|
|
|
+ (void *)p, p->pt, stop, rs232_strstop(stop));
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ GET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+
|
|
|
+ switch (stop) {
|
|
|
+ case RS232_STOP_1:
|
|
|
+ pdcb.StopBits = ONESTOPBIT;
|
|
|
+ break;
|
|
|
+ case RS232_STOP_2:
|
|
|
+ pdcb.StopBits = TWOSTOPBITS;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ SET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+ p->stop = stop;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_set_data(struct rs232_port_t *p, enum rs232_data_e data)
|
|
|
+{
|
|
|
+ DCB pdcb;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p data=%d (%s data bits)\n",
|
|
|
+ (void *)p, p->pt, data, rs232_strdata(data));
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ GET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+
|
|
|
+ switch (data) {
|
|
|
+ case RS232_DATA_5:
|
|
|
+ pdcb.ByteSize = 5;
|
|
|
+ break;
|
|
|
+ case RS232_DATA_6:
|
|
|
+ pdcb.ByteSize = 6;
|
|
|
+ break;
|
|
|
+ case RS232_DATA_7:
|
|
|
+ pdcb.ByteSize = 7;
|
|
|
+ break;
|
|
|
+ case RS232_DATA_8:
|
|
|
+ pdcb.ByteSize = 8;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ SET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+ p->data = data;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_set_flow(struct rs232_port_t *p, enum rs232_flow_e flow)
|
|
|
+{
|
|
|
+ DCB pdcb;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p flow=%d (flow control %s)\n",
|
|
|
+ (void *)p, p->pt, flow, rs232_strflow(flow));
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ GET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+
|
|
|
+ switch (flow) {
|
|
|
+ case RS232_FLOW_OFF:
|
|
|
+ pdcb.fOutxCtsFlow = FALSE;
|
|
|
+ pdcb.fRtsControl = RTS_CONTROL_DISABLE;
|
|
|
+ pdcb.fInX = FALSE;
|
|
|
+ pdcb.fOutX = FALSE;
|
|
|
+ break;
|
|
|
+ case RS232_FLOW_HW:
|
|
|
+ pdcb.fOutxCtsFlow = TRUE;
|
|
|
+ pdcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
|
|
|
+ pdcb.fInX = FALSE;
|
|
|
+ pdcb.fOutX = FALSE;
|
|
|
+ break;
|
|
|
+ case RS232_FLOW_XON_XOFF:
|
|
|
+ pdcb.fOutxCtsFlow = FALSE;
|
|
|
+ pdcb.fRtsControl = RTS_CONTROL_DISABLE;
|
|
|
+ pdcb.fInX = TRUE;
|
|
|
+ pdcb.fOutX = TRUE;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return RS232_ERR_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ SET_PORT_STATE(wx->fd, &pdcb);
|
|
|
+
|
|
|
+ p->flow = flow;
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_flush(struct rs232_port_t *p)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p\n", (void *)p, p->pt);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ if (!FlushFileBuffers(wx->fd)) {
|
|
|
+ DBG("FlushFileBuffers() %s\n", last_error());
|
|
|
+ return RS232_ERR_FLUSH;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!PurgeComm(wx->fd, PURGE_TXABORT | PURGE_RXABORT |
|
|
|
+ PURGE_TXCLEAR | PURGE_RXCLEAR)) {
|
|
|
+ DBG("PurgeComm() %s\n", last_error());
|
|
|
+ return RS232_ERR_FLUSH;
|
|
|
+ }
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_close(struct rs232_port_t *p)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p\n", (void *)p, p->pt);
|
|
|
+
|
|
|
+ if (!rs232_port_open(p))
|
|
|
+ return RS232_ERR_PORT_CLOSED;
|
|
|
+
|
|
|
+ ret = CloseHandle(wx->fd);
|
|
|
+ if (ret == 0) {
|
|
|
+ DBG("CloseHandle() %s\n", last_error());
|
|
|
+ return RS232_ERR_CLOSE;
|
|
|
+ }
|
|
|
+
|
|
|
+#ifdef USE_OVERLAPPED
|
|
|
+ ret = CloseHandle(wx->oWait.hEvent);
|
|
|
+ if (ret == 0) {
|
|
|
+ DBG("CloseHandle() %s\n", last_error());
|
|
|
+ return RS232_ERR_CLOSE;
|
|
|
+ }
|
|
|
+
|
|
|
+ wx->wait_progress = 0;
|
|
|
+#endif
|
|
|
+
|
|
|
+ return RS232_ERR_NOERROR;
|
|
|
+}
|
|
|
+
|
|
|
+RS232_LIB unsigned int
|
|
|
+rs232_fd(struct rs232_port_t *p)
|
|
|
+{
|
|
|
+ struct rs232_windows_t *wx = p->pt;
|
|
|
+
|
|
|
+ DBG("p=%p p->pt=%p wx->fd=%d\n", (void *)p, p->pt, wx->fd);
|
|
|
+
|
|
|
+ return (unsigned int) wx->fd;
|
|
|
+}
|