ser.c

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