TPUART serial: return TPUART ACKs as L2 ACK in vBusmonitor mode
[bcusdk.git] / eibd / backend / tpuartserial.cpp
blob6a92a8d22f42fab435078720528a520531f10603
1 /*
2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2008 Martin Koegler <mkoegler@auto.tuwien.ac.at>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include "tpuartserial.h"
25 /** get serial status lines */
26 static int
27 getstat (int fd)
29 int s;
30 ioctl (fd, TIOCMGET, &s);
31 return s;
34 /** set serial status lines */
35 static void
36 setstat (int fd, int s)
38 ioctl (fd, TIOCMSET, &s);
42 TPUARTSerialLayer2Driver::TPUARTSerialLayer2Driver (const char *dev,
43 eibaddr_t a, Trace * tr)
45 struct termios t1;
46 t = tr;
47 TRACEPRINTF (t, 2, this, "Open");
49 fd = open (dev, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);
50 if (fd == -1)
51 throw Exception (DEV_OPEN_FAIL);
52 set_low_latency (fd, &sold);
54 close (fd);
56 fd = open (dev, O_RDWR | O_NOCTTY | O_SYNC);
57 if (fd == -1)
58 throw Exception (DEV_OPEN_FAIL);
59 tcgetattr (fd, &old);
61 t1.c_cflag = CS8 | CLOCAL | CREAD | PARENB;
62 t1.c_iflag = IGNBRK | INPCK | ISIG;
63 t1.c_oflag = 0;
64 t1.c_lflag = 0;
65 t1.c_cc[VTIME] = 1;
66 t1.c_cc[VMIN] = 0;
67 cfsetospeed (&t1, B19200);
68 cfsetispeed (&t1, 0);
70 tcsetattr (fd, TCSAFLUSH, &t1);
72 setstat (fd, (getstat (fd) & ~TIOCM_RTS) | TIOCM_DTR);
74 mode = 0;
75 vmode = 0;
76 addr = a;
77 indaddr.resize (1);
78 indaddr[0] = a;
80 pth_sem_init (&in_signal);
81 pth_sem_init (&out_signal);
83 getwait = pth_event (PTH_EVENT_SEM, &out_signal);
85 Start ();
86 TRACEPRINTF (t, 2, this, "Openend");
89 TPUARTSerialLayer2Driver::~TPUARTSerialLayer2Driver ()
91 TRACEPRINTF (t, 2, this, "Close");
92 Stop ();
93 pth_event_free (getwait, PTH_FREE_THIS);
95 while (!outqueue.isempty ())
96 delete outqueue.get ();
97 while (!inqueue.isempty ())
98 delete inqueue.get ();
100 if (fd != -1)
102 setstat (fd, (getstat (fd) & ~TIOCM_RTS) & ~TIOCM_DTR);
103 tcsetattr (fd, TCSAFLUSH, &old);
104 restore_low_latency (fd, &sold);
105 close (fd);
110 bool
111 TPUARTSerialLayer2Driver::addAddress (eibaddr_t addr)
113 unsigned i;
114 for (i = 0; i < indaddr (); i++)
115 if (indaddr[i] == addr)
116 return 0;
117 indaddr.resize (indaddr () + 1);
118 indaddr[indaddr () - 1] = addr;
119 return 1;
122 bool
123 TPUARTSerialLayer2Driver::addGroupAddress (eibaddr_t addr)
125 unsigned i;
126 for (i = 0; i < groupaddr (); i++)
127 if (groupaddr[i] == addr)
128 return 0;
129 groupaddr.resize (groupaddr () + 1);
130 groupaddr[groupaddr () - 1] = addr;
131 return 1;
134 bool
135 TPUARTSerialLayer2Driver::removeAddress (eibaddr_t addr)
137 unsigned i;
138 for (i = 0; i < indaddr (); i++)
139 if (indaddr[i] == addr)
141 indaddr.deletepart (i, 1);
142 return 1;
144 return 0;
147 bool
148 TPUARTSerialLayer2Driver::removeGroupAddress (eibaddr_t addr)
150 unsigned i;
151 for (i = 0; i < groupaddr (); i++)
152 if (groupaddr[i] == addr)
154 groupaddr.deletepart (i, 1);
155 return 1;
157 return 0;
160 bool TPUARTSerialLayer2Driver::openVBusmonitor ()
162 vmode = 1;
163 return 1;
166 bool TPUARTSerialLayer2Driver::closeVBusmonitor ()
168 vmode = 0;
169 return 1;
172 eibaddr_t
173 TPUARTSerialLayer2Driver::getDefaultAddr ()
175 return addr;
178 bool
179 TPUARTSerialLayer2Driver::Connection_Lost ()
181 return 0;
184 bool
185 TPUARTSerialLayer2Driver::Send_Queue_Empty ()
187 return inqueue.isempty ();
190 void
191 TPUARTSerialLayer2Driver::Send_L_Data (LPDU * l)
193 TRACEPRINTF (t, 2, this, "Send %s", l->Decode ()());
194 inqueue.put (l);
195 pth_sem_inc (&in_signal, 1);
198 LPDU *
199 TPUARTSerialLayer2Driver::Get_L_Data (pth_event_t stop)
201 if (stop != NULL)
202 pth_event_concat (getwait, stop, NULL);
204 pth_wait (getwait);
206 if (stop)
207 pth_event_isolate (getwait);
209 if (pth_event_status (getwait) == PTH_STATUS_OCCURRED)
211 pth_sem_dec (&out_signal);
212 LPDU *l = outqueue.get ();
213 TRACEPRINTF (t, 2, this, "Recv %s", l->Decode ()());
214 return l;
216 else
217 return 0;
221 //Open
223 bool
224 TPUARTSerialLayer2Driver::enterBusmonitor ()
226 uchar c = 0x05;
227 t->TracePacket (2, this, "openBusmonitor", 1, &c);
228 write (fd, &c, 1);
229 mode = 1;
230 return 1;
233 bool
234 TPUARTSerialLayer2Driver::leaveBusmonitor ()
236 uchar c = 0x01;
237 t->TracePacket (2, this, "leaveBusmonitor", 1, &c);
238 write (fd, &c, 1);
239 mode = 0;
240 return 1;
243 bool
244 TPUARTSerialLayer2Driver::Open ()
246 uchar c = 0x01;
247 t->TracePacket (2, this, "open-reset", 1, &c);
248 write (fd, &c, 1);
249 return 1;
252 bool
253 TPUARTSerialLayer2Driver::Close ()
255 return 1;
258 void
259 TPUARTSerialLayer2Driver::RecvLPDU (const uchar * data, int len)
261 t->TracePacket (1, this, "Recv", len, data);
262 if (mode || vmode)
264 L_Busmonitor_PDU *l = new L_Busmonitor_PDU;
265 l->pdu.set (data, len);
266 outqueue.put (l);
267 pth_sem_inc (&out_signal, 1);
269 if (!mode)
271 LPDU *l = LPDU::fromPacket (CArray (data, len));
272 if (l->getType () == L_Data && ((L_Data_PDU *) l)->valid_checksum)
274 outqueue.put (l);
275 pth_sem_inc (&out_signal, 1);
277 else
278 delete l;
282 void
283 TPUARTSerialLayer2Driver::Run (pth_sem_t * stop1)
285 uchar buf[255];
286 int i;
287 CArray in;
288 int to = 0;
289 int waitconfirm = 0;
290 int acked = 0;
291 int retry = 0;
292 int watch = 0;
293 pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
294 pth_event_t input = pth_event (PTH_EVENT_SEM, &in_signal);
295 pth_event_t timeout = pth_event (PTH_EVENT_TIME, pth_timeout (0, 0));
296 pth_event_t watchdog = pth_event (PTH_EVENT_TIME, pth_timeout (0, 0));
297 pth_event_t sendtimeout = pth_event (PTH_EVENT_TIME, pth_timeout (0, 0));
298 while (pth_event_status (stop) != PTH_STATUS_OCCURRED)
300 if (in () == 0 && !waitconfirm)
301 pth_event_concat (stop, input, NULL);
302 if (to)
303 pth_event_concat (stop, timeout, NULL);
304 if (waitconfirm)
305 pth_event_concat (stop, sendtimeout, NULL);
306 if (watch)
307 pth_event_concat (stop, watchdog, NULL);
308 i = pth_read_ev (fd, buf, sizeof (buf), stop);
309 pth_event_isolate (stop);
310 pth_event_isolate (timeout);
311 pth_event_isolate (sendtimeout);
312 pth_event_isolate (watchdog);
313 if (i > 0)
315 t->TracePacket (0, this, "Recv", i, buf);
316 in.setpart (buf, in (), i);
318 while (in () > 0)
320 if (in[0] == 0x8B)
322 if (!mode && vmode)
324 const uchar pkt[1] = { 0xCC };
325 RecvLPDU (pkt, 1);
327 if (waitconfirm)
329 waitconfirm = 0;
330 delete inqueue.get ();
331 pth_sem_dec (&in_signal);
332 retry = 0;
334 in.deletepart (0, 1);
336 else if (in[0] == 0x0B)
338 if (!mode && vmode)
340 const uchar pkt[1] = { 0x0C };
341 RecvLPDU (pkt, 1);
343 if (waitconfirm)
345 retry++;
346 waitconfirm = 0;
347 TRACEPRINTF (t, 0, this, "NACK");
348 if (retry > 3)
350 TRACEPRINTF (t, 0, this, "Drop NACK");
351 delete inqueue.get ();
352 pth_sem_dec (&in_signal);
353 retry = 0;
356 in.deletepart (0, 1);
358 else if ((in[0] & 0x07) == 0x07)
360 TRACEPRINTF (t, 0, this, "RecvWatchdog: %02X", in[0]);
361 watch = 2;
362 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, watchdog,
363 pth_timeout (10, 0));
364 in.deletepart (0, 1);
366 else if (in[0] == 0xCC || in[0] == 0xC0 || in[0] == 0x0C)
368 RecvLPDU (in.array (), 1);
369 in.deletepart (0, 1);
371 else if ((in[0] & 0xD0) == 0x90)
373 if (in () < 6)
375 if (!to)
377 to = 1;
378 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
379 pth_timeout (0, 300000));
381 if (pth_event_status (timeout) != PTH_STATUS_OCCURRED)
382 break;
383 TRACEPRINTF (t, 0, this, "Remove1 %02X", in[0]);
384 in.deletepart (0, 1);
385 continue;
387 if (!acked)
389 uchar c = 0x10;
390 if ((in[5] & 0x80) == 0)
392 for (unsigned i = 0; i < indaddr (); i++)
393 if (indaddr[i] == (in[3] << 8) | in[4])
394 c |= 0x1;
396 else
398 for (unsigned i = 0; i < groupaddr (); i++)
399 if (groupaddr[i] == (in[3] << 8) | in[4])
400 c |= 0x1;
402 TRACEPRINTF (t, 0, this, "SendAck %02X", c);
403 pth_write_ev (fd, &c, 1, stop);
404 acked = 1;
406 unsigned len = in[5] & 0x0f;
407 len += 6 + 2;
408 if (in () < len)
410 if (!to)
412 to = 1;
413 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
414 pth_timeout (0, 300000));
416 if (pth_event_status (timeout) != PTH_STATUS_OCCURRED)
417 break;
418 TRACEPRINTF (t, 0, this, "Remove2 %02X", in[0]);
419 in.deletepart (0, 1);
420 continue;
422 acked = 0;
423 RecvLPDU (in.array (), len);
424 in.deletepart (0, len);
426 else if ((in[0] & 0xD0) == 0x10)
428 if (in () < 7)
430 if (!to)
432 to = 1;
433 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
434 pth_timeout (0, 300000));
436 if (pth_event_status (timeout) != PTH_STATUS_OCCURRED)
437 break;
438 TRACEPRINTF (t, 0, this, "Remove1 %02X", in[0]);
439 in.deletepart (0, 1);
440 continue;
442 if (!acked)
444 uchar c = 0x10;
445 if ((in[1] & 0x80) == 0)
447 for (unsigned i = 0; i < indaddr (); i++)
448 if (indaddr[i] == (in[4] << 8) | in[5])
449 c |= 0x1;
451 else
453 for (unsigned i = 0; i < groupaddr (); i++)
454 if (groupaddr[i] == (in[4] << 8) | in[5])
455 c |= 0x1;
457 TRACEPRINTF (t, 0, this, "SendAck %02X", c);
458 pth_write_ev (fd, &c, 1, stop);
459 acked = 1;
461 unsigned len = in[6] & 0xff;
462 len += 7 + 2;
463 if (in () < len)
465 if (!to)
467 to = 1;
468 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
469 pth_timeout (0, 300000));
471 if (pth_event_status (timeout) != PTH_STATUS_OCCURRED)
472 break;
473 TRACEPRINTF (t, 0, this, "Remove2 %02X", in[0]);
474 in.deletepart (0, 1);
475 continue;
477 acked = 0;
478 RecvLPDU (in.array (), len);
479 in.deletepart (0, len);
481 else
483 acked = 0;
484 TRACEPRINTF (t, 0, this, "Remove %02X", in[0]);
485 in.deletepart (0, 1);
487 to = 0;
489 if (waitconfirm
490 && pth_event_status (sendtimeout) == PTH_STATUS_OCCURRED)
492 retry++;
493 waitconfirm = 0;
494 if (retry >= 3)
496 TRACEPRINTF (t, 0, this, "Drop Send");
497 delete inqueue.get ();
498 pth_sem_dec (&in_signal);
501 if (watch == 1 && pth_event_status (watchdog) == PTH_STATUS_OCCURRED)
503 uchar c = 0x01;
504 t->TracePacket (2, this, "Watchdog Reset", 1, &c);
505 write (fd, &c, 1);
506 watch = 0;
508 if (watch == 2 && pth_event_status (watchdog) == PTH_STATUS_OCCURRED)
509 watch = 0;
510 if (in () == 0 && !inqueue.isempty () && !waitconfirm)
512 LPDU *l = (LPDU *) inqueue.top ();
513 CArray d = l->ToPacket ();
514 CArray w;
515 unsigned i;
516 int j;
517 w.resize (d () * 2);
518 for (i = 0; i < d (); i++)
520 w[2 * i] = 0x80 | (i & 0x3f);
521 w[2 * i + 1] = d[i];
523 w[(d () * 2) - 2] = (w[(d () * 2) - 2] & 0x3f) | 0x40;
524 t->TracePacket (0, this, "Write", w);
525 j = pth_write_ev (fd, w.array (), w (), stop);
526 waitconfirm = 1;
527 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, sendtimeout,
528 pth_timeout (0, 600000));
530 else if (in () == 0 && !waitconfirm && !watch && mode == 0 && !to)
532 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, watchdog,
533 pth_timeout (10, 0));
534 watch = 1;
535 uchar c = 0x02;
536 t->TracePacket (2, this, "Watchdog Status", 1, &c);
537 write (fd, &c, 1);
540 pth_event_free (stop, PTH_FREE_THIS);
541 pth_event_free (input, PTH_FREE_THIS);
542 pth_event_free (timeout, PTH_FREE_THIS);
543 pth_event_free (watchdog, PTH_FREE_THIS);
544 pth_event_free (sendtimeout, PTH_FREE_THIS);