BeRTOS
|
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