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 
00259 void ser_setbaudrate(struct Serial *fd, unsigned long rate)
00260 {
00261     fd->hw->table->setBaudrate(fd->hw, rate);
00262 }
00263 
00264 
00265 void ser_setparity(struct Serial *fd, int parity)
00266 {
00267     fd->hw->table->setParity(fd->hw, parity);
00268 }
00269 
00270 static int ser_error(struct KFile *fd)
00271 {
00272     Serial *fds = SERIAL_CAST(fd);
00273     return ser_getstatus(fds);
00274 }
00275 
00276 static void ser_clearerr(struct KFile *fd)
00277 {
00278     Serial *fds = SERIAL_CAST(fd);
00279     ser_setstatus(fds, 0);
00280 }
00281 
00282 
00283 
00287 void ser_purge(struct Serial *fd)
00288 {
00289     ser_purgeRx(fd);
00290     ser_purgeTx(fd);
00291 }
00292 
00296 void ser_purgeRx(struct Serial *fd)
00297 {
00298     fifo_flush_locked(&fd->rxfifo);
00299 }
00300 
00304 void ser_purgeTx(struct Serial *fd)
00305 {
00306     fifo_flush_locked(&fd->txfifo);
00307 }
00308 
00309 
00318 static int ser_flush(struct KFile *fd)
00319 {
00320     Serial *fds = SERIAL_CAST(fd);
00321 
00322     /*
00323      * Wait until the FIFO becomes empty, and then until the byte currently in
00324      * the hardware register gets shifted out.
00325      */
00326     while (!fifo_isempty(&fds->txfifo)
00327            || fds->hw->table->txSending(fds->hw))
00328         cpu_relax();
00329     return 0;
00330 }
00331 
00332 
00339 static struct Serial *ser_open(struct Serial *fd, unsigned int unit)
00340 {
00341     ASSERT(unit < countof(ser_handles));
00342 
00343     ser_handles[unit] = fd;
00344     ASSERT(!fd->is_open);
00345     DB(fd->is_open = true);
00346 
00347     fd->unit = unit;
00348 
00349     fd->hw = ser_hw_getdesc(unit);
00350 
00351     /* Initialize circular buffers */
00352     ASSERT(fd->hw->txbuffer);
00353     ASSERT(fd->hw->rxbuffer);
00354     fifo_init(&fd->txfifo, fd->hw->txbuffer, fd->hw->txbuffer_size);
00355     fifo_init(&fd->rxfifo, fd->hw->rxbuffer, fd->hw->rxbuffer_size);
00356 
00357     fd->hw->table->init(fd->hw, fd);
00358 
00359     /* Set default values */
00360 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
00361     ser_settimeouts(fd, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
00362 #endif
00363 #if CONFIG_SER_DEFBAUDRATE
00364     ser_setbaudrate(fd, CONFIG_SER_DEFBAUDRATE);
00365 #endif
00366 
00367     /* Clear error flags */
00368     ser_setstatus(fd, 0);
00369 
00370     return fd;
00371 }
00372 
00373 
00377 static int ser_close(struct KFile *fd)
00378 {
00379     Serial *fds = SERIAL_CAST(fd);
00380     Serial *port = fds;
00381 
00382     ASSERT(port->is_open);
00383     DB(port->is_open = false);
00384 
00385     // Wait until we finish sending everything
00386     ser_flush(fd);
00387 
00388     port->hw->table->cleanup(port->hw);
00389     DB(port->hw = NULL);
00390 
00391     /*
00392      * We purge the FIFO buffer only after the low-level cleanup, so that
00393      * we are sure that there are no more interrupts.
00394      */
00395     ser_purge(fds);
00396     return 0;
00397 }
00398 
00402 static struct KFile *ser_reopen(struct KFile *fd)
00403 {
00404     Serial *fds = SERIAL_CAST(fd);
00405 
00406     ser_close(fd);
00407     ser_open(fds, fds->unit);
00408     return (KFile *)fds;
00409 }
00410 
00416 void ser_init(struct Serial *fds, unsigned int unit)
00417 {
00418     memset(fds, 0, sizeof(*fds));
00419 
00420     DB(fds->fd._type = KFT_SERIAL);
00421     fds->fd.reopen = ser_reopen;
00422     fds->fd.close = ser_close;
00423     fds->fd.read = ser_read;
00424     fds->fd.write = ser_write;
00425     fds->fd.flush = ser_flush;
00426     fds->fd.error = ser_error;
00427     fds->fd.clearerr = ser_clearerr;
00428     ser_open(fds, unit);
00429 }
00430 
00431 
00437 static size_t spimaster_read(struct KFile *fd, void *_buf, size_t size)
00438 {
00439     Serial *fd_spi = SERIAL_CAST(fd);
00440 
00441     ser_flush(&fd_spi->fd);
00442     ser_purgeRx(fd_spi);
00443 
00444     size_t total_rd = 0;
00445     uint8_t *buf = (uint8_t *)_buf;
00446     int c;
00447 
00448     while (size--)
00449     {
00450         /*
00451          * Send and receive chars 1 by 1, otherwise the rxfifo
00452          * will overrun.
00453          */
00454         ser_putchar(0, fd_spi);
00455 
00456         if ((c = ser_getchar(fd_spi)) == EOF)
00457             break;
00458 
00459         *buf++ = c;
00460         total_rd++;
00461     }
00462     return total_rd;
00463 }
00464 
00468 static size_t spimaster_write(struct KFile *fd, const void *buf, size_t size)
00469 {
00470     Serial *fd_spi = SERIAL_CAST(fd);
00471 
00472     ser_purgeRx(fd_spi);
00473 
00474     return ser_write(&fd_spi->fd, buf, size);
00475 }
00476 
00477 
00491 void spimaster_init(Serial *fds, unsigned int unit)
00492 {
00493     ser_init(fds, unit);
00494     fds->fd.read = spimaster_read;
00495     fds->fd.write = spimaster_write;
00496 }
00497 
00498