Remove cvs log.
[bertos.git] / drv / ser.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004, 2006 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
31  *
32  * -->
33  *
34  * \brief Buffered serial I/O driver
35  *
36  * The serial rx interrupt buffers incoming data in a software FIFO
37  * to decouple the higher level protocols from the line speed.
38  * Outgoing data is buffered as well for better performance.
39  * This driver is not optimized for best performance, but it
40  * has proved to be fast enough to handle transfer rates up to
41  * 38400bps on a 16MHz 80196.
42  *
43  * MODULE CONFIGURATION
44  *
45  *  \li \c CONFIG_SER_HWHANDSHAKE - set to 1 to enable RTS/CTS handshake.
46  *         Support is incomplete/untested.
47  *  \li \c CONFIG_SER_TXTIMEOUT - Enable software serial transmission timeouts
48  *
49  *
50  * \version $Id$
51  * \author Bernardo Innocenti <bernie@develer.com>
52  */
53
54 #include "ser.h"
55
56 #include "wdt.h"
57
58 #include "ser_p.h"
59 #include <mware/formatwr.h>
60 #include <cfg/debug.h>
61 #include <appconfig.h>
62
63 /*
64  * Sanity check for config parameters required by this module.
65  */
66 #if !defined(CONFIG_KERNEL) || ((CONFIG_KERNEL != 0) && CONFIG_KERNEL != 1)
67         #error CONFIG_KERNEL must be set to either 0 or 1 in config.h
68 #endif
69 #if !defined(CONFIG_SER_RXTIMEOUT)
70         #error CONFIG_SER_TXTIMEOUT missing in config.h
71 #endif
72 #if !defined(CONFIG_SER_RXTIMEOUT)
73         #error CONFIG_SER_RXTIMEOUT missing in config.h
74 #endif
75 #if !defined(CONFIG_SER_GETS) || ((CONFIG_SER_GETS != 0) && CONFIG_SER_GETS != 1)
76         #error CONFIG_SER_GETS must be set to either 0 or 1 in config.h
77 #endif
78 #if !defined(CONFIG_SER_DEFBAUDRATE)
79         #error CONFIG_SER_DEFBAUDRATE missing in config.h
80 #endif
81 #if !defined(CONFIG_PRINTF)
82         #error CONFIG_PRINTF missing in config.h
83 #endif
84
85 #if CONFIG_KERNEL
86         #include <kern/proc.h>
87 #endif
88
89 #if CONFIG_SER_TXTIMEOUT != -1 || CONFIG_SER_RXTIMEOUT != -1
90         #include <drv/timer.h>
91 #endif
92
93
94 /* Serial configuration parameters */
95 #define SER_CTSDELAY        70  /**< CTS line retry interval (ms) */
96 #define SER_TXPOLLDELAY      2  /**< Transmit buffer full retry interval (ms) */
97 #define SER_RXPOLLDELAY      2  /**< Receive buffer empty retry interval (ms) */
98
99
100 struct Serial ser_handles[SER_CNT];
101
102
103 /**
104  * Inserisce il carattere c nel buffer di trasmissione.
105  * Questa funzione mette il processo chiamante in attesa
106  * quando il buffer e' pieno.
107  *
108  * \return EOF in caso di errore o timeout, altrimenti
109  *         il carattere inviato.
110  */
111 int ser_putchar(int c, struct Serial *port)
112 {
113         //ASSERT_VALID_FIFO(&port->txfifo);
114         if (fifo_isfull_locked(&port->txfifo))
115         {
116 #if CONFIG_SER_TXTIMEOUT != -1
117                 ticks_t start_time = timer_clock();
118 #endif
119
120                 /* Attende finche' il buffer e' pieno... */
121                 do
122                 {
123                         wdt_reset();
124 #if CONFIG_KERNEL && CONFIG_KERN_SCHED
125                         /* Give up timeslice to other processes. */
126                         proc_switch();
127 #endif
128 #if CONFIG_SER_TXTIMEOUT != -1
129                         if (timer_clock() - start_time >= port->txtimeout)
130                         {
131                                 ATOMIC(port->status |= SERRF_TXTIMEOUT);
132                                 return EOF;
133                         }
134 #endif /* CONFIG_SER_TXTIMEOUT */
135                 }
136                 while (fifo_isfull_locked(&port->txfifo));
137         }
138
139         fifo_push_locked(&port->txfifo, (unsigned char)c);
140
141         /* (re)trigger tx interrupt */
142         port->hw->table->txStart(port->hw);
143
144         /* Avoid returning signed extended char */
145         return (int)((unsigned char)c);
146 }
147
148
149 /**
150  * Preleva un carattere dal buffer di ricezione.
151  * Questa funzione mette il processo chiamante in attesa
152  * quando il buffer e' vuoto. L'attesa ha un timeout
153  * di ser_rxtimeout millisecondi.
154  *
155  * \return EOF in caso di errore o timeout, altrimenti
156  *         il carattere ricevuto.
157  */
158 int ser_getchar(struct Serial *port)
159 {
160         if (fifo_isempty_locked(&port->rxfifo))
161         {
162 #if CONFIG_SER_RXTIMEOUT != -1
163                 ticks_t start_time = timer_clock();
164 #endif
165                 /* Wait while buffer is empty */
166                 do
167                 {
168                         wdt_reset();
169 #if CONFIG_KERNEL && CONFIG_KERN_SCHED
170                         /* Give up timeslice to other processes. */
171                         proc_switch();
172 #endif
173 #if CONFIG_SER_RXTIMEOUT != -1
174                         if (timer_clock() - start_time >= port->rxtimeout)
175                         {
176                                 ATOMIC(port->status |= SERRF_RXTIMEOUT);
177                                 return EOF;
178                         }
179 #endif /* CONFIG_SER_RXTIMEOUT */
180                 }
181                 while (fifo_isempty_locked(&port->rxfifo) && (ser_getstatus(port) & SERRF_RX) == 0);
182         }
183
184         /*
185          * Get a byte from the FIFO (avoiding sign-extension),
186          * re-enable RTS, then return result.
187          */
188         if (ser_getstatus(port) & SERRF_RX)
189                 return EOF;
190         return (int)(unsigned char)fifo_pop_locked(&port->rxfifo);
191 }
192
193
194 /**
195  * Preleva un carattere dal buffer di ricezione.
196  * Se il buffer e' vuoto, ser_getchar_nowait() ritorna
197  * immediatamente EOF.
198  */
199 int ser_getchar_nowait(struct Serial *port)
200 {
201         if (fifo_isempty_locked(&port->rxfifo))
202                 return EOF;
203
204         /* NOTE: the double cast prevents unwanted sign extension */
205         return (int)(unsigned char)fifo_pop_locked(&port->rxfifo);
206 }
207
208
209 #if CONFIG_SER_GETS
210 /**
211  * Read a line long at most as size and put it
212  * in buf.
213  * \return number of chars read or EOF in case
214  *         of error.
215  */
216 int ser_gets(struct Serial *port, char *buf, int size)
217 {
218         return ser_gets_echo(port, buf, size, false);
219 }
220
221
222 /**
223  * Read a line long at most as size and put it
224  * in buf, with optional echo.
225  *
226  * \return number of chars read, or EOF in case
227  *         of error.
228  */
229 int ser_gets_echo(struct Serial *port, char *buf, int size, bool echo)
230 {
231         int i = 0;
232         int c;
233
234         for (;;)
235         {
236                 if ((c = ser_getchar(port)) == EOF)
237                 {
238                         buf[i] = '\0';
239                         return -1;
240                 }
241
242                 /* FIXME */
243                 if (c == '\r' || c == '\n' || i >= size-1)
244                 {
245                         buf[i] = '\0';
246                         if (echo)
247                                 ser_print(port, "\r\n");
248                         break;
249                 }
250                 buf[i++] = c;
251                 if (echo)
252                         ser_putchar(c, port);
253         }
254
255         return i;
256 }
257 #endif /* !CONFIG_SER_GETS */
258
259
260 /**
261  * Read at most \a size bytes from \a port and put them in \a buf
262  *
263  * \return number of bytes actually read, or EOF in
264  *         case of error.
265  */
266 int ser_read(struct Serial *port, void *buf, size_t size)
267 {
268         size_t i = 0;
269         char *_buf = (char *)buf;
270         int c;
271
272         while (i < size)
273         {
274                 if ((c = ser_getchar(port)) == EOF)
275                         return EOF;
276                 _buf[i++] = c;
277         }
278
279         return i;
280 }
281
282
283 /**
284  * Write a string to serial.
285  * \return 0 if OK, EOF in case of error.
286  */
287 int ser_print(struct Serial *port, const char *s)
288 {
289         while (*s)
290         {
291                 if (ser_putchar(*s++, port) == EOF)
292                         return EOF;
293         }
294         return 0;
295 }
296
297
298 /**
299  * \brief Write a buffer to serial.
300  *
301  * \return 0 if OK, EOF in case of error.
302  *
303  * \todo Optimize with fifo_pushblock()
304  */
305 int ser_write(struct Serial *port, const void *_buf, size_t len)
306 {
307         const char *buf = (const char *)_buf;
308
309         while (len--)
310         {
311                 if (ser_putchar(*buf++, port) == EOF)
312                         return EOF;
313         }
314         return 0;
315 }
316
317
318 #if CONFIG_PRINTF
319 /**
320  * Formatted write
321  */
322 int ser_printf(struct Serial *port, const char *format, ...)
323 {
324         va_list ap;
325         int len;
326
327         va_start(ap, format);
328         len = _formatted_write(format, (void (*)(char, void *))ser_putchar, port, ap);
329         va_end(ap);
330
331         return len;
332 }
333 #endif /* CONFIG_PRINTF */
334
335
336 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
337 void ser_settimeouts(struct Serial *port, mtime_t rxtimeout, mtime_t txtimeout)
338 {
339         port->rxtimeout = ms_to_ticks(rxtimeout);
340         port->txtimeout = ms_to_ticks(txtimeout);
341 }
342 #endif /* CONFIG_SER_RXTIMEOUT || CONFIG_SER_TXTIMEOUT */
343
344 #if CONFIG_SER_RXTIMEOUT != -1
345 /**
346  * Discard input to resynchronize with remote end.
347  *
348  * Discard incoming data until the port stops receiving
349  * characters for at least \a delay milliseconds.
350  *
351  * \note Serial errors are reset before and after executing the purge.
352  */
353 void ser_resync(struct Serial *port, mtime_t delay)
354 {
355         mtime_t old_rxtimeout = ticks_to_ms(port->rxtimeout);
356
357         ser_settimeouts(port, delay, ticks_to_ms(port->txtimeout));
358         do
359         {
360                 ser_setstatus(port, 0);
361                 ser_getchar(port);
362         }
363         while (!(ser_getstatus(port) & SERRF_RXTIMEOUT));
364
365         /* Restore port to an usable status */
366         ser_setstatus(port, 0);
367         ser_settimeouts(port, old_rxtimeout, ticks_to_ms(port->txtimeout));
368 }
369 #endif /* CONFIG_SER_RXTIMEOUT */
370
371
372 void ser_setbaudrate(struct Serial *port, unsigned long rate)
373 {
374         port->hw->table->setBaudrate(port->hw, rate);
375 }
376
377
378 void ser_setparity(struct Serial *port, int parity)
379 {
380         port->hw->table->setParity(port->hw, parity);
381 }
382
383
384 /**
385  * Flush both the RX and TX buffers.
386  */
387 void ser_purge(struct Serial *port)
388 {
389         fifo_flush_locked(&port->rxfifo);
390         fifo_flush_locked(&port->txfifo);
391 }
392
393
394 /**
395  * Wait until all pending output is completely
396  * transmitted to the other end.
397  *
398  * \note The current implementation only checks the
399  *       software transmission queue. Any hardware
400  *       FIFOs are ignored.
401  */
402 void ser_drain(struct Serial *ser)
403 {
404         /*
405          * Wait until the FIFO becomes empty, and then until the byte currently in
406          * the hardware register gets shifted out.
407          */
408         while (!fifo_isempty(&ser->txfifo)
409                || ser->hw->table->txSending(ser->hw))
410         {
411                 #if CONFIG_KERNEL && CONFIG_KERN_SCHED
412                         /* Give up timeslice to other processes. */
413                         proc_switch();
414                 #endif
415                         wdt_reset();
416         }
417 }
418
419
420 /**
421  * Initialize a serial port.
422  *
423  * \param unit  Serial unit to open. Possible values are architecture dependant.
424  */
425 struct Serial *ser_open(unsigned int unit)
426 {
427         struct Serial *port;
428
429         ASSERT(unit < countof(ser_handles));
430         port = &ser_handles[unit];
431
432         ASSERT(!port->is_open);
433         DB(port->is_open = true;)
434
435         port->unit = unit;
436
437         port->hw = ser_hw_getdesc(unit);
438
439         /* Initialize circular buffers */
440         ASSERT(port->hw->txbuffer);
441         ASSERT(port->hw->rxbuffer);
442         fifo_init(&port->txfifo, port->hw->txbuffer, port->hw->txbuffer_size);
443         fifo_init(&port->rxfifo, port->hw->rxbuffer, port->hw->rxbuffer_size);
444
445         port->hw->table->init(port->hw, port);
446
447         /* Set default values */
448 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
449         ser_settimeouts(port, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
450 #endif
451 #if CONFIG_SER_DEFBAUDRATE
452         ser_setbaudrate(port, CONFIG_SER_DEFBAUDRATE);
453 #endif
454
455         /* Clear error flags */
456         ser_setstatus(port, 0);
457
458         return port;
459 }
460
461
462 /**
463  * Clean up serial port, disabling the associated hardware.
464  */
465 void ser_close(struct Serial *port)
466 {
467         ASSERT(port->is_open);
468         DB(port->is_open = false;)
469
470         // Wait until we finish sending everything
471         ser_drain(port);
472
473         port->hw->table->cleanup(port->hw);
474         DB(port->hw = NULL;)
475
476         /*
477          * We purge the FIFO buffer only after the low-level cleanup, so that
478          * we are sure that there are no more interrupts.
479          */
480         ser_purge(port);
481 }