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