00001
00054 #include "ser.h"
00055 #include "wdt.h"
00056 #include "ser_p.h"
00057 #include <mware/formatwr.h>
00058 #include <cfg/debug.h>
00059 #include <appconfig.h>
00060
00061 #include <string.h>
00062
00063
00064
00065
00066 #if !defined(CONFIG_KERNEL) || ((CONFIG_KERNEL != 0) && CONFIG_KERNEL != 1)
00067 #error CONFIG_KERNEL must be set to either 0 or 1 in config.h
00068 #endif
00069 #if !defined(CONFIG_SER_RXTIMEOUT)
00070 #error CONFIG_SER_TXTIMEOUT missing in config.h
00071 #endif
00072 #if !defined(CONFIG_SER_RXTIMEOUT)
00073 #error CONFIG_SER_RXTIMEOUT missing in config.h
00074 #endif
00075 #if !defined(CONFIG_SER_DEFBAUDRATE)
00076 #error CONFIG_SER_DEFBAUDRATE missing in config.h
00077 #endif
00078
00079 #if CONFIG_KERNEL
00080 #include <kern/proc.h>
00081 #endif
00082
00083 #if CONFIG_SER_TXTIMEOUT != -1 || CONFIG_SER_RXTIMEOUT != -1
00084 #include <drv/timer.h>
00085 #endif
00086
00087
00088 struct Serial ser_handles[SER_CNT];
00089
00098 static int ser_putchar(int c, struct Serial *port)
00099 {
00100 if (fifo_isfull_locked(&port->txfifo))
00101 {
00102 #if CONFIG_SER_TXTIMEOUT != -1
00103
00104 if (port->txtimeout == 0)
00105 return EOF;
00106
00107 ticks_t start_time = timer_clock();
00108 #endif
00109
00110
00111 do
00112 {
00113 wdt_reset();
00114 #if CONFIG_KERNEL && CONFIG_KERN_SCHED
00115
00116 proc_switch();
00117 #endif
00118 #if CONFIG_SER_TXTIMEOUT != -1
00119 if (timer_clock() - start_time >= port->txtimeout)
00120 {
00121 ATOMIC(port->status |= SERRF_TXTIMEOUT);
00122 return EOF;
00123 }
00124 #endif
00125 }
00126 while (fifo_isfull_locked(&port->txfifo));
00127 }
00128
00129 fifo_push_locked(&port->txfifo, (unsigned char)c);
00130
00131
00132 port->hw->table->txStart(port->hw);
00133
00134
00135 return (int)((unsigned char)c);
00136 }
00137
00138
00147 static int ser_getchar(struct Serial *port)
00148 {
00149 if (fifo_isempty_locked(&port->rxfifo))
00150 {
00151 #if CONFIG_SER_RXTIMEOUT != -1
00152
00153 if (port->rxtimeout == 0)
00154 return EOF;
00155
00156 ticks_t start_time = timer_clock();
00157 #endif
00158
00159 do
00160 {
00161 wdt_reset();
00162 #if CONFIG_KERNEL && CONFIG_KERN_SCHED
00163
00164 proc_switch();
00165 #endif
00166 #if CONFIG_SER_RXTIMEOUT != -1
00167 if (timer_clock() - start_time >= port->rxtimeout)
00168 {
00169 ATOMIC(port->status |= SERRF_RXTIMEOUT);
00170 return EOF;
00171 }
00172 #endif
00173 }
00174 while (fifo_isempty_locked(&port->rxfifo) && (ser_getstatus(port) & SERRF_RX) == 0);
00175 }
00176
00177
00178
00179
00180
00181 if (ser_getstatus(port) & SERRF_RX)
00182 return EOF;
00183 return (int)(unsigned char)fifo_pop_locked(&port->rxfifo);
00184 }
00185
00192 int ser_getchar_nowait(struct KFileSerial *fd)
00193 {
00194 if (fifo_isempty_locked(&fd->ser->rxfifo))
00195 return EOF;
00196
00197
00198 return (int)(unsigned char)fifo_pop_locked(&fd->ser->rxfifo);
00199 }
00200
00201
00202
00208 static size_t ser_read(struct KFile *fd, void *_buf, size_t size)
00209 {
00210 KFileSerial *fds = KFILESERIAL(fd);
00211
00212 size_t i = 0;
00213 char *buf = (char *)_buf;
00214 int c;
00215
00216 while (i < size)
00217 {
00218 if ((c = ser_getchar(fds->ser)) == EOF)
00219 break;
00220 buf[i++] = c;
00221 }
00222
00223 return i;
00224 }
00225
00233 static size_t ser_write(struct KFile *fd, const void *_buf, size_t size)
00234 {
00235 KFileSerial *fds = KFILESERIAL(fd);
00236 const char *buf = (const char *)_buf;
00237 size_t i = 0;
00238
00239 while (size--)
00240 {
00241 if (ser_putchar(*buf++, fds->ser) == EOF)
00242 break;
00243 i++;
00244 }
00245 return i;
00246 }
00247
00248
00249 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
00250 void ser_settimeouts(struct KFileSerial *fd, mtime_t rxtimeout, mtime_t txtimeout)
00251 {
00252 fd->ser->rxtimeout = ms_to_ticks(rxtimeout);
00253 fd->ser->txtimeout = ms_to_ticks(txtimeout);
00254 }
00255 #endif
00256
00257 #if CONFIG_SER_RXTIMEOUT != -1
00258
00266 void ser_resync(struct KFileSerial *fd, mtime_t delay)
00267 {
00268 mtime_t old_rxtimeout = ticks_to_ms(fd->ser->rxtimeout);
00269
00270 ser_settimeouts(fd, delay, ticks_to_ms(fd->ser->txtimeout));
00271 do
00272 {
00273 ser_setstatus(fd->ser, 0);
00274 ser_getchar(fd->ser);
00275 }
00276 while (!(ser_getstatus(fd->ser) & SERRF_RXTIMEOUT));
00277
00278
00279 ser_setstatus(fd->ser, 0);
00280 ser_settimeouts(fd, old_rxtimeout, ticks_to_ms(fd->ser->txtimeout));
00281 }
00282 #endif
00283
00284
00285 void ser_setbaudrate(struct KFileSerial *fd, unsigned long rate)
00286 {
00287 fd->ser->hw->table->setBaudrate(fd->ser->hw, rate);
00288 }
00289
00290
00291 void ser_setparity(struct KFileSerial *fd, int parity)
00292 {
00293 fd->ser->hw->table->setParity(fd->ser->hw, parity);
00294 }
00295
00296 static int ser_error(struct KFile *fd)
00297 {
00298 KFileSerial *fds = KFILESERIAL(fd);
00299 return ser_getstatus(fds->ser);
00300 }
00301
00302 static void ser_clearerr(struct KFile *fd)
00303 {
00304 KFileSerial *fds = KFILESERIAL(fd);
00305 ser_setstatus(fds->ser, 0);
00306 }
00307
00308
00309
00313 void ser_purge(struct KFileSerial *fd)
00314 {
00315 ser_purgeRx(fd);
00316 ser_purgeTx(fd);
00317 }
00318
00322 void ser_purgeRx(struct KFileSerial *fd)
00323 {
00324 fifo_flush_locked(&fd->ser->rxfifo);
00325 }
00326
00330 void ser_purgeTx(struct KFileSerial *fd)
00331 {
00332 fifo_flush_locked(&fd->ser->txfifo);
00333 }
00334
00335
00344 static int ser_flush(struct KFile *fd)
00345 {
00346 KFileSerial *fds = KFILESERIAL(fd);
00347
00348
00349
00350
00351
00352 while (!fifo_isempty(&fds->ser->txfifo)
00353 || fds->ser->hw->table->txSending(fds->ser->hw))
00354 {
00355 #if CONFIG_KERNEL && CONFIG_KERN_SCHED
00356
00357 proc_switch();
00358 #endif
00359 wdt_reset();
00360 }
00361 return 0;
00362 }
00363
00364
00371 static struct Serial *ser_open(struct KFileSerial *fd, unsigned int unit)
00372 {
00373 struct Serial *port;
00374
00375 ASSERT(unit < countof(ser_handles));
00376 port = &ser_handles[unit];
00377
00378 ASSERT(!port->is_open);
00379 DB(port->is_open = true);
00380
00381 port->unit = unit;
00382
00383 port->hw = ser_hw_getdesc(unit);
00384
00385
00386 ASSERT(port->hw->txbuffer);
00387 ASSERT(port->hw->rxbuffer);
00388 fifo_init(&port->txfifo, port->hw->txbuffer, port->hw->txbuffer_size);
00389 fifo_init(&port->rxfifo, port->hw->rxbuffer, port->hw->rxbuffer_size);
00390
00391 port->hw->table->init(port->hw, port);
00392
00393 fd->ser = port;
00394
00395 #if CONFIG_SER_RXTIMEOUT != -1 || CONFIG_SER_TXTIMEOUT != -1
00396 ser_settimeouts(fd, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
00397 #endif
00398 #if CONFIG_SER_DEFBAUDRATE
00399 ser_setbaudrate(fd, CONFIG_SER_DEFBAUDRATE);
00400 #endif
00401
00402
00403 ser_setstatus(port, 0);
00404
00405 return port;
00406 }
00407
00408
00412 static int ser_close(struct KFile *fd)
00413 {
00414 KFileSerial *fds = KFILESERIAL(fd);
00415 Serial *port = fds->ser;
00416
00417 ASSERT(port->is_open);
00418 DB(port->is_open = false);
00419
00420
00421 ser_flush(fd);
00422
00423 port->hw->table->cleanup(port->hw);
00424 DB(port->hw = NULL);
00425
00426
00427
00428
00429
00430 ser_purge(fds);
00431 return 0;
00432 }
00433
00437 static struct KFile *ser_reopen(struct KFile *fd)
00438 {
00439 KFileSerial *fds = KFILESERIAL(fd);
00440
00441 ser_close(fd);
00442 ser_open(fds, fds->ser->unit);
00443 return (KFile *)fds;
00444 }
00445
00449 void ser_init(struct KFileSerial *fds, unsigned int unit)
00450 {
00451 memset(fds, 0, sizeof(*fds));
00452
00453 DB(fds->fd._type = KFT_SERIAL);
00454 fds->fd.reopen = ser_reopen;
00455 fds->fd.close = ser_close;
00456 fds->fd.read = ser_read;
00457 fds->fd.write = ser_write;
00458 fds->fd.flush = ser_flush;
00459 fds->fd.error = ser_error;
00460 fds->fd.clearerr = ser_clearerr;
00461 ser_open(fds, unit);
00462 }
00463
00464
00470 static size_t spimaster_read(struct KFile *fd, void *_buf, size_t size)
00471 {
00472 KFileSerial *fd_spi = KFILESERIAL(fd);
00473
00474 ser_flush(&fd_spi->fd);
00475 ser_purgeRx(fd_spi);
00476
00477 size_t total_rd = 0;
00478 uint8_t *buf = (uint8_t *)_buf;
00479 int c;
00480
00481 while (size--)
00482 {
00483
00484
00485
00486
00487 ser_putchar(0, fd_spi->ser);
00488
00489 if ((c = ser_getchar(fd_spi->ser)) == EOF)
00490 break;
00491
00492 *buf++ = c;
00493 total_rd++;
00494 }
00495 return total_rd;
00496 }
00497
00501 static size_t spimaster_write(struct KFile *fd, const void *buf, size_t size)
00502 {
00503 KFileSerial *fd_spi = KFILESERIAL(fd);
00504
00505 ser_purgeRx(fd_spi);
00506
00507 return ser_write(&fd_spi->fd, buf, size);
00508 }
00509
00510
00522 void spimaster_init(KFileSerial *fds, unsigned int unit)
00523 {
00524 ser_init(fds, unit);
00525 fds->fd.read = spimaster_read;
00526 fds->fd.write = spimaster_write;
00527 }
00528
00529