Remove unused variable.
[bertos.git] / drv / ser.c
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
6  * This file is part of DevLib - See devlib/README for information.
7  * -->
8  *
9  * \brief Buffered serial I/O driver
10  *
11  * The serial rx interrupt buffers incoming data in a software FIFO
12  * to decouple the higher level protocols from the line speed.
13  * Outgoing data is buffered as well for better performance.
14  * This driver is not optimized for best performance, but it
15  * has proved to be fast enough to handle transfer rates up to
16  * 38400bps on a 16MHz 80196.
17  *
18  * MODULE CONFIGURATION
19  *
20  *  \li \c CONFIG_SER_HWHANDSHAKE - set to 1 to enable RTS/CTS handshake.
21  *         Support is incomplete/untested.
22  *  \li \c CONFIG_SER_TXTIMEOUT - Enable software serial transmission timeouts
23  *
24  *
25  * \version $Id$
26  * \author Bernardo Innocenti <bernie@develer.com>
27  */
28
29 /*#*
30  *#* $Log$
31  *#* Revision 1.20  2004/10/19 11:48:00  bernie
32  *#* Remove unused variable.
33  *#*
34  *#* Revision 1.19  2004/10/19 08:14:13  bernie
35  *#* Fix a few longstanding bugs wrt status handling (made by rasky on scfirm).
36  *#*
37  *#* Revision 1.18  2004/09/20 03:31:15  bernie
38  *#* Sanitize for C++.
39  *#*
40  *#* Revision 1.17  2004/09/14 21:06:07  bernie
41  *#* Use debug.h instead of kdebug.h; Spelling fixes.
42  *#*
43  *#* Revision 1.16  2004/09/06 21:40:50  bernie
44  *#* Move buffer handling in chip-specific driver.
45  *#*
46  *#* Revision 1.15  2004/08/25 14:12:08  rasky
47  *#* Aggiornato il comment block dei log RCS
48  *#*
49  *#* Revision 1.14  2004/08/24 16:22:57  bernie
50  *#* Thinkos; Doxygen fixes
51  *#*
52  *#* Revision 1.13  2004/08/24 16:20:48  bernie
53  *#* ser_read(): Make buffer argument void *#* for consistency with ANSI C and ser_write()
54  *#*
55  *#* Revision 1.12  2004/08/24 13:49:39  bernie
56  *#* Fix thinko.
57  *#*
58  *#* Revision 1.11  2004/08/15 05:32:22  bernie
59  *#* ser_resync(): New function.
60  *#*
61  *#* Revision 1.10  2004/08/10 06:29:50  bernie
62  *#* Rename timer_gettick() to timer_ticks().
63  *#*
64  *#* Revision 1.9  2004/08/08 06:06:20  bernie
65  *#* Use new-style CONFIG_ idiom; Fix module-wide documentation.
66  *#*
67  *#* Revision 1.8  2004/07/29 22:57:09  bernie
68  *#* ser_drain(): New function; Make Serial::is_open a debug-only feature; Switch to new-style CONFIG_* macros.
69  *#*
70  *#* Revision 1.7  2004/07/18 21:49:03  bernie
71  *#* Make CONFIG_SER_DEFBAUDRATE optional.
72  *#*
73  *#* Revision 1.6  2004/06/07 15:56:28  aleph
74  *#* Remove cast-as-lvalue extension abuse
75  *#*
76  *#* Revision 1.5  2004/06/06 16:41:44  bernie
77  *#* ser_putchar(): Use fifo_push_locked() to fix potential race on 8bit processors.
78  *#*
79  *#* Revision 1.4  2004/06/03 11:27:09  bernie
80  *#* Add dual-license information.
81  *#*
82  *#* Revision 1.3  2004/06/02 21:35:24  aleph
83  *#* Serial enhancements: interruptible receive handler and 8 bit serial status for AVR; remove volatile attribute to FIFOBuffer, useless for new fifobuf routens
84  *#*
85  *#* Revision 1.2  2004/05/23 18:21:53  bernie
86  *#* Trim CVS logs and cleanup header info.
87  *#*
88  *#*/
89
90 #include <mware/formatwr.h>
91 #include <debug.h>
92 #include "ser.h"
93 #include "ser_p.h"
94 #include "hw.h"
95
96 #ifdef CONFIG_KERNEL
97         #include <kern/proc.h>
98 #endif
99 #if CONFIG_SER_TXTIMEOUT != -1 || CONFIG_SER_RXTIMEOUT != -1
100         #include <drv/timer.h>
101 #endif
102
103
104 /* Serial configuration parameters */
105 #define SER_CTSDELAY        70  /*!< CTS line retry interval (ms) */
106 #define SER_TXPOLLDELAY      2  /*!< Transmit buffer full retry interval (ms) */
107 #define SER_RXPOLLDELAY      2  /*!< Receive buffer empty retry interval (ms) */
108
109
110 struct Serial ser_handles[SER_CNT];
111
112
113 /*!
114  * Inserisce il carattere c nel buffer di trasmissione.
115  * Questa funzione mette il processo chiamante in attesa
116  * quando il buffer e' pieno.
117  *
118  * \return EOF in caso di errore o timeout, altrimenti
119  *         il carattere inviato.
120  */
121 int ser_putchar(int c, struct Serial *port)
122 {
123         //ASSERT_VALID_FIFO(&port->txfifo);
124         if (fifo_isfull_locked(&port->txfifo))
125         {
126 #if CONFIG_SER_TXTIMEOUT != -1
127                 time_t start_time = timer_ticks();
128 #endif
129
130                 /* Attende finche' il buffer e' pieno... */
131                 do
132                 {
133 #if defined(CONFIG_KERN_SCHED) && CONFIG_KERN_SCHED
134                         /* Give up timeslice to other processes. */
135                         proc_switch();
136 #endif
137 #if CONFIG_SER_TXTIMEOUT != -1
138                         if (timer_ticks() - start_time >= port->txtimeout)
139                         {
140                                 port->status |= SERRF_TXTIMEOUT;
141                                 return EOF;
142                         }
143 #endif /* CONFIG_SER_TXTIMEOUT */
144                 }
145                 while (fifo_isfull_locked(&port->txfifo));
146         }
147
148         fifo_push_locked(&port->txfifo, (unsigned char)c);
149
150         /* (re)trigger tx interrupt */
151         port->hw->table->enabletxirq(port->hw);
152
153         /* Avoid returning signed extended char */
154         return (int)((unsigned char)c);
155 }
156
157
158 /*!
159  * Preleva un carattere dal buffer di ricezione.
160  * Questa funzione mette il processo chiamante in attesa
161  * quando il buffer e' vuoto. L'attesa ha un timeout
162  * di ser_rxtimeout millisecondi.
163  *
164  * \return EOF in caso di errore o timeout, altrimenti
165  *         il carattere ricevuto.
166  */
167 int ser_getchar(struct Serial *port)
168 {
169         if (fifo_isempty_locked(&port->rxfifo))
170         {
171 #if CONFIG_SER_RXTIMEOUT != -1
172                 time_t start_time = timer_ticks();
173 #endif
174                 /* Wait while buffer is empty */
175                 do
176                 {
177 #if defined(CONFIG_KERN_SCHED) && CONFIG_KERN_SCHED
178                         /* Give up timeslice to other processes. */
179                         proc_switch();
180 #endif
181 #if CONFIG_SER_RXTIMEOUT != -1
182                         if (timer_ticks() - start_time >= port->rxtimeout)
183                         {
184                                 port->status |= SERRF_RXTIMEOUT;
185                                 return EOF;
186                         }
187 #endif /* CONFIG_SER_RXTIMEOUT */
188                 }
189                 while (fifo_isempty_locked(&port->rxfifo) && (port->status & SERRF_RX) == 0);
190         }
191
192         /*
193          * Get a byte from the FIFO (avoiding sign-extension),
194          * re-enable RTS, then return result.
195          */
196         if (port->status & SERRF_RX)
197                 return EOF;
198         return (int)(unsigned char)fifo_pop_locked(&port->rxfifo);
199 }
200
201
202 /*!
203  * Preleva un carattere dal buffer di ricezione.
204  * Se il buffer e' vuoto, ser_getchar_nowait() ritorna
205  * immediatamente EOF.
206  */
207 int ser_getchar_nowait(struct Serial *port)
208 {
209         if (fifo_isempty_locked(&port->rxfifo))
210                 return EOF;
211
212         /* NOTE: the double cast prevents unwanted sign extension */
213         return (int)(unsigned char)fifo_pop_locked(&port->rxfifo);
214 }
215
216
217 #if CONFIG_SER_GETS
218 /*!
219  * Read a line long at most as size and puts it
220  * in buf.
221  * \return number of chars read or EOF in case
222  *         of error.
223  */
224 int ser_gets(struct Serial *port, char *buf, int size)
225 {
226         return ser_gets_echo(port, buf, size, false);
227 }
228
229
230 /*!
231  * Read a line long at most as size and put it
232  * in buf, with optional echo.
233  *
234  * \return number of chars read, or EOF in case
235  *         of error.
236  */
237 int ser_gets_echo(struct Serial *port, char *buf, int size, bool echo)
238 {
239         int i = 0;
240         int c;
241
242         for (;;)
243         {
244                 if ((c = ser_getchar(port)) == EOF)
245                 {
246                         buf[i] = '\0';
247                         return -1;
248                 }
249
250                 /* FIXME */
251                 if (c == '\r' || c == '\n' || i >= size-1)
252                 {
253                         buf[i] = '\0';
254                         if (echo)
255                                 ser_print(port, "\r\n");
256                         break;
257                 }
258                 buf[i++] = c;
259                 if (echo)
260                         ser_putchar(c, port);
261         }
262
263         return i;
264 }
265 #endif /* !CONFIG_SER_GETS */
266
267
268 /*!
269  * Read at most \a size bytes from \a port and put them in \a buf
270  *
271  * \return number of bytes actually read, or EOF in
272  *         case of error.
273  */
274 int ser_read(struct Serial *port, void *buf, size_t size)
275 {
276         size_t i = 0;
277         char *_buf = (char *)buf;
278         int c;
279
280         while (i < size)
281         {
282                 if ((c = ser_getchar(port)) == EOF)
283                         return EOF;
284                 _buf[i++] = c;
285         }
286
287         return i;
288 }
289
290
291 /*!
292  * Write a string to serial.
293  * \return 0 if OK, EOF in case of error.
294  */
295 int ser_print(struct Serial *port, const char *s)
296 {
297         while (*s)
298         {
299                 if (ser_putchar(*s++, port) == EOF)
300                         return EOF;
301         }
302         return 0;
303 }
304
305
306 /*!
307  * \brief Write a buffer to serial.
308  *
309  * \return 0 if OK, EOF in case of error.
310  *
311  * \todo Optimize with fifo_pushblock()
312  */
313 int ser_write(struct Serial *port, const void *_buf, size_t len)
314 {
315         const char *buf = (const char *)_buf;
316
317         while (len--)
318         {
319                 if (ser_putchar(*buf++, port) == EOF)
320                         return EOF;
321         }
322         return 0;
323 }
324
325
326 #if CONFIG_PRINTF
327 /*!
328  * Formatted write
329  */
330 int ser_printf(struct Serial *port, const char *format, ...)
331 {
332         va_list ap;
333         int len;
334
335         va_start(ap, format);
336         len = _formatted_write(format, (void (*)(char, void *))ser_putchar, port, ap);
337         va_end(ap);
338
339         return len;
340 }
341 #endif /* CONFIG_PRINTF */
342
343
344 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
345 void ser_settimeouts(struct Serial *port, time_t rxtimeout, time_t txtimeout)
346 {
347         port->rxtimeout = rxtimeout;
348         port->txtimeout = txtimeout;
349 }
350 #endif /* CONFIG_SER_RXTIMEOUT || CONFIG_SER_TXTIMEOUT */
351
352 #if CONFIG_SER_RXTIMEOUT != -1
353 /*!
354  * Discard input to resynchronize with remote end.
355  *
356  * Discard incoming data until the port stops receiving
357  * characters for at least \a delay milliseconds.
358  *
359  * \note Serial errors are reset before and after executing the purge.
360  */
361 void ser_resync(struct Serial *port, time_t delay)
362 {
363         time_t old_rxtimeout = port->rxtimeout;
364
365         ser_settimeouts(port, delay, port->txtimeout);
366         do
367         {
368                 ser_setstatus(port, 0);
369                 ser_getchar(port);
370         }
371         while (!(ser_getstatus(port) & SERRF_RXTIMEOUT));
372
373         /* Restore port to an usable status */
374         ser_setstatus(port, 0);
375         ser_settimeouts(port, old_rxtimeout, port->txtimeout);
376 }
377 #endif /* CONFIG_SER_RXTIMEOUT */
378
379
380 void ser_setbaudrate(struct Serial *port, unsigned long rate)
381 {
382         port->hw->table->setbaudrate(port->hw, rate);
383 }
384
385
386 void ser_setparity(struct Serial *port, int parity)
387 {
388         port->hw->table->setparity(port->hw, parity);
389 }
390
391
392 /*!
393  * Flush both the RX and TX buffers.
394  */
395 void ser_purge(struct Serial *port)
396 {
397         fifo_flush_locked(&port->rxfifo);
398         fifo_flush_locked(&port->txfifo);
399 }
400
401
402 /*!
403  * Wait until all pending output is completely
404  * transmitted to the other end.
405  *
406  * \note The current implementation only checks the
407  *       software transmission queue. Any hardware
408  *       FIFOs are ignored.
409  */
410 void ser_drain(struct Serial *ser)
411 {
412         while (!fifo_isempty(&ser->txfifo))
413         {
414 #if defined(CONFIG_KERN_SCHED) && CONFIG_KERN_SCHED
415                         /* Give up timeslice to other processes. */
416                         proc_switch();
417 #endif
418         }
419 }
420
421
422 /*!
423  * Initialize serial
424  */
425 struct Serial *ser_open(unsigned int unit)
426 {
427         struct Serial *port;
428
429         ASSERT(unit < countof(ser_handles));
430         port = &ser_handles[unit];
431
432         ASSERT(!port->is_open);
433         DB(port->is_open = true;)
434
435         port->unit = unit;
436
437         port->hw = ser_hw_getdesc(unit);
438
439         /* Initialize circular buffers */
440         ASSERT(port->hw->txbuffer);
441         ASSERT(port->hw->rxbuffer);
442         fifo_init(&port->txfifo, port->hw->txbuffer, port->hw->txbuffer_size);
443         fifo_init(&port->rxfifo, port->hw->rxbuffer, port->hw->rxbuffer_size);
444
445         port->hw->table->init(port->hw, port);
446
447         /* Set default values */
448 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
449         ser_settimeouts(port, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
450 #endif
451 #if CONFIG_SER_DEFBAUDRATE
452         ser_setbaudrate(port, CONFIG_SER_DEFBAUDRATE);
453 #endif
454
455         return port;
456 }
457
458
459 /*!
460  * Clean up serial port, disabling the associated hardware.
461  */
462 void ser_close(struct Serial *port)
463 {
464         ASSERT(port->is_open);
465         DB(port->is_open = false;)
466
467         port->hw->table->cleanup(port->hw);
468         port->hw = NULL;
469 }