Support extended frames
[bcusdk.git] / eibd / backend / tpuartserial.cpp
blobd22e611beb9a800703689982d661b4329632f375
1 /*
2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2007 Martin Kögler <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 pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
293 pth_event_t input = pth_event (PTH_EVENT_SEM, &in_signal);
294 pth_event_t timeout = pth_event (PTH_EVENT_TIME, pth_timeout (0, 0));
295 pth_event_t sendtimeout = pth_event (PTH_EVENT_TIME, pth_timeout (0, 0));
296 while (pth_event_status (stop) != PTH_STATUS_OCCURRED)
298 if (in () == 0 && !waitconfirm)
299 pth_event_concat (stop, input, NULL);
300 if (to)
301 pth_event_concat (stop, timeout, NULL);
302 if (waitconfirm)
303 pth_event_concat (stop, sendtimeout, NULL);
304 i = pth_read_ev (fd, buf, sizeof (buf), stop);
305 pth_event_isolate (stop);
306 pth_event_isolate (timeout);
307 pth_event_isolate (sendtimeout);
308 if (i > 0)
310 t->TracePacket (0, this, "Recv", i, buf);
311 in.setpart (buf, in (), i);
313 while (in () > 0)
315 if (in[0] == 0x8B)
317 if (waitconfirm)
319 waitconfirm = 0;
320 delete inqueue.get ();
321 pth_sem_dec (&in_signal);
322 retry = 0;
324 in.deletepart (0, 1);
326 else if (in[0] == 0x0B)
328 if (waitconfirm)
330 retry++;
331 waitconfirm = 0;
332 TRACEPRINTF (t, 0, this, "NACK");
333 if (retry > 3)
335 TRACEPRINTF (t, 0, this, "Drop NACK");
336 delete inqueue.get ();
337 pth_sem_dec (&in_signal);
338 retry = 0;
341 in.deletepart (0, 1);
343 else if (in[0] == 0xCC || in[0] == 0xC0 || in[0] == 0x0C)
345 RecvLPDU (in.array (), 1);
346 in.deletepart (0, 1);
348 else if ((in[0] & 0xD0) == 0x90)
350 if (in () < 6)
352 if (!to)
354 to = 1;
355 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
356 pth_timeout (0, 300000));
358 if (pth_event_status (timeout) != PTH_STATUS_OCCURRED)
359 break;
360 TRACEPRINTF (t, 0, this, "Remove1 %02X", in[0]);
361 in.deletepart (0, 1);
362 continue;
364 if (!acked)
366 uchar c = 0x10;
367 if ((in[5] & 0x80) == 0)
369 for (unsigned i = 0; i < indaddr (); i++)
370 if (indaddr[i] == (in[3] << 8) | in[4])
371 c |= 0x1;
373 else
375 for (unsigned i = 0; i < groupaddr (); i++)
376 if (groupaddr[i] == (in[3] << 8) | in[4])
377 c |= 0x1;
379 TRACEPRINTF (t, 0, this, "SendAck %02X", c);
380 pth_write_ev (fd, &c, 1, stop);
381 acked = 1;
383 unsigned len = in[5] & 0x0f;
384 len += 6 + 2;
385 if (in () < len)
387 if (!to)
389 to = 1;
390 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
391 pth_timeout (0, 300000));
393 if (pth_event_status (timeout) != PTH_STATUS_OCCURRED)
394 break;
395 TRACEPRINTF (t, 0, this, "Remove2 %02X", in[0]);
396 in.deletepart (0, 1);
397 continue;
399 acked = 0;
400 RecvLPDU (in.array (), len);
401 in.deletepart (0, len);
403 else if ((in[0] & 0xD0) == 0x10)
405 if (in () < 7)
407 if (!to)
409 to = 1;
410 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
411 pth_timeout (0, 300000));
413 if (pth_event_status (timeout) != PTH_STATUS_OCCURRED)
414 break;
415 TRACEPRINTF (t, 0, this, "Remove1 %02X", in[0]);
416 in.deletepart (0, 1);
417 continue;
419 if (!acked)
421 uchar c = 0x10;
422 if ((in[1] & 0x80) == 0)
424 for (unsigned i = 0; i < indaddr (); i++)
425 if (indaddr[i] == (in[4] << 8) | in[5])
426 c |= 0x1;
428 else
430 for (unsigned i = 0; i < groupaddr (); i++)
431 if (groupaddr[i] == (in[4] << 8) | in[5])
432 c |= 0x1;
434 TRACEPRINTF (t, 0, this, "SendAck %02X", c);
435 pth_write_ev (fd, &c, 1, stop);
436 acked = 1;
438 unsigned len = in[6] & 0xff;
439 len += 7 + 2;
440 if (in () < len)
442 if (!to || 1)
444 to = 1;
445 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, timeout,
446 pth_timeout (0, 300000));
448 if (pth_event_status (timeout) != PTH_STATUS_OCCURRED)
449 break;
450 TRACEPRINTF (t, 0, this, "Remove2 %02X", in[0]);
451 in.deletepart (0, 1);
452 continue;
454 acked = 0;
455 RecvLPDU (in.array (), len);
456 in.deletepart (0, len);
458 else
460 acked = 0;
461 TRACEPRINTF (t, 0, this, "Remove %02X", in[0]);
462 in.deletepart (0, 1);
464 to = 0;
466 if (waitconfirm
467 && pth_event_status (sendtimeout) == PTH_STATUS_OCCURRED)
469 retry++;
470 waitconfirm = 0;
471 if (retry >= 3)
473 TRACEPRINTF (t, 0, this, "Drop Send");
474 delete inqueue.get ();
475 pth_sem_dec (&in_signal);
478 if (in () == 0 && !inqueue.isempty () && !waitconfirm)
480 LPDU *l = (LPDU *) inqueue.top ();
481 CArray d = l->ToPacket ();
482 CArray w;
483 unsigned i;
484 int j;
485 w.resize (d () * 2);
486 for (i = 0; i < d (); i++)
488 w[2 * i] = 0x80 | (i & 0x3f);
489 w[2 * i + 1] = d[i];
491 w[(d () * 2) - 2] = (w[(d () * 2) - 2] & 0x3f) | 0x40;
492 t->TracePacket (0, this, "Write", w);
493 j = pth_write_ev (fd, w.array (), w (), stop);
494 waitconfirm = 1;
495 pth_event (PTH_EVENT_TIME | PTH_MODE_REUSE, sendtimeout,
496 pth_timeout (0, 600000));
499 pth_event_free (stop, PTH_FREE_THIS);
500 pth_event_free (input, PTH_FREE_THIS);
501 pth_event_free (timeout, PTH_FREE_THIS);
502 pth_event_free (sendtimeout, PTH_FREE_THIS);