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