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