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