Copyright update for 2011
[bcusdk.git] / eibd / backend / bcu1serial.cpp
blobb620bec2082a78ffcdf83bbe2a40efd4d77eaf65
1 /*
2 EIBD eib bus access and management daemon
3 Copyright (C) 2005-2011 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <fcntl.h>
21 #include <termios.h>
22 #include <sys/ioctl.h>
23 #include <unistd.h>
24 #include <time.h>
25 #include "bcu1serial.h"
27 void
28 BCU1SerialLowLevelDriver::SendReset ()
32 bool
33 BCU1SerialLowLevelDriver::Connection_Lost ()
35 return 0;
38 void
39 BCU1SerialLowLevelDriver::Send_Packet (CArray l)
41 CArray pdu;
42 t->TracePacket (1, this, "Send", l);
43 inqueue.put (l);
44 pth_sem_set_value (&send_empty, 0);
45 pth_sem_inc (&in_signal, TRUE);
48 bool
49 BCU1SerialLowLevelDriver::Send_Queue_Empty ()
51 return inqueue.isempty ();
54 pth_sem_t *
55 BCU1SerialLowLevelDriver::Send_Queue_Empty_Cond ()
57 return &send_empty;
60 CArray *
61 BCU1SerialLowLevelDriver::Get_Packet (pth_event_t stop)
63 if (stop != NULL)
64 pth_event_concat (getwait, stop, NULL);
66 pth_wait (getwait);
68 if (stop)
69 pth_event_isolate (getwait);
71 if (pth_event_status (getwait) == PTH_STATUS_OCCURRED)
73 pth_sem_dec (&out_signal);
74 CArray *c = outqueue.get ();
75 t->TracePacket (1, this, "Recv", *c);
76 return c;
78 else
79 return 0;
82 BCU1SerialLowLevelDriver::BCU1SerialLowLevelDriver (const char *dev,
83 Trace * tr)
85 struct termios ti;
87 t = tr;
88 pth_sem_init (&in_signal);
89 pth_sem_init (&out_signal);
90 pth_sem_init (&send_empty);
91 pth_sem_set_value (&send_empty, 1);
92 getwait = pth_event (PTH_EVENT_SEM, &out_signal);
94 TRACEPRINTF (t, 1, this, "Open");
95 fd = open (dev, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);
96 if (fd == -1)
97 return;
98 set_low_latency (fd, &sold);
100 close (fd);
101 fd = open (dev, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);
102 if (fd == -1)
103 return;
105 if (tcgetattr (fd, &told))
107 restore_low_latency (fd, &sold);
108 close (fd);
109 fd = -1;
110 return;
113 if (tcgetattr (fd, &ti))
115 restore_low_latency (fd, &sold);
116 close (fd);
117 fd = -1;
118 return;
120 ti.c_cflag = CS8 | CLOCAL | CREAD;
121 ti.c_iflag = IGNBRK | INPCK | ISIG;
122 ti.c_oflag = 0;
123 ti.c_lflag = 0;
124 ti.c_cc[VTIME] = 1;
125 ti.c_cc[VMIN] = 0;
126 cfsetospeed (&ti, B9600);
127 cfsetispeed (&ti, 0);
129 if (tcsetattr (fd, TCSAFLUSH, &ti))
131 restore_low_latency (fd, &sold);
132 close (fd);
133 fd = -1;
134 return;
137 setstat (getstat () & ~(TIOCM_RTS | TIOCM_CTS));
138 while ((getstat () & TIOCM_CTS));
140 Start ();
141 TRACEPRINTF (t, 1, this, "Opened");
144 BCU1SerialLowLevelDriver::~BCU1SerialLowLevelDriver ()
146 TRACEPRINTF (t, 1, this, "Close");
147 Stop ();
148 pth_event_free (getwait, PTH_FREE_THIS);
150 if (fd != -1)
152 restore_low_latency (fd, &sold);
153 tcsetattr (fd, TCSAFLUSH, &told);
154 close (fd);
158 bool
159 BCU1SerialLowLevelDriver::init ()
161 return fd != -1;
165 BCU1SerialLowLevelDriver::getstat ()
167 int s;
168 ioctl (fd, TIOCMGET, &s);
169 return s;
172 void
173 BCU1SerialLowLevelDriver::setstat (int s)
175 ioctl (fd, TIOCMSET, &s);
178 /** counts to number of set bits in x */
180 bitcount (unsigned char x)
182 int i, j;
183 for (i = j = 0; i < 8; i++)
184 if (x & (1 << i))
185 j++;
186 return j;
189 bool
190 BCU1SerialLowLevelDriver::startsync ()
192 int to = 0;
193 int s = getstat ();
194 setstat (s | TIOCM_RTS);
195 while (!(getstat () & TIOCM_CTS))
197 to++;
198 if (to > 0x10000)
199 return false;
201 TRACEPRINTF (t, 0, this, "Startsync");
202 return true;
205 bool
206 BCU1SerialLowLevelDriver::endsync ()
208 int to = 0;
209 int s = getstat ();
211 setstat (s & ~TIOCM_RTS);
212 while ((getstat () & TIOCM_CTS))
214 to++;
215 if (to > 0x10000)
216 return false;
218 TRACEPRINTF (t, 0, this, "Endsync");
219 return true;
222 bool
223 BCU1SerialLowLevelDriver::exchange (uchar c, uchar & result,
224 pth_event_t stop)
226 uchar s;
227 int i;
228 int to = 0;
230 write (fd, &c, 1);
231 while ((i = read (fd, &s, 1)) == -1)
233 to++;
234 if (to > 0x10000)
235 return false;
237 TRACEPRINTF (t, 0, this, "exchange %02X <->%02X", c, s);
238 result = s;
239 return true;
242 void
243 BCU1SerialLowLevelDriver::Run (pth_sem_t * stop1)
245 pth_event_t stop = pth_event (PTH_EVENT_SEM, stop1);
246 pth_event_t input = pth_event (PTH_EVENT_SEM, &in_signal);
247 pth_event_t timeout = pth_event (PTH_EVENT_RTIME, pth_time (0, 10));
248 while (pth_event_status (stop) != PTH_STATUS_OCCURRED)
250 int error;
251 timeout =
252 pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout,
253 pth_time (0, 150));
254 pth_event_concat (stop, input, timeout, NULL);
255 pth_wait (stop);
256 pth_event_isolate (stop);
257 pth_event_isolate (input);
258 timeout =
259 pth_event (PTH_EVENT_RTIME | PTH_MODE_REUSE, timeout,
260 pth_time (0, 200));
261 pth_event_concat (stop, timeout, NULL);
263 struct timeval v1, v2;
264 gettimeofday (&v1, 0);
266 CArray e;
267 CArray r;
268 uchar s;
269 if (!inqueue.isempty ())
271 const CArray & c = inqueue.top ();
272 e.resize (c () + 1);
273 s = c () & 0x1f;
274 s |= 0x20;
275 s |= 0x80 * bitcount (s);
276 e[0] = s;
277 e.setpart (c, 1);
279 else
281 e.resize (1);
282 e[0] = 0xff;
284 if (!startsync ())
286 error = 1;
287 goto err;
289 if (!exchange (e[0], s, stop))
291 error = 3;
292 goto err;
294 if (!endsync ())
296 error = 2;
297 goto err;
299 if (s == 0xff && e[0] != 0xff)
301 for (unsigned i = 1; i < e (); i++)
303 if (!startsync ())
305 error = 1;
306 goto err;
308 if (!exchange (e[i], s, stop))
310 error = 3;
311 goto err;
313 if (endsync ())
315 error = 2;
316 goto err;
319 if (s != 0x00)
321 error = 10;
322 goto err;
324 inqueue.get ();
325 TRACEPRINTF (t, 0, this, "Sent");
326 pth_sem_dec (&in_signal);
327 if (inqueue.isempty ())
328 pth_sem_set_value (&send_empty, 1);
330 else if (s != 0xff)
332 r.resize ((s & 0x1f));
333 for (unsigned i = 0; i < (s & 0x1f); i++)
335 if (!startsync ())
337 error = 1;
338 goto err;
340 if (!exchange (0, r[i], stop))
342 error = 3;
343 goto err;
345 if (!endsync ())
347 error = 2;
348 goto err;
351 TRACEPRINTF (t, 0, this, "Recv");
352 outqueue.put (new CArray (r));
353 pth_sem_inc (&out_signal, 1);
355 gettimeofday (&v2, 0);
356 TRACEPRINTF (t, 1, this, "Recvtime: %d",
357 v2.tv_sec * 1000000L + v2.tv_usec -
358 (v1.tv_sec * 1000000L + v1.tv_usec));
360 if (0)
362 err:
363 gettimeofday (&v2, 0);
364 TRACEPRINTF (t, 1, this, "ERecvtime: %d",
365 v2.tv_sec * 1000000L + v2.tv_usec -
366 (v1.tv_sec * 1000000L + v1.tv_usec));
367 setstat (getstat () & ~(TIOCM_RTS | TIOCM_CTS));
368 pth_usleep (2000);
369 while ((getstat () & TIOCM_CTS));
370 TRACEPRINTF (t, 0, this, "Restart %d", error);
373 pth_event_isolate (timeout);
375 pth_event_free (timeout, PTH_FREE_THIS);
376 pth_event_free (stop, PTH_FREE_THIS);
377 pth_event_free (input, PTH_FREE_THIS);
380 LowLevelDriverInterface::EMIVer BCU1SerialLowLevelDriver::getEMIVer ()
382 return vEMI1;