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