ARDUINO as Master
[owTools.git] / src / owARDUINOInterface.cpp
1 // Copyright (c) 2017, Tobias Mueller tm(at)tm3d.de
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //  * Redistributions of source code must retain the above copyright
9 //    notice, this list of conditions and the following disclaimer.
10 //  * Redistributions in binary form must reproduce the above copyright
11 //    notice, this list of conditions and the following disclaimer in the
12 //    documentation and/or other materials provided with the
13 //    distribution.
14 //  * All advertising materials mentioning features or use of this
15 //    software must display the following acknowledgement: This product
16 //    includes software developed by tm3d.de and its contributors.
17 //  * Neither the name of tm3d.de nor the names of its contributors may
18 //    be used to endorse or promote products derived from this software
19 //    without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/select.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <sys/ioctl.h>
40 #include <time.h>
41 #include <termios.h>
42 #include <errno.h>
43 #include <sys/time.h>
44 #include "owARDUINOInterface.h"
45
46 #define MODE_DATA                      0xE1
47 #define MODE_COMMAND                   0xE3
48
49 // Baud rate bits
50 #define PARMSET_9600                   0x00
51 #define PARMSET_19200                  0x02
52 #define PARMSET_57600                  0x04
53 #define PARMSET_115200                 0x06
54
55
56
57 #define COM_IDENTIFER 1
58 #define COM_RESET 2
59 #define COM_SEARCH_INIT 3
60 #define COM_SEARCH_NEXT 4
61 #define COM_BLOCK 5
62 #define COM_SBYTE 6
63 #define COM_RBYTE 7
64 #define COM_SBIT 8
65 #define COM_RBIT 9
66
67 //---------------------------------------------------------------------------
68 //  Description:
69 //     flush the rx and tx buffers
70 //
71 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
72 //              OpenCOM to indicate the port number.
73 //
74 void owARDUINOInterface::FlushCOM() {
75    tcflush(fd, TCIOFLUSH);
76 }
77
78
79 int owARDUINOInterface::OpenCOM(uint8_t comnr) {
80         struct termios t;               // see man termios - declared as above
81         int rc;
82         //int fd;
83         char port_zstr[100];
84         if (com_init) return fd;
85
86         sprintf(port_zstr,"/dev/ttyUSB%i",comnr);
87
88    fd = open(port_zstr, O_RDWR|O_NONBLOCK| O_NOCTTY );
89    if (fd<0)
90    {
91            log->set(OWLOG_ERROR,"ERROR open Com %s return %i",port_zstr,fd);
92       return fd;
93    }
94    rc = tcgetattr (fd, &t);
95    if (rc < 0)
96    {
97       int tmp;
98       tmp = errno;
99       close(fd);
100       errno = tmp;
101       log->set(OWLOG_ERROR,"OWERROR_SYSTEM_RESOURCE_INIT_FAILED %s",port_zstr);
102       return rc; // changed (2.00), used to return rc;
103    }
104
105    cfsetospeed(&t, B9600);
106    cfsetispeed (&t, B9600);
107
108    // Get terminal parameters. (2.00) removed raw
109    tcgetattr(fd,&t);
110    // Save original settings.
111    origterm = t;
112
113         t.c_cflag     &=  ~PARENB;            // Make 8n1
114         t.c_cflag     &=  ~CSTOPB;
115         t.c_cflag     &=  ~CSIZE;
116         t.c_cflag     |=  CS8;
117
118         t.c_cflag     &=  ~CRTSCTS;           // no flow control
119         t.c_cc[VMIN]   =  1;                  // read doesn't block
120         t.c_cc[VTIME]  =  5;                  // 0.5 seconds read timeout
121         t.c_cflag     |=  CREAD | CLOCAL;     // turn on READ & ignore ctrl lines
122         t.c_cflag     &=  ~CRTSCTS;       // no flow control
123         t.c_iflag     &=  ~(IXON | IXOFF | IXANY);// turn off s/w flow ctrl
124 /* Make raw */
125         cfmakeraw(&t);
126          tcflush(fd,TCIOFLUSH);
127
128    rc = tcsetattr(fd, TCSAFLUSH, &t);
129  
130    if (rc < 0)
131    {
132       int tmp;
133       tmp = errno;
134       close(fd);
135       errno = tmp;
136       log->set(OWLOG_ERROR,"OWERROR_SYSTEM_RESOURCE_INIT_FAILED %s",port_zstr);
137       return rc; // changed (2.00), used to return rc;
138    }
139         com_init=1;
140    return fd; // changed (2.00), used to return fd;
141 }
142
143
144 //---------------------------------------------------------------------------
145 // Closes the connection to the port.
146 //
147 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
148 //              OpenCOM to indicate the port number.
149 //
150 void owARDUINOInterface::CloseCOM()
151 {
152    // restore tty settings
153    tcsetattr(fd, TCSAFLUSH, &origterm);
154    FlushCOM();
155    close(fd);
156    com_init=0;
157    
158 }
159
160
161 //--------------------------------------------------------------------------
162 // Write an array of bytes to the COM port, verify that it was
163 // sent out.  Assume that baud rate has been set.
164 //
165 // 'portnum'   - number 0 to MAX_PORTNUM-1.  This number provided will
166 //               be used to indicate the port number desired when calling
167 //               all other functions in this library.
168 // Returns 1 for success and 0 for failure
169 //
170 int owARDUINOInterface::WriteCOM( int outlen, uint8_t *outbuf)
171 {
172    long count = outlen;
173    int i=0;
174    for (int k=0;k<outlen;k++) {
175                  i+= write(fd, outbuf+k, 1);
176 //               sleep(1);
177         }
178
179    tcdrain(fd);
180    return (i == count);
181 }
182
183
184 //--------------------------------------------------------------------------
185 // Read an array of bytes to the COM port, verify that it was
186 // sent out.  Assume that baud rate has been set.
187 //
188 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
189 //              OpenCOM to indicate the port number.
190 // 'outlen'   - number of bytes to write to COM port
191 // 'outbuf'   - pointer ot an array of bytes to write
192 //
193 // Returns:  TRUE(1)  - success
194 //           FALSE(0) - failure
195 //
196 int owARDUINOInterface::ReadCOM( int inlen, uint8_t *inbuf)
197 {
198    fd_set         filedescr;
199    struct timeval tval;
200    int            cnt;
201
202    // loop to wait until each byte is available and read it
203    for (cnt = 0; cnt < inlen; cnt++)
204    {
205       // set a descriptor to wait for a character available
206       FD_ZERO(&filedescr);
207       FD_SET(fd,&filedescr);
208       // set timeout to 10ms
209       tval.tv_sec = 10;
210       tval.tv_usec = 10000;
211
212       // if byte available read or return bytes read
213       if (select(fd+1,&filedescr,NULL,NULL,&tval) != 0)
214       {
215          if (read(fd,&inbuf[cnt],1) != 1) {
216                         log->set(OWLOG_ERROR,"Read Error on Serial");
217
218             return cnt;
219          }
220       }
221       else {
222                 log->set(OWLOG_ERROR,"Read Error on Serial (select)");
223         return cnt;
224         }
225    }
226
227    
228    // success, so return desired length
229    return inlen;
230 }
231
232
233
234
235 //--------------------------------------------------------------------------
236 //  Description:
237 //     Send a break on the com port for at least 2 ms
238 //
239 // 'portnum'  - number 0 to MAX_PORTNUM-1.  This number was provided to
240 //              OpenCOM to indicate the port number.
241 //
242 void owARDUINOInterface::BreakCOM()
243 {
244    int duration = 0;              // see man termios break may be
245    tcsendbreak(fd, duration);     // too long
246 }
247
248
249 //--------------------------------------------------------------------------
250 // Set the baud rate on the com port.
251 //
252 // 'portnum'   - number 0 to MAX_PORTNUM-1.  This number was provided to
253 //               OpenCOM to indicate the port number.
254 // 'new_baud'  - new baud rate defined as
255 // PARMSET_9600     0x00
256 // PARMSET_19200    0x02
257 // PARMSET_57600    0x04
258 // PARMSET_115200   0x06
259 //
260 void owARDUINOInterface::SetBaudCOM( uint8_t new_baud)
261 {
262    struct termios t;
263    int rc;
264    speed_t baud;
265
266    // read the attribute structure
267    rc = tcgetattr(fd, &t);
268    if (rc < 0)
269    {
270       close(fd); 
271       log->set(OWLOG_ERROR,"Error on Serial (set Boudrate)");
272
273       return;
274    }
275
276    // convert parameter to linux baud rate
277    switch(new_baud)
278    {
279       case PARMSET_9600:
280          baud = B9600;
281          break;
282       case PARMSET_19200:
283          baud = B19200;
284          break;
285       case PARMSET_57600:
286          baud = B57600;
287          break;
288       case PARMSET_115200:
289          baud = B115200;
290          break;
291       default:
292          baud = B9600;
293          break;
294    }
295
296    // set baud in structure
297    cfsetospeed(&t, baud);
298    cfsetispeed(&t, baud);
299
300    // change baud on port
301    rc = tcsetattr(fd, TCSAFLUSH, &t);
302    if (rc < 0) {
303           log->set(OWLOG_ERROR,"Error on Serial (set Boudrate)");
304
305       close(fd);
306   }
307 }
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325 int owARDUINOInterface::InitAdapter(uint8_t nr) {
326         // attempt to open the communications port
327         if ((fd = OpenCOM(nr)) < 0)
328         {
329                 log->set(OWLOG_ERROR,"OWERROR_OPENCOM_FAILED");
330                 return -1;
331         }       
332         sleep(2);
333         uint8_t readbuffer[20],sendpacket[20];
334         uint8_t sendlen=0;
335         sendpacket[sendlen++]=0x01;
336         sendpacket[sendlen++]=0x00;
337         sendpacket[sendlen++]=0x03;
338         if (WriteCOM(sendlen,sendpacket)) {
339       if ((sendlen=ReadCOM(3,readbuffer)) == 3) {
340       
341         //      printf("%02X %02X %02X\n",readbuffer[0],readbuffer[1],readbuffer[2] );
342         
343                 
344                 
345       }  else {
346         //printf("%i\n",sendlen);
347         log->set(OWLOG_ERROR,"OWERROR_READCOM_FAILED");
348       }
349    }   else  log->set(OWLOG_ERROR,"OWERROR_WRITECOM_FAILED");            
350          
351         com_init=1;
352         
353         
354         return 1;       
355 }
356
357
358 int owARDUINOInterface::owFirst() {
359         uint8_t readbuffer[20],sendpacket[20];
360         uint8_t sendlen=0;
361         sendpacket[sendlen++]=0x03;
362         sendpacket[sendlen++]=0x00;     
363         sendpacket[sendlen++]=0x08;
364         if (WriteCOM(sendlen,sendpacket)) {
365                 if ((sendlen=ReadCOM(8,readbuffer)) == 8) {
366                         if (readbuffer[0]!=0) {
367                                 for (int i=0;i<8;i++) ROM_NO[i]=readbuffer[i];
368                                 return 1;
369                         }
370                 }
371         }
372         return 0;
373
374 }
375 int owARDUINOInterface::owNext() {
376         uint8_t readbuffer[20],sendpacket[20];
377         uint8_t sendlen=0;
378         sendpacket[sendlen++]=0x04;
379         sendpacket[sendlen++]=0x00;     
380         sendpacket[sendlen++]=0x08;
381         if (WriteCOM(sendlen,sendpacket)) {
382                 if ((sendlen=ReadCOM(8,readbuffer)) == 8) {
383                         if (readbuffer[0]!=0) {
384                                 for (int i=0;i<8;i++) ROM_NO[i]=readbuffer[i];
385                                 return 1;
386                         }
387                 }
388         }
389         return 0;
390
391 }
392
393
394 void owARDUINOInterface::ReleaseAdapter() {
395         CloseCOM();
396 }
397
398
399 int owARDUINOInterface::Reset() {
400         uint8_t readbuffer[5],sendpacket[5];
401         uint8_t sendlen=0;
402  /*     size_t l;
403
404         if ((l=read(fd,readbuffer,5))>0) {
405                 printf("in buf %i bytes %02X %02X %02X %02X %02X\n",l,readbuffer[0],readbuffer[1],readbuffer[2],readbuffer[3],readbuffer[4]);
406          }*/
407         sendlen=0;
408         sendpacket[sendlen++]=0x02;
409         sendpacket[sendlen++]=0x00;
410         sendpacket[sendlen++]=0x01;
411         if (WriteCOM(sendlen,sendpacket)) {
412                 if ((sendlen=ReadCOM(1,readbuffer)) == 1) {
413                 //      printf("Reset %i\n",readbuffer[0]);
414                         if (readbuffer[0]) return 1;
415                         
416                 }
417         }
418
419         return 0;
420 }
421
422
423 uint8_t owARDUINOInterface::sendrecivByte(uint8_t byte) {
424         
425         uint8_t readbuffer[5],sendpacket[5];
426         uint8_t sendlen=0;
427 /*      size_t l;
428         if ((l=read(fd,readbuffer,5))>0) {
429                 printf("in buf %i bytes %02X %02X %02X %02X %02X\n",l,readbuffer[0],readbuffer[1],readbuffer[2],readbuffer[3],readbuffer[4]);
430          }*/
431         if (byte!=0xFF) {
432                 sendlen=0;
433                 sendpacket[sendlen++]=COM_SBYTE;
434                 sendpacket[sendlen++]=0x01;
435                 sendpacket[sendlen++]=0x01;
436                 sendpacket[sendlen++]=byte;
437                 if (WriteCOM(sendlen,sendpacket)) {
438                         if ((sendlen=ReadCOM(1,readbuffer)) == 1) {
439                 //              printf("Send %02X %02X \n",byte,readbuffer[0]);
440
441                                 return byte;
442                         }
443                 }
444         } else {
445                 sendlen=0;
446                 sendpacket[sendlen++]=COM_RBYTE;
447                 sendpacket[sendlen++]=0x00;
448                 sendpacket[sendlen++]=0x01;
449                 if (WriteCOM(sendlen,sendpacket)) {
450                         if ((sendlen=ReadCOM(1,readbuffer)) == 1) {
451                         //      printf("Recive %02X\n",readbuffer[0]);
452                                 return readbuffer[0];
453                         }
454                 }
455                 
456         }
457
458    return 0;                            
459 }
460 uint8_t owARDUINOInterface::sendrecivBit(uint8_t bit) {
461         return 0;
462 }
463
464 int owARDUINOInterface::Communicate(std::vector<uint8_t> *data, int scount, int rcount) {
465         int i=0;
466         data->resize(scount);
467         uint8_t readbuffer[128],sendpacket[128+3];
468         uint8_t sendlen=0;
469         sendpacket[sendlen++]=COM_BLOCK;
470         sendpacket[sendlen++]=scount;
471         sendpacket[sendlen++]=rcount;
472         for(uint8_t v:*data) {
473                 sendpacket[sendlen++]=v;
474                 (*data)[i]=v;i++;
475         }
476         if (WriteCOM(sendlen,sendpacket)) {
477                         if ((sendlen=ReadCOM(rcount,readbuffer)) == rcount) {
478                                 for(i=0;i<rcount;i++) {
479                                         //printf("%02X ",readbuffer[i]);
480                                         data->push_back(readbuffer[i]);
481                                 }
482                                 //printf("\n");
483                         }
484                 }
485                 
486         
487         return 0;
488 }
489