BeRTOS
ser.c
Go to the documentation of this file.
00001 
00052 #include "ser.h"
00053 #include "wdt.h"
00054 #include "timer.h"
00055 #include "ser_p.h"
00056 
00057 #include "cfg/cfg_ser.h"
00058 #include "cfg/cfg_proc.h"
00059 #include <cfg/debug.h>
00060 
00061 #include <mware/formatwr.h>
00062 
00063 #include <cpu/power.h> /* cpu_relax() */
00064 
00065 #include <string.h> /* memset() */
00066 
00067 /*
00068  * Sanity check for config parameters required by this module.
00069  */
00070 #if !defined(CONFIG_KERN) || ((CONFIG_KERN != 0) && CONFIG_KERN != 1)
00071     #error CONFIG_KERN must be set to either 0 or 1 in cfg_kern.h
00072 #endif
00073 #if !defined(CONFIG_SER_RXTIMEOUT)
00074     #error CONFIG_SER_TXTIMEOUT missing in cfg_ser.h
00075 #endif
00076 #if !defined(CONFIG_SER_RXTIMEOUT)
00077     #error CONFIG_SER_RXTIMEOUT missing in cfg_ser.h
00078 #endif
00079 #if !defined(CONFIG_SER_DEFBAUDRATE)
00080     #error CONFIG_SER_DEFBAUDRATE missing in cfg_ser.h
00081 #endif
00082 
00083 
00084 struct Serial *ser_handles[SER_CNT];
00085 
00094 static int ser_putchar(int c, struct Serial *port)
00095 {
00096     if (fifo_isfull_locked(&port->txfifo))
00097     {
00098 #if CONFIG_SER_TXTIMEOUT != -1
00099         /* If timeout == 0 we don't want to wait */
00100         if (port->txtimeout == 0)
00101             return EOF;
00102 
00103         ticks_t start_time = timer_clock();
00104 #endif
00105 
00106         /* Wait while buffer is full... */
00107         do
00108         {
00109             cpu_relax();
00110 
00111 #if CONFIG_SER_TXTIMEOUT != -1
00112             if (timer_clock() - start_time >= port->txtimeout)
00113             {
00114                 ATOMIC(port->status |= SERRF_TXTIMEOUT);
00115                 return EOF;
00116             }
00117 #endif /* CONFIG_SER_TXTIMEOUT */
00118         }
00119         while (fifo_isfull_locked(&port->txfifo));
00120     }
00121 
00122     fifo_push_locked(&port->txfifo, (unsigned char)c);
00123 
00124     /* (re)trigger tx interrupt */
00125     port->hw->table->txStart(port->hw);
00126 
00127     /* Avoid returning signed extended char */
00128     return (int)((unsigned char)c);
00129 }
00130 
00131 
00140 static int ser_getchar(struct Serial *port)
00141 {
00142     if (fifo_isempty_locked(&port->rxfifo))
00143     {
00144 #if CONFIG_SER_RXTIMEOUT != -1
00145         /* If timeout == 0 we don't want to wait for chars */
00146         if (port->rxtimeout == 0)
00147             return EOF;
00148 
00149         ticks_t start_time = timer_clock();
00150 #endif
00151 
00152         /* Wait while buffer is empty */
00153         do
00154         {
00155             cpu_relax();
00156 
00157 #if CONFIG_SER_RXTIMEOUT != -1
00158             if (timer_clock() - start_time >= port->rxtimeout)
00159             {
00160                 ATOMIC(port->status |= SERRF_RXTIMEOUT);
00161                 return EOF;
00162             }
00163 #endif /* CONFIG_SER_RXTIMEOUT */
00164         }
00165         while (fifo_isempty_locked(&port->rxfifo) && (ser_getstatus(port) & SERRF_RX) == 0);
00166     }
00167 
00168     /*
00169      * Get a byte from the FIFO (avoiding sign-extension),
00170      * re-enable RTS, then return result.
00171      */
00172     if (ser_getstatus(port) & SERRF_RX)
00173         return EOF;
00174     return (int)(unsigned char)fifo_pop_locked(&port->rxfifo);
00175 }
00176 
00183 int ser_getchar_nowait(struct Serial *fd)
00184 {
00185     if (fifo_isempty_locked(&fd->rxfifo))
00186         return EOF;
00187 
00188     /* NOTE: the double cast prevents unwanted sign extension */
00189     return (int)(unsigned char)fifo_pop_locked(&fd->rxfifo);
00190 }
00191 
00192 
00193 
00199 static size_t ser_read(struct KFile *fd, void *_buf, size_t size)
00200 {
00201     Serial *fds = SERIAL_CAST(fd);
00202 
00203     size_t i = 0;
00204     char *buf = (char *)_buf;
00205     int c;
00206 
00207     while (i < size)
00208     {
00209         if ((c = ser_getchar(fds)) == EOF)
00210             break;
00211         buf[i++] = c;
00212     }
00213 
00214     return i;
00215 }
00216 
00224 static size_t ser_write(struct KFile *fd, const void *_buf, size_t size)
00225 {
00226     Serial *fds = SERIAL_CAST(fd);
00227     const char *buf = (const char *)_buf;
00228     size_t i = 0;
00229 
00230     while (size--)
00231     {
00232         if (ser_putchar(*buf++, fds) == EOF)
00233             break;
00234         i++;
00235     }
00236     return i;
00237 }
00238 
00239 
00240 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
00241 void ser_settimeouts(struct Serial *fd, mtime_t rxtimeout, mtime_t txtimeout)
00242 {
00243     #if CONFIG_SER_RXTIMEOUT != -1
00244         fd->rxtimeout = ms_to_ticks(rxtimeout);
00245     #else
00246         (void)rxtimeout;
00247     #endif
00248 
00249     #if CONFIG_SER_TXTIMEOUT != -1
00250         fd->txtimeout = ms_to_ticks(txtimeout);
00251     #else
00252         (void)txtimeout;
00253     #endif
00254 }
00255 #endif /* CONFIG_SER_RXTIMEOUT || CONFIG_SER_TXTIMEOUT */
00256 
00257 
00261 void ser_setbaudrate(struct Serial *fd, unsigned long rate)
00262 {
00263     fd->hw->table->setBaudrate(fd->hw, rate);
00264 }
00265 
00266 
00270 void ser_setparity(struct Serial *fd, int parity)
00271 {
00272     fd->hw->table->setParity(fd->hw, parity);
00273 }
00274 
00275 static int ser_error(struct KFile *fd)
00276 {
00277     Serial *fds = SERIAL_CAST(fd);
00278     return ser_getstatus(fds);
00279 }
00280 
00281 static void ser_clearerr(struct KFile *fd)
00282 {
00283     Serial *fds = SERIAL_CAST(fd);
00284     ser_setstatus(fds, 0);
00285 }
00286 
00287 
00288 
00292 void ser_purge(struct Serial *fd)
00293 {
00294     ser_purgeRx(fd);
00295     ser_purgeTx(fd);
00296 }
00297 
00301 void ser_purgeRx(struct Serial *fd)
00302 {
00303     fifo_flush_locked(&fd->rxfifo);
00304 }
00305 
00309 void ser_purgeTx(struct Serial *fd)
00310 {
00311     fifo_flush_locked(&fd->txfifo);
00312 }
00313 
00314 
00323 static int ser_flush(struct KFile *fd)
00324 {
00325     Serial *fds = SERIAL_CAST(fd);
00326 
00327     /*
00328      * Wait until the FIFO becomes empty, and then until the byte currently in
00329      * the hardware register gets shifted out.
00330      */
00331     while (!fifo_isempty(&fds->txfifo)
00332            || fds->hw->table->txSending(fds->hw))
00333         cpu_relax();
00334     return 0;
00335 }
00336 
00337 
00344 static struct Serial *ser_open(struct Serial *fd, unsigned int unit)
00345 {
00346     ASSERT(unit < countof(ser_handles));
00347 
00348     ser_handles[unit] = fd;
00349     ASSERT(!fd->is_open);
00350     DB(fd->is_open = true);
00351 
00352     fd->unit = unit;
00353 
00354     fd->hw = ser_hw_getdesc(unit);
00355 
00356     /* Initialize circular buffers */
00357     ASSERT(fd->hw->txbuffer);
00358     ASSERT(fd->hw->rxbuffer);
00359     fifo_init(&fd->txfifo, fd->hw->txbuffer, fd->hw->txbuffer_size);
00360     fifo_init(&fd->rxfifo, fd->hw->rxbuffer, fd->hw->rxbuffer_size);
00361 
00362     fd->hw->table->init(fd->hw, fd);
00363 
00364     /* Set default values */
00365 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
00366     ser_settimeouts(fd, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
00367 #endif
00368 #if CONFIG_SER_DEFBAUDRATE
00369     ser_setbaudrate(fd, CONFIG_SER_DEFBAUDRATE);
00370 #endif
00371 
00372     /* Clear error flags */
00373     ser_setstatus(fd, 0);
00374 
00375     return fd;
00376 }
00377 
00378 
00382 static int ser_close(struct KFile *fd)
00383 {
00384     Serial *fds = SERIAL_CAST(fd);
00385     Serial *port = fds;
00386 
00387     ASSERT(port->is_open);
00388     DB(port->is_open = false);
00389 
00390     // Wait until we finish sending everything
00391     ser_flush(fd);
00392 
00393     port->hw->table->cleanup(port->hw);
00394     DB(port->hw = NULL);
00395 
00396     /*
00397      * We purge the FIFO buffer only after the low-level cleanup, so that
00398      * we are sure that there are no more interrupts.
00399      */
00400     ser_purge(fds);
00401     return 0;
00402 }
00403 
00407 static struct KFile *ser_reopen(struct KFile *fd)
00408 {
00409     Serial *fds = SERIAL_CAST(fd);
00410 
00411     ser_close(fd);
00412     ser_open(fds, fds->unit);
00413     return (KFile *)fds;
00414 }
00415 
00421 void ser_init(struct Serial *fds, unsigned int unit)
00422 {
00423     memset(fds, 0, sizeof(*fds));
00424 
00425     DB(fds->fd._type = KFT_SERIAL);
00426     fds->fd.reopen = ser_reopen;
00427     fds->fd.close = ser_close;
00428     fds->fd.read = ser_read;
00429     fds->fd.write = ser_write;
00430     fds->fd.flush = ser_flush;
00431     fds->fd.error = ser_error;
00432     fds->fd.clearerr = ser_clearerr;
00433     ser_open(fds, unit);
00434 }
00435 
00436 
00442 static size_t spimaster_read(struct KFile *fd, void *_buf, size_t size)
00443 {
00444     Serial *fd_spi = SERIAL_CAST(fd);
00445 
00446     ser_flush(&fd_spi->fd);
00447     ser_purgeRx(fd_spi);
00448 
00449     size_t total_rd = 0;
00450     uint8_t *buf = (uint8_t *)_buf;
00451     int c;
00452 
00453     while (size--)
00454     {
00455         /*
00456          * Send and receive chars 1 by 1, otherwise the rxfifo
00457          * will overrun.
00458          */
00459         ser_putchar(0, fd_spi);
00460 
00461         if ((c = ser_getchar(fd_spi)) == EOF)
00462             break;
00463 
00464         *buf++ = c;
00465         total_rd++;
00466     }
00467     return total_rd;
00468 }
00469 
00473 static size_t spimaster_write(struct KFile *fd, const void *buf, size_t size)
00474 {
00475     Serial *fd_spi = SERIAL_CAST(fd);
00476 
00477     ser_purgeRx(fd_spi);
00478 
00479     return ser_write(&fd_spi->fd, buf, size);
00480 }
00481 
00482 
00496 void spimaster_init(Serial *fds, unsigned int unit)
00497 {
00498     ser_init(fds, unit);
00499     fds->fd.read = spimaster_read;
00500     fds->fd.write = spimaster_write;
00501 }
00502 
00503