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