Skip to content
This repository has been archived by the owner on Dec 18, 2018. It is now read-only.
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
/*
* 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>
#ifndef UNDER_CE
#include <errno.h>
#endif
#include "librs232/rs232.h"
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;
}
static char * last_error(void)
{
unsigned long err = 0;
unsigned long ret = 0;
static 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 (%d)", errbuf, ret);
}
else
snprintf(retbuf, MAX_PATH, "LastError: %d (FormatMessageA failed)", ret);
return retbuf;
}
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)
return NULL;
DBG("p=%p p->pt=%p\n", (void *)p, p->pt);
memset(p->dev, 0, RS232_STRLEN_DEVICE+1);
strncpy(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 = 500;
wx->w_timeout = 500;
wx->r_buffer = 1024;
wx->w_buffer = 1024;
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 (!rs232_port_open(p))
return RS232_ERR_PORT_CLOSED;
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;
if (!rs232_port_open(p))
return RS232_ERR_PORT_CLOSED;
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_qeue(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_qeue_clear(struct rs232_port_t *p)
{
/* TODO */
UNREFERENCED_PARAMETER(p);
DBG("%s\n", "sorry, not implemented yet");
}
RS232_LIB unsigned int
rs232_read(struct rs232_port_t *p, unsigned char *buf, unsigned int buf_len,
unsigned int *read_len)
{
unsigned int r = 0;
struct rs232_windows_t *wx = p->pt;
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;
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;
DBG("read_len=%d hex='%s' ascii='%s'\n", r, rs232_hex_dump(buf, r),
rs232_ascii_dump(buf, r));
return RS232_ERR_NOERROR;
}
/* 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)
{
UNREFERENCED_PARAMETER(p);
UNREFERENCED_PARAMETER(buf);
UNREFERENCED_PARAMETER(timeout);
UNREFERENCED_PARAMETER(read_len);
UNREFERENCED_PARAMETER(buf_len);
/* TODO */
DBG("%s\n", "sorry, not implemented yet");
return RS232_ERR_UNKNOWN;
}
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 r = 0;
struct rs232_windows_t *wx = p->pt;
unsigned int rt = wx->r_timeout;
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;
*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;
DBG("read_len=%d hex='%s' ascii='%s'\n", r, rs232_hex_dump(buf, r),
rs232_ascii_dump(buf, 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;
}
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 w = 0;
struct rs232_windows_t *wx = p->pt;
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;
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;
DBG("write_len=%d hex='%s' ascii='%s'\n", w, rs232_hex_dump(buf, w),
rs232_ascii_dump(buf, w));
return RS232_ERR_NOERROR;
}
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 w = 0;
struct rs232_windows_t *wx = p->pt;
unsigned int wt = wx->w_timeout;
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;
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;
DBG("write_len=%d hex='%s' ascii='%s'\n", w, rs232_hex_dump(buf, w),
rs232_ascii_dump(buf, w));
return RS232_ERR_NOERROR;
}
static char *
fix_device_name(char *device)
{
char *s = device;
static char ret[RS232_STRLEN_DEVICE+1] = {0};
while (*s && !isdigit(*s))
s++;
if (s && (atoi(s) > 0)) {
/* meh, Windows CE is special and can't handle URN path, just COM1: format */
#ifndef UNDER_CE
snprintf(ret, RS232_STRLEN_DEVICE, "\\\\.\\COM%s", s);
#else
snprintf(ret, RS232_STRLEN_DEVICE, "COM%s:", s);
#endif
return ret;
}
return device;
}
RS232_LIB unsigned int
rs232_open(struct rs232_port_t *p)
{
wchar_t *wname = a2w(fix_device_name(p->dev));
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));
if (wname == NULL)
return RS232_ERR_UNKNOWN;
wx->fd = CreateFile(wname, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (wname)
free(wname);
if (wx->fd == INVALID_HANDLE_VALUE) {
DBG("CreateFile() %s\n", last_error());
return RS232_ERR_OPEN;
}
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);
strncpy(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_DTR_OFF:
pdcb.fRtsControl = RTS_CONTROL_DISABLE;
break;
case RS232_DTR_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("PurgeComm() %s\n", last_error());
return RS232_ERR_CLOSE;
}
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;
}