Rename timer_gettick() to timer_ticks().
[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.10  2004/08/10 06:29:50  bernie
32  * Rename timer_gettick() to timer_ticks().
33  *
34  * Revision 1.9  2004/08/08 06:06:20  bernie
35  * Use new-style CONFIG_ idiom; Fix module-wide documentation.
36  *
37  * Revision 1.8  2004/07/29 22:57:09  bernie
38  * ser_drain(): New function; Make Serial::is_open a debug-only feature; Switch to new-style CONFIG_* macros.
39  *
40  * Revision 1.7  2004/07/18 21:49:03  bernie
41  * Make CONFIG_SER_DEFBAUDRATE optional.
42  *
43  * Revision 1.6  2004/06/07 15:56:28  aleph
44  * Remove cast-as-lvalue extension abuse
45  *
46  * Revision 1.5  2004/06/06 16:41:44  bernie
47  * ser_putchar(): Use fifo_push_locked() to fix potential race on 8bit processors.
48  *
49  * Revision 1.4  2004/06/03 11:27:09  bernie
50  * Add dual-license information.
51  *
52  * Revision 1.3  2004/06/02 21:35:24  aleph
53  * Serial enhancements: interruptible receive handler and 8 bit serial status for AVR; remove volatile attribute to FIFOBuffer, useless for new fifobuf routens
54  *
55  * Revision 1.2  2004/05/23 18:21:53  bernie
56  * Trim CVS logs and cleanup header info.
57  *
58  */
59
60 #include <mware/formatwr.h>
61 #include <drv/kdebug.h>
62 #include "ser.h"
63 #include "ser_p.h"
64 #include "hw.h"
65
66 #ifdef CONFIG_KERNEL
67         #include <kern/proc.h>
68 #endif
69 #if CONFIG_SER_TXTIMEOUT != -1 || CONFIG_SER_RXTIMEOUT != -1
70         #include <drv/timer.h>
71 #endif
72
73
74 /* Serial configuration parameters */
75 #define SER_CTSDELAY        70  /*!< CTS line retry interval (ms) */
76 #define SER_TXPOLLDELAY      2  /*!< Transmit buffer full retry interval (ms) */
77 #define SER_RXPOLLDELAY      2  /*!< Receive buffer empty retry interval (ms) */
78
79
80 struct Serial ser_handles[SER_CNT];
81
82
83 /*!
84  * Inserisce il carattere c nel buffer di trasmissione.
85  * Questa funzione mette il processo chiamante in attesa
86  * quando il buffer e' pieno.
87  *
88  * \return EOF in caso di errore o timeout, altrimenti
89  *         il carattere inviato.
90  */
91 int ser_putchar(int c, struct Serial *port)
92 {
93         if (fifo_isfull_locked(&port->txfifo))
94         {
95 #if CONFIG_SER_TXTIMEOUT != -1
96                 time_t start_time = timer_ticks();
97 #endif
98
99                 /* Attende finche' il buffer e' pieno... */
100                 do
101                 {
102 #if defined(CONFIG_KERN_SCHED) && CONFIG_KERN_SCHED
103                         /* Give up timeslice to other processes. */
104                         proc_switch();
105 #endif
106 #if CONFIG_SER_TXTIMEOUT != -1
107                         if (timer_ticks() - start_time >= port->txtimeout)
108                         {
109                                 port->status |= SERRF_TXTIMEOUT;
110                                 return EOF;
111                         }
112 #endif /* CONFIG_SER_TXTIMEOUT */
113                 }
114                 while (fifo_isfull_locked(&port->txfifo));
115         }
116
117         fifo_push_locked(&port->txfifo, (unsigned char)c);
118
119         /* (re)trigger tx interrupt */
120         port->hw->table->enabletxirq(port->hw);
121
122         /* Avoid returning signed estended char */
123         return (int)((unsigned char)c);
124 }
125
126
127 /*!
128  * Preleva un carattere dal buffer di ricezione.
129  * Questa funzione mette il processo chiamante in attesa
130  * quando il buffer e' vuoto. L'attesa ha un timeout
131  * di ser_rxtimeout millisecondi.
132  *
133  * \return EOF in caso di errore o timeout, altrimenti
134  *         il carattere ricevuto.
135  */
136 int ser_getchar(struct Serial *port)
137 {
138         int result;
139
140         if (fifo_isempty_locked(&port->rxfifo))
141         {
142 #if CONFIG_SER_RXTIMEOUT != -1
143                 time_t start_time = timer_ticks();
144 #endif
145                 /* Wait while buffer is empty */
146                 do
147                 {
148 #if defined(CONFIG_KERN_SCHED) && CONFIG_KERN_SCHED
149                         /* Give up timeslice to other processes. */
150                         proc_switch();
151 #endif
152 #if CONFIG_SER_RXTIMEOUT != -1
153                         if (timer_ticks() - start_time >= port->rxtimeout)
154                         {
155                                 port->status |= SERRF_RXTIMEOUT;
156                                 return EOF;
157                         }
158 #endif /* CONFIG_SER_RXTIMEOUT */
159                 }
160                 while (fifo_isempty_locked(&port->rxfifo));
161         }
162
163         /*
164          * Get a byte from the FIFO (avoiding sign-extension),
165          * re-enable RTS, then return result.
166          */
167         result = (int)(unsigned char)fifo_pop(&port->rxfifo);
168         return port->status ? EOF : result;
169 }
170
171
172 /*!
173  * Preleva un carattere dal buffer di ricezione.
174  * Se il buffer e' vuoto, ser_getchar_nowait() ritorna
175  * immediatamente EOF.
176  */
177 int ser_getchar_nowait(struct Serial *port)
178 {
179         if (fifo_isempty_locked(&port->rxfifo))
180                 return EOF;
181
182         /* NOTE: the double cast prevents unwanted sign extension */
183         return (int)(unsigned char)fifo_pop(&port->rxfifo);
184 }
185
186
187 #if CONFIG_SER_GETS
188 /*!
189  * Read a line long at most as size and puts it
190  * in buf.
191  * \return number of chars read or EOF in case
192  *         of error.
193  */
194 int ser_gets(struct Serial *port, char *buf, int size)
195 {
196         return ser_gets_echo(port, buf, size, false);
197 }
198
199
200 /*!
201  * Read a line long at most as size and put it
202  * in buf, with optional echo.
203  *
204  * \return number of chars read, or EOF in case
205  *         of error.
206  */
207 int ser_gets_echo(struct Serial *port, char *buf, int size, bool echo)
208 {
209         int i = 0;
210         int c;
211
212         for (;;)
213         {
214                 if ((c = ser_getchar(port)) == EOF)
215                 {
216                         buf[i] = '\0';
217                         return -1;
218                 }
219
220                 /* FIXME */
221                 if (c == '\r' || c == '\n' || i >= size-1)
222                 {
223                         buf[i] = '\0';
224                         if (echo)
225                                 ser_print(port, "\r\n");
226                         break;
227                 }
228                 buf[i++] = c;
229                 if (echo)
230                         ser_putchar(c, port);
231         }
232
233         return i;
234 }
235 #endif /* !CONFIG_SER_GETS */
236
237
238 /*!
239  * Read at most size bytes and puts them
240  * in buf.
241  * \return number of bytes read or EOF in case
242  *         of error.
243  */
244 int ser_read(struct Serial *port, char *buf, size_t size)
245 {
246         size_t i = 0;
247         int c;
248
249         while (i < size)
250         {
251                 if ((c = ser_getchar(port)) == EOF)
252                         return EOF;
253                 buf[i++] = c;
254         }
255
256         return i;
257 }
258
259
260 /*!
261  * Write a string to serial.
262  * \return 0 if OK, EOF in case of error.
263  */
264 int ser_print(struct Serial *port, const char *s)
265 {
266         while (*s)
267         {
268                 if (ser_putchar(*s++, port) == EOF)
269                         return EOF;
270         }
271         return 0;
272 }
273
274
275 /*!
276  * \brief Write a buffer to serial.
277  *
278  * \return 0 if OK, EOF in case of error.
279  *
280  * \todo Optimize with fifo_pushblock()
281  */
282 int ser_write(struct Serial *port, const void *_buf, size_t len)
283 {
284         const char *buf = _buf;
285
286         while (len--)
287         {
288                 if (ser_putchar(*buf++, port) == EOF)
289                         return EOF;
290         }
291         return 0;
292 }
293
294
295 #if CONFIG_PRINTF
296 /*!
297  * Formatted write
298  */
299 int ser_printf(struct Serial *port, const char *format, ...)
300 {
301         va_list ap;
302         int len;
303
304         ser_setstatus(port, 0);
305         va_start(ap, format);
306         len = _formatted_write(format, (void (*)(char, void *))ser_putchar, port, ap);
307         va_end(ap);
308
309         return len;
310 }
311 #endif /* CONFIG_PRINTF */
312
313
314 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
315 void ser_settimeouts(struct Serial *port, time_t rxtimeout, time_t txtimeout)
316 {
317         port->rxtimeout = rxtimeout;
318         port->txtimeout = txtimeout;
319 }
320 #endif /* CONFIG_SER_RXTIMEOUT || CONFIG_SER_TXTIMEOUT */
321
322
323 void ser_setbaudrate(struct Serial *port, unsigned long rate)
324 {
325         port->hw->table->setbaudrate(port->hw, rate);
326 }
327
328
329 void ser_setparity(struct Serial *port, int parity)
330 {
331         port->hw->table->setparity(port->hw, parity);
332 }
333
334
335 /*!
336  * Flush both the RX and TX buffers.
337  */
338 void ser_purge(struct Serial *ser)
339 {
340         fifo_flush_locked(&ser->rxfifo);
341         fifo_flush_locked(&ser->txfifo);
342 }
343
344 /*!
345  * Wait until all pending output is completely
346  * transmitted to the other end.
347  *
348  * \note The current implementation only checks the
349  *       software transmission queue. Any hardware
350  *       FIFOs are ignored.
351  */
352 void ser_drain(struct Serial *ser)
353 {
354         while(!fifo_isempty(&ser->txfifo))
355         {
356 #if defined(CONFIG_KERN_SCHED) && CONFIG_KERN_SCHED
357                         /* Give up timeslice to other processes. */
358                         proc_switch();
359 #endif
360         }
361 }
362
363
364 /*!
365  * Initialize serial
366  */
367 struct Serial *ser_open(unsigned int unit)
368 {
369         struct Serial *port;
370
371         ASSERT(unit < countof(ser_handles));
372         port = &ser_handles[unit];
373
374         ASSERT(!port->is_open);
375         DB(port->is_open = true;)
376
377         port->unit = unit;
378
379         /* Initialize circular buffer */
380         fifo_init(&port->rxfifo, port->rxbuffer, sizeof(port->rxbuffer));
381         fifo_init(&port->txfifo, port->txbuffer, sizeof(port->txbuffer));
382
383         port->hw = ser_hw_getdesc(unit);
384         port->hw->table->init(port->hw, port);
385
386         /* Set default values */
387 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
388         ser_settimeouts(port, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
389 #endif
390 #if CONFIG_SER_DEFBAUDRATE
391         ser_setbaudrate(port, CONFIG_SER_DEFBAUDRATE);
392 #endif
393
394         return port;
395 }
396
397
398 /*!
399  * Clean up serial port, disabling the associated hardware.
400  */
401 void ser_close(struct Serial *port)
402 {
403         ASSERT(port->is_open);
404         DB(port->is_open = false;)
405
406         port->hw->table->cleanup(port->hw);
407         port->hw = NULL;
408 }