| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190 |
- /*
- * Copyright (c) 2011 Petr Stetiar <[email protected]>, 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;
- }
|