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