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