1 // Copyright (c) 2017, Tobias Mueller tm(at)tm3d.de
\r
2 // All rights reserved.
\r
4 // Redistribution and use in source and binary forms, with or without
\r
5 // modification, are permitted provided that the following conditions are
\r
8 // * Redistributions of source code must retain the above copyright
\r
9 // notice, this list of conditions and the following disclaimer.
\r
10 // * Redistributions in binary form must reproduce the above copyright
\r
11 // notice, this list of conditions and the following disclaimer in the
\r
12 // documentation and/or other materials provided with the
\r
14 // * All advertising materials mentioning features or use of this
\r
15 // software must display the following acknowledgement: This product
\r
16 // includes software developed by tm3d.de and its contributors.
\r
17 // * Neither the name of tm3d.de nor the names of its contributors may
\r
18 // be used to endorse or promote products derived from this software
\r
19 // without specific prior written permission.
\r
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\r
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
\r
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
\r
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
\r
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
\r
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
\r
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
\r
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
\r
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
\r
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
35 #include <sys/select.h>
\r
36 #include <sys/ioctl.h>
\r
37 #include <termios.h>
\r
38 #include <sys/time.h>
\r
40 #include <sys/types.h>
\r
41 #include <sys/stat.h>
\r
45 #include "owARDUINOInterface.h"
\r
48 #define COM_IDENTIFER 1
\r
50 #define COM_SEARCH_INIT 3
\r
51 #define COM_SEARCH_NEXT 4
\r
58 //---------------------------------------------------------------------------
\r
60 // flush the rx and tx buffers
\r
62 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
\r
63 // OpenCOM to indicate the port number.
\r
65 void owARDUINOInterface::FlushCOM() {
\r
67 tcflush(fd, TCIOFLUSH);
\r
70 PurgeComm(fd, PURGE_TXABORT | PURGE_RXABORT |
\r
71 PURGE_TXCLEAR | PURGE_RXCLEAR);
\r
81 owARDUINOInterface::OpenCOM(uint8_t comnr)
\r
83 char port_zstr[100];
\r
85 struct termios t; // see man termios - declared as above
\r
89 if (com_init) return fd;
\r
91 sprintf(port_zstr,"/dev/ttyUSB%i",comnr);
\r
93 fd = open(port_zstr, O_RDWR|O_NONBLOCK| O_NOCTTY );
\r
96 log->set(OWLOG_ERROR,"ERROR open Com %s return %i",port_zstr,fd);
\r
99 rc = tcgetattr (fd, &t);
\r
106 log->set(OWLOG_ERROR,"OWERROR_SYSTEM_RESOURCE_INIT_FAILED %s",port_zstr);
\r
107 return rc; // changed (2.00), used to return rc;
\r
110 cfsetospeed(&t, B9600);
\r
111 cfsetispeed (&t, B9600);
\r
113 // Get terminal parameters. (2.00) removed raw
\r
115 // Save original settings.
\r
118 t.c_cflag &= ~PARENB; // Make 8n1
\r
119 t.c_cflag &= ~CSTOPB;
\r
120 t.c_cflag &= ~CSIZE;
\r
123 t.c_cflag &= ~CRTSCTS; // no flow control
\r
124 t.c_cc[VMIN] = 1; // read doesn't block
\r
125 t.c_cc[VTIME] = 5; // 0.5 seconds read timeout
\r
126 t.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
\r
127 t.c_cflag &= ~CRTSCTS; // no flow control
\r
128 t.c_iflag &= ~(IXON | IXOFF | IXANY);// turn off s/w flow ctrl
\r
131 tcflush(fd,TCIOFLUSH);
\r
133 rc = tcsetattr(fd, TCSAFLUSH, &t);
\r
141 log->set(OWLOG_ERROR,"OWERROR_SYSTEM_RESOURCE_INIT_FAILED %s",port_zstr);
\r
142 return rc; // changed (2.00), used to return rc;
\r
145 return fd; // changed (2.00), used to return fd;
\r
149 COMMTIMEOUTS CommTimeOuts;
\r
151 int comnr1 = comnr;
\r
152 sprintf_s(port_zstr,100, "COM%d", comnr1);
\r
154 if ((fd = CreateFileA(port_zstr, GENERIC_READ | GENERIC_WRITE,
\r
156 NULL, // no security attrs
\r
158 FILE_FLAG_OVERLAPPED, // overlapped I/O
\r
159 NULL)) == (HANDLE)-1) {
\r
161 log->set(OWLOG_ERROR, "ERROR open Com %s return %i", port_zstr, fd);
\r
164 // get any early notifications
\r
165 SetCommMask(fd, EV_RXCHAR | EV_TXEMPTY | EV_ERR | EV_BREAK);
\r
166 SetupComm(fd, 2048, 2048);
\r
167 // purge any information in the buffer
\r
168 PurgeComm(fd, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
\r
169 // set up for overlapped non-blocking I/O
\r
170 CommTimeOuts.ReadIntervalTimeout = 0;
\r
171 CommTimeOuts.ReadTotalTimeoutMultiplier = 20;
\r
172 CommTimeOuts.ReadTotalTimeoutConstant = 40;
\r
173 CommTimeOuts.WriteTotalTimeoutMultiplier = 20;
\r
174 CommTimeOuts.WriteTotalTimeoutConstant = 40;
\r
175 SetCommTimeouts(fd, &CommTimeOuts);
\r
176 // setup the com port
\r
177 GetCommState(fd, &dcb);
\r
178 dcb.BaudRate = CBR_9600; // current baud rate
\r
179 dcb.fBinary = TRUE; // binary mode, no EOF check
\r
180 dcb.fParity = FALSE; // enable parity checking
\r
181 dcb.fOutxCtsFlow = FALSE; // CTS output flow control
\r
182 dcb.fOutxDsrFlow = FALSE; // DSR output flow control
\r
183 dcb.fDtrControl = FALSE; // DTR flow control type
\r
184 dcb.fDsrSensitivity = FALSE; // DSR sensitivity
\r
185 dcb.fTXContinueOnXoff = FALSE; // XOFF continues Tx
\r
186 dcb.fOutX = FALSE; // XON/XOFF out flow control
\r
187 dcb.fInX = FALSE; // XON/XOFF in flow control
\r
188 dcb.fErrorChar = FALSE; // enable error replacement
\r
189 dcb.fNull = FALSE; // enable null stripping
\r
190 dcb.fRtsControl = FALSE; // RTS flow control
\r
191 dcb.fAbortOnError = FALSE; // abort reads/writes on error
\r
192 dcb.XonLim = 0; // transmit XON threshold
\r
193 dcb.XoffLim = 0; // transmit XOFF threshold
\r
194 dcb.ByteSize = 8; // number of bits/byte, 4-8
\r
195 dcb.Parity = NOPARITY; // 0-4=no,odd,even,mark,space
\r
196 dcb.StopBits = ONESTOPBIT; // 0,1,2 = 1, 1.5, 2
\r
197 dcb.XonChar = 0; // Tx and Rx XON character
\r
198 dcb.XoffChar = 0; // Tx and Rx XOFF character
\r
199 dcb.ErrorChar = 0; // error replacement character
\r
200 dcb.EofChar = 0; // end of input character
\r
201 dcb.EvtChar = 0; // received event character
\r
202 fRetVal = SetCommState(fd, &dcb);
\r
205 // check if successfull
\r
209 log->set(OWLOG_ERROR, "OWERROR_SYSTEM_RESOURCE_INIT_FAILED %s", port_zstr);
\r
218 //---------------------------------------------------------------------------
\r
219 // Closes the connection to the port.
\r
221 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
\r
222 // OpenCOM to indicate the port number.
\r
224 void owARDUINOInterface::CloseCOM()
\r
227 // restore tty settings
\r
228 tcsetattr(fd, TCSAFLUSH, &origterm);
\r
233 // disable event notification and wait for thread
\r
235 SetCommMask(fd, 0);
\r
237 PurgeComm(fd, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
\r
246 //--------------------------------------------------------------------------
\r
247 // Write an array of bytes to the COM port, verify that it was
\r
248 // sent out. Assume that baud rate has been set.
\r
250 // 'portnum' - number 0 to MAX_PORTNUM-1. This number provided will
\r
251 // be used to indicate the port number desired when calling
\r
252 // all other functions in this library.
\r
253 // Returns 1 for success and 0 for failure
\r
255 int owARDUINOInterface::WriteCOM( int outlen, uint8_t *outbuf) {
\r
257 long count = outlen;
\r
259 for (int k=0;k<outlen;k++) {
\r
260 i+= write(fd, outbuf+k, 1);
\r
265 return (i == count);
\r
269 DWORD dwBytesWritten = 0;
\r
271 OVERLAPPED osWrite = { 0 };
\r
272 // calculate a timeout
\r
273 to = 20 * outlen + 60;
\r
275 osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
276 ResetEvent(osWrite.hEvent);
\r
277 fWriteStat = WriteFile(fd, (LPSTR)&outbuf[0], outlen, &dwBytesWritten, &osWrite);
\r
278 // check for an error
\r
281 ler = GetLastError();
\r
282 // if not done writting then wait
\r
283 if (!fWriteStat && ler == ERROR_IO_PENDING) {
\r
284 // log->set(OWLOG_ERROR, "SERIAL_ERROR_IO_PENDING");
\r
285 WaitForSingleObject(osWrite.hEvent, to);
\r
286 // verify all is written correctly
\r
288 fWriteStat = GetOverlappedResult(fd, &osWrite, &dwBytesWritten, FALSE);
\r
290 // check results of write
\r
291 if (!fWriteStat || (dwBytesWritten != (DWORD)outlen))
\r
299 //--------------------------------------------------------------------------
\r
300 // Read an array of bytes to the COM port, verify that it was
\r
301 // sent out. Assume that baud rate has been set.
\r
303 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
\r
304 // OpenCOM to indicate the port number.
\r
305 // 'outlen' - number of bytes to write to COM port
\r
306 // 'outbuf' - pointer ot an array of bytes to write
\r
308 // Returns: TRUE(1) - success
\r
309 // FALSE(0) - failure
\r
311 int owARDUINOInterface::ReadCOM( int inlen, uint8_t *inbuf)
\r
315 struct timeval tval;
\r
318 // loop to wait until each byte is available and read it
\r
319 for (cnt = 0; cnt < inlen; cnt++)
\r
321 // set a descriptor to wait for a character available
\r
322 FD_ZERO(&filedescr);
\r
323 FD_SET(fd,&filedescr);
\r
324 // set timeout to 10ms
\r
326 tval.tv_usec = 10000;
\r
328 // if byte available read or return bytes read
\r
329 if (select(fd+1,&filedescr,NULL,NULL,&tval) != 0)
\r
331 if (read(fd,&inbuf[cnt],1) != 1) {
\r
332 log->set(OWLOG_ERROR,"Read Error on Serial");
\r
338 log->set(OWLOG_ERROR,"Read Error on Serial (select)");
\r
344 // success, so return desired length
\r
348 DWORD dwLength = 0;
\r
351 OVERLAPPED osReader = { 0 };
\r
352 // calculate a timeout
\r
353 to = 20 * inlen + 60;
\r
355 osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
\r
356 ResetEvent(osReader.hEvent);
\r
357 fReadStat = ReadFile(fd, (LPSTR)&inbuf[0], inlen, &dwLength, &osReader);
\r
359 // check for an error
\r
361 ler = GetLastError();
\r
362 // log->set(OWLOG_ERROR, "Read Error on Serial");
\r
364 // if not done writing then wait
\r
366 while (!fReadStat && ler == ERROR_IO_PENDING) {
\r
367 // wait until everything is read
\r
368 // log->set(OWLOG_ERROR, "Read Error on Serial");
\r
369 // printf("try Read %i\n", e); e++;
\r
370 WaitForSingleObject(osReader.hEvent, to);
\r
371 // verify all is read correctly
\r
372 fReadStat = GetOverlappedResult(fd, &osReader, &dwLength, FALSE);
\r
373 //printf("%i %i\n", dwLength, inlen);
\r
374 if (dwLength == inlen) break;
\r
376 printf("repeat\n");
\r
390 //--------------------------------------------------------------------------
\r
392 // Send a break on the com port for at least 2 ms
\r
394 // 'portnum' - number 0 to MAX_PORTNUM-1. This number was provided to
\r
395 // OpenCOM to indicate the port number.
\r
397 void owARDUINOInterface::BreakCOM()
\r
399 int duration = 0; // see man termios break may be
\r
400 tcsendbreak(fd, duration); // too long
\r
413 int owARDUINOInterface::InitAdapter(uint8_t nr) {
\r
414 // attempt to open the communications port
\r
415 if ((fd = OpenCOM(nr)) < 0)
\r
417 log->set(OWLOG_ERROR,"OWERROR_OPENCOM_FAILED");
\r
426 uint8_t readbuffer[20],sendpacket[20];
\r
428 sendpacket[sendlen++]=0x01;
\r
429 sendpacket[sendlen++]=0x00;
\r
430 sendpacket[sendlen++]=0x03;
\r
431 if (WriteCOM(sendlen,sendpacket)) {
\r
432 if ((sendlen=ReadCOM(3,readbuffer)) == 3) {
\r
433 // printf("%02X %02X %02X\n",readbuffer[0],readbuffer[1],readbuffer[2] );
\r
435 log->set(OWLOG_ERROR,"OWERROR_READCOM_FAILED");
\r
437 } else log->set(OWLOG_ERROR,"OWERROR_WRITECOM_FAILED");
\r
443 int owARDUINOInterface::owFirst() {
\r
444 uint8_t readbuffer[20],sendpacket[20];
\r
446 sendpacket[sendlen++]=0x03;
\r
447 sendpacket[sendlen++]=0x00;
\r
448 sendpacket[sendlen++]=0x08;
\r
449 if (WriteCOM(sendlen,sendpacket)) {
\r
450 if ((sendlen=ReadCOM(8,readbuffer)) == 8) {
\r
451 if (readbuffer[0]!=0) {
\r
452 for (int i=0;i<8;i++) ROM_NO[i]=readbuffer[i];
\r
460 int owARDUINOInterface::owNext() {
\r
461 uint8_t readbuffer[20],sendpacket[20];
\r
463 sendpacket[sendlen++]=0x04;
\r
464 sendpacket[sendlen++]=0x00;
\r
465 sendpacket[sendlen++]=0x08;
\r
466 if (WriteCOM(sendlen,sendpacket)) {
\r
467 if ((sendlen=ReadCOM(8,readbuffer)) == 8) {
\r
468 if (readbuffer[0]!=0) {
\r
469 for (int i=0;i<8;i++) ROM_NO[i]=readbuffer[i];
\r
479 void owARDUINOInterface::ReleaseAdapter() {
\r
484 int owARDUINOInterface::Reset() {
\r
485 uint8_t readbuffer[5],sendpacket[5];
\r
488 sendpacket[sendlen++]=0x02;
\r
489 sendpacket[sendlen++]=0x00;
\r
490 sendpacket[sendlen++]=0x01;
\r
491 if (WriteCOM(sendlen,sendpacket)) {
\r
492 if ((sendlen=ReadCOM(1,readbuffer)) == 1) {
\r
493 if (readbuffer[0]) return 1;
\r
501 uint8_t owARDUINOInterface::sendrecivByte(uint8_t byte) {
\r
503 uint8_t readbuffer[5],sendpacket[5];
\r
507 sendpacket[sendlen++]=COM_SBYTE;
\r
508 sendpacket[sendlen++]=0x01;
\r
509 sendpacket[sendlen++]=0x01;
\r
510 sendpacket[sendlen++]=byte;
\r
511 if (WriteCOM(sendlen,sendpacket)) {
\r
512 if ((sendlen=ReadCOM(1,readbuffer)) == 1) {
\r
518 sendpacket[sendlen++]=COM_RBYTE;
\r
519 sendpacket[sendlen++]=0x00;
\r
520 sendpacket[sendlen++]=0x01;
\r
521 if (WriteCOM(sendlen,sendpacket)) {
\r
522 if ((sendlen=ReadCOM(1,readbuffer)) == 1) {
\r
523 return readbuffer[0];
\r
531 uint8_t owARDUINOInterface::sendrecivBit(uint8_t bit) {
\r
535 int owARDUINOInterface::Communicate(std::vector<uint8_t> *data, int scount, int rcount) {
\r
537 data->resize(scount);
\r
538 uint8_t readbuffer[128],sendpacket[128+3];
\r
540 sendpacket[sendlen++]=COM_BLOCK;
\r
541 sendpacket[sendlen++]=scount;
\r
542 sendpacket[sendlen++]=rcount;
\r
543 for(uint8_t v:*data) {
\r
544 sendpacket[sendlen++]=v;
\r
548 if (WriteCOM(sendlen,sendpacket)) {
\r
549 if ((sendlen=ReadCOM(rcount,readbuffer)) == rcount) {
\r
550 for(i=0;i<rcount;i++) {
\r
551 data->push_back(readbuffer[i]);
\r
554 for (i = 0; i<rcount; i++)
\r
555 data->push_back(0xFF);
\r