Fix doxygen warning.
[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 #include "wdt.h"
56 #include "ser_p.h"
57 #include <mware/formatwr.h>
58 #include <cfg/debug.h>
59 #include <appconfig.h>
60
61 #include <string.h> /* memset */
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_DEFBAUDRATE)
76         #error CONFIG_SER_DEFBAUDRATE missing in config.h
77 #endif
78
79 #if CONFIG_KERNEL
80         #include <kern/proc.h>
81 #endif
82
83 #if CONFIG_SER_TXTIMEOUT != -1 || CONFIG_SER_RXTIMEOUT != -1
84         #include <drv/timer.h>
85 #endif
86
87
88 /* Serial configuration parameters */
89 #define SER_CTSDELAY        70  /**< CTS line retry interval (ms) */
90 #define SER_TXPOLLDELAY      2  /**< Transmit buffer full retry interval (ms) */
91 #define SER_RXPOLLDELAY      2  /**< Receive buffer empty retry interval (ms) */
92
93
94 struct Serial ser_handles[SER_CNT];
95
96
97 /**
98  * Inserisce il carattere c nel buffer di trasmissione.
99  * Questa funzione mette il processo chiamante in attesa
100  * quando il buffer e' pieno.
101  *
102  * \return EOF in caso di errore o timeout, altrimenti
103  *         il carattere inviato.
104  */
105 static int ser_putchar(int c, struct Serial *port)
106 {
107         //ASSERT_VALID_FIFO(&port->txfifo);
108         if (fifo_isfull_locked(&port->txfifo))
109         {
110 #if CONFIG_SER_TXTIMEOUT != -1
111                 ticks_t start_time = timer_clock();
112 #endif
113
114                 /* Attende finche' il buffer e' pieno... */
115                 do
116                 {
117                         wdt_reset();
118 #if CONFIG_KERNEL && CONFIG_KERN_SCHED
119                         /* Give up timeslice to other processes. */
120                         proc_switch();
121 #endif
122 #if CONFIG_SER_TXTIMEOUT != -1
123                         if (timer_clock() - start_time >= port->txtimeout)
124                         {
125                                 ATOMIC(port->status |= SERRF_TXTIMEOUT);
126                                 return EOF;
127                         }
128 #endif /* CONFIG_SER_TXTIMEOUT */
129                 }
130                 while (fifo_isfull_locked(&port->txfifo));
131         }
132
133         fifo_push_locked(&port->txfifo, (unsigned char)c);
134
135         /* (re)trigger tx interrupt */
136         port->hw->table->txStart(port->hw);
137
138         /* Avoid returning signed extended char */
139         return (int)((unsigned char)c);
140 }
141
142
143 /**
144  * Preleva un carattere dal buffer di ricezione.
145  * Questa funzione mette il processo chiamante in attesa
146  * quando il buffer e' vuoto. L'attesa ha un timeout
147  * di ser_rxtimeout millisecondi.
148  *
149  * \return EOF in caso di errore o timeout, altrimenti
150  *         il carattere ricevuto.
151  */
152 static int ser_getchar(struct Serial *port)
153 {
154         if (fifo_isempty_locked(&port->rxfifo))
155         {
156 #if CONFIG_SER_RXTIMEOUT != -1
157                 ticks_t start_time = timer_clock();
158 #endif
159                 /* Wait while buffer is empty */
160                 do
161                 {
162                         wdt_reset();
163 #if CONFIG_KERNEL && CONFIG_KERN_SCHED
164                         /* Give up timeslice to other processes. */
165                         proc_switch();
166 #endif
167 #if CONFIG_SER_RXTIMEOUT != -1
168                         if (timer_clock() - start_time >= port->rxtimeout)
169                         {
170                                 ATOMIC(port->status |= SERRF_RXTIMEOUT);
171                                 return EOF;
172                         }
173 #endif /* CONFIG_SER_RXTIMEOUT */
174                 }
175                 while (fifo_isempty_locked(&port->rxfifo) && (ser_getstatus(port) & SERRF_RX) == 0);
176         }
177
178         /*
179          * Get a byte from the FIFO (avoiding sign-extension),
180          * re-enable RTS, then return result.
181          */
182         if (ser_getstatus(port) & SERRF_RX)
183                 return EOF;
184         return (int)(unsigned char)fifo_pop_locked(&port->rxfifo);
185 }
186
187 /**
188  * Preleva un carattere dal buffer di ricezione.
189  * Se il buffer e' vuoto, ser_getchar_nowait() ritorna
190  * immediatamente EOF.
191  */
192 int ser_getchar_nowait(struct KFileSerial *fd)
193 {
194         if (fifo_isempty_locked(&fd->ser->rxfifo))
195                 return EOF;
196
197         /* NOTE: the double cast prevents unwanted sign extension */
198         return (int)(unsigned char)fifo_pop_locked(&fd->ser->rxfifo);
199 }
200
201
202 /**
203  * Read at most \a size bytes from \a port and put them in \a buf
204  *
205  * \return number of bytes actually read.
206  */
207 static size_t ser_read(struct KFile *fd, void *_buf, size_t size)
208 {
209         KFileSerial *fds = KFILESERIAL(fd);
210
211         size_t i = 0;
212         char *buf = (char *)_buf;
213         int c;
214
215         while (i < size)
216         {
217                 if ((c = ser_getchar(fds->ser)) == EOF)
218                         break;
219                 buf[i++] = c;
220         }
221
222         return i;
223 }
224
225 /**
226  * \brief Write a buffer to serial.
227  *
228  * \return 0 if OK, EOF in case of error.
229  *
230  * \todo Optimize with fifo_pushblock()
231  */
232 static size_t ser_write(struct KFile *fd, const void *_buf, size_t size)
233 {
234         KFileSerial *fds = KFILESERIAL(fd);
235         const char *buf = (const char *)_buf;
236         size_t i = 0;
237
238         while (size--)
239         {
240                 if (ser_putchar(*buf++, fds->ser) == EOF)
241                         break;
242                 i++;
243         }
244         return i;
245 }
246
247
248 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
249 void ser_settimeouts(struct KFileSerial *fd, mtime_t rxtimeout, mtime_t txtimeout)
250 {
251         fd->ser->rxtimeout = ms_to_ticks(rxtimeout);
252         fd->ser->txtimeout = ms_to_ticks(txtimeout);
253 }
254 #endif /* CONFIG_SER_RXTIMEOUT || CONFIG_SER_TXTIMEOUT */
255
256 #if CONFIG_SER_RXTIMEOUT != -1
257 /**
258  * Discard input to resynchronize with remote end.
259  *
260  * Discard incoming data until the port stops receiving
261  * characters for at least \a delay milliseconds.
262  *
263  * \note Serial errors are reset before and after executing the purge.
264  */
265 void ser_resync(struct KFileSerial *fd, mtime_t delay)
266 {
267         mtime_t old_rxtimeout = ticks_to_ms(fd->ser->rxtimeout);
268
269         ser_settimeouts(fd, delay, ticks_to_ms(fd->ser->txtimeout));
270         do
271         {
272                 ser_setstatus(fd->ser, 0);
273                 ser_getchar(fd->ser);
274         }
275         while (!(ser_getstatus(fd->ser) & SERRF_RXTIMEOUT));
276
277         /* Restore port to an usable status */
278         ser_setstatus(fd->ser, 0);
279         ser_settimeouts(fd, old_rxtimeout, ticks_to_ms(fd->ser->txtimeout));
280 }
281 #endif /* CONFIG_SER_RXTIMEOUT */
282
283
284 void ser_setbaudrate(struct KFileSerial *fd, unsigned long rate)
285 {
286         fd->ser->hw->table->setBaudrate(fd->ser->hw, rate);
287 }
288
289
290 void ser_setparity(struct KFileSerial *fd, int parity)
291 {
292         fd->ser->hw->table->setParity(fd->ser->hw, parity);
293 }
294
295 static int ser_error(struct KFile *fd)
296 {
297         KFileSerial *fds = KFILESERIAL(fd);
298         return ser_getstatus(fds->ser);
299 }
300
301 static void ser_clearerr(struct KFile *fd)
302 {
303         KFileSerial *fds = KFILESERIAL(fd);
304         ser_setstatus(fds->ser, 0);
305 }
306
307
308
309 /**
310  * Flush both the RX and TX buffers.
311  */
312 void ser_purge(struct KFileSerial *fd)
313 {
314         ser_purgeRx(fd);
315         ser_purgeTx(fd);
316 }
317
318 /**
319  * Flush RX buffer.
320  */
321 void ser_purgeRx(struct KFileSerial *fd)
322 {
323         fifo_flush_locked(&fd->ser->rxfifo);
324 }
325
326 /**
327  * Flush TX buffer.
328  */
329 void ser_purgeTx(struct KFileSerial *fd)
330 {
331         fifo_flush_locked(&fd->ser->txfifo);
332 }
333
334
335 /**
336  * Wait until all pending output is completely
337  * transmitted to the other end.
338  *
339  * \note The current implementation only checks the
340  *       software transmission queue. Any hardware
341  *       FIFOs are ignored.
342  */
343 static int ser_flush(struct KFile *fd)
344 {
345         KFileSerial *fds = KFILESERIAL(fd);
346
347         /*
348          * Wait until the FIFO becomes empty, and then until the byte currently in
349          * the hardware register gets shifted out.
350          */
351         while (!fifo_isempty(&fds->ser->txfifo)
352                || fds->ser->hw->table->txSending(fds->ser->hw))
353         {
354                 #if CONFIG_KERNEL && CONFIG_KERN_SCHED
355                         /* Give up timeslice to other processes. */
356                         proc_switch();
357                 #endif
358                         wdt_reset();
359         }
360         return 0;
361 }
362
363
364 /**
365  * Initialize a serial port.
366  *
367  * \param fd KFile Serial struct interface.
368  * \param unit  Serial unit to open. Possible values are architecture dependant.
369  */
370 static struct Serial *ser_open(struct KFileSerial *fd, unsigned int unit)
371 {
372         struct Serial *port;
373
374         ASSERT(unit < countof(ser_handles));
375         port = &ser_handles[unit];
376
377         ASSERT(!port->is_open);
378         DB(port->is_open = true);
379
380         port->unit = unit;
381
382         port->hw = ser_hw_getdesc(unit);
383
384         /* Initialize circular buffers */
385         ASSERT(port->hw->txbuffer);
386         ASSERT(port->hw->rxbuffer);
387         fifo_init(&port->txfifo, port->hw->txbuffer, port->hw->txbuffer_size);
388         fifo_init(&port->rxfifo, port->hw->rxbuffer, port->hw->rxbuffer_size);
389
390         port->hw->table->init(port->hw, port);
391
392         fd->ser = port;
393         /* Set default values */
394 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
395         ser_settimeouts(fd, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
396 #endif
397 #if CONFIG_SER_DEFBAUDRATE
398         ser_setbaudrate(fd, CONFIG_SER_DEFBAUDRATE);
399 #endif
400
401         /* Clear error flags */
402         ser_setstatus(port, 0);
403
404         return port;
405 }
406
407
408 /**
409  * Clean up serial port, disabling the associated hardware.
410  */
411 static int ser_close(struct KFile *fd)
412 {
413         KFileSerial *fds = KFILESERIAL(fd);
414         Serial *port = fds->ser;
415
416         ASSERT(port->is_open);
417         DB(port->is_open = false);
418
419         // Wait until we finish sending everything
420         ser_flush(fd);
421
422         port->hw->table->cleanup(port->hw);
423         DB(port->hw = NULL);
424
425         /*
426          * We purge the FIFO buffer only after the low-level cleanup, so that
427          * we are sure that there are no more interrupts.
428          */
429         ser_purge(fds);
430         return 0;
431 }
432
433 /**
434  * Reopen serial port.
435  */
436 static struct KFile *ser_reopen(struct KFile *fd)
437 {
438         KFileSerial *fds = KFILESERIAL(fd);
439
440         ser_close(fd);
441         ser_open(fds, fds->ser->unit);
442         return (KFile *)fds;
443 }
444
445 /**
446  * Init serial driver for \a unit.
447  */
448 void ser_init(struct KFileSerial *fds, unsigned int unit)
449 {
450         memset(fds, 0, sizeof(*fds));
451
452         DB(fds->fd._type = KFT_SERIAL);
453         fds->fd.reopen = ser_reopen;
454         fds->fd.close = ser_close;
455         fds->fd.read = ser_read;
456         fds->fd.write = ser_write;
457         fds->fd.flush = ser_flush;
458         fds->fd.error = ser_error;
459         fds->fd.clearerr = ser_clearerr;
460         ser_open(fds, unit);
461 }
462
463
464 /**
465  * Read data from SPI bus.
466  * Since we are master, we have to trigger slave by sending
467  * fake chars on the bus.
468  */
469 static size_t spimaster_read(struct KFile *fd, void *_buf, size_t size)
470 {
471         KFileSerial *fd_spi = KFILESERIAL(fd);
472
473         ser_flush(&fd_spi->fd);
474         ser_purgeRx(fd_spi);
475
476         size_t total_rd = 0;
477         uint8_t *buf = (uint8_t *)_buf;
478         int c;
479
480         while (size--)
481         {
482                 /*
483                  * Send and receive chars 1 by 1, otherwise the rxfifo
484                  * will overrun.
485                  */
486                 ser_putchar(0, fd_spi->ser);
487
488                 if ((c = ser_getchar(fd_spi->ser)) == EOF)
489                         break;
490
491                 *buf++ = c;
492                 total_rd++;
493         }
494         return total_rd;
495 }
496
497 /**
498  * Write data to SPI bus.
499  */
500 static size_t spimaster_write(struct KFile *fd, const void *buf, size_t size)
501 {
502         KFileSerial *fd_spi = KFILESERIAL(fd);
503
504         ser_purgeRx(fd_spi);
505
506         return ser_write(&fd_spi->fd, buf, size);
507 }
508
509
510 /**
511  * Init SPI serial driver \a unit in master mode.
512  *
513  * This interface implements the SPI master protocol over a serial SPI
514  * driver. This is needed because normal serial driver send/receive data
515  * at the same time. SPI slaves like memories and other peripherals
516  * first receive and *then* send response back instead.
517  * To achieve this, when we are master and we are *sending*,
518  * we have to discard all incoming data. Then, when we want to
519  * receive, we must write fake data to SPI to trigger slave devices.
520  */
521 void spimaster_init(KFileSerial *fds, unsigned int unit)
522 {
523         ser_init(fds, unit);
524         fds->fd.read = spimaster_read;
525         fds->fd.write = spimaster_write;
526 }
527
528