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