00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 #include <compiler.h>
00069 #include <stdlib.h>
00070 #include <string.h>
00071 #include <memdebug.h>
00072
00073 #include <sys/atom.h>
00074 #include <sys/heap.h>
00075 #include <sys/event.h>
00076 #include <sys/timer.h>
00077
00078 #include <dev/irqreg.h>
00079 #include <dev/usart.h>
00080
00081 #include <fcntl.h>
00082
00083
00084
00085
00086
00087 #ifndef _IOFBF
00088 #define _IOFBF 0x00
00089 #define _IOLBF 0x01
00090 #define _IONBF 0x02
00091 #endif
00092
00097
00111 int UsartInit(NUTDEVICE * dev)
00112 {
00113 int rc;
00114 USARTDCB *dcb = dev->dev_dcb;
00115
00116
00117 if ((rc = (*dcb->dcb_init) ()) == 0) {
00118
00119 (*dcb->dcb_set_speed) (USART_INITSPEED);
00120 }
00121 return rc;
00122 }
00123
00134 static int UsartResetBuffer(RINGBUF * rbf, size_t size, size_t lowm, size_t hiwm)
00135 {
00136 uint8_t *xbp = rbf->rbf_start;
00137 size_t xsz = rbf->rbf_siz;
00138
00139
00140 NutEnterCritical();
00141 rbf->rbf_siz = 0;
00142 NutExitCritical();
00143
00144
00145 if (xsz != size) {
00146 if (xsz && xbp) {
00147 free(xbp);
00148 }
00149 if (size && (xbp = malloc(size)) == 0) {
00150 return -1;
00151 }
00152 }
00153
00154
00155 if (size) {
00156 rbf->rbf_start = xbp;
00157 rbf->rbf_head = xbp;
00158 rbf->rbf_tail = xbp;
00159 rbf->rbf_last = xbp + size;
00160 rbf->rbf_lwm = lowm;
00161 rbf->rbf_hwm = hiwm;
00162 rbf->rbf_cnt = 0;
00163
00164
00165 NutEnterCritical();
00166 rbf->rbf_siz = size;
00167 NutExitCritical();
00168 }
00169 return 0;
00170 }
00171
00198 int UsartRead(NUTFILE * fp, void *buffer, int size)
00199 {
00200 size_t rc;
00201 size_t avail;
00202 size_t taken = 0;
00203 uint8_t ch;
00204 uint8_t *cp = buffer;
00205 NUTDEVICE *dev = fp->nf_dev;
00206 USARTDCB *dcb = dev->dev_dcb;
00207 RINGBUF *rbf = &dcb->dcb_rx_rbf;
00208
00209
00210
00211
00212 if (rbf->rbf_siz == 0) {
00213 return -1;
00214 }
00215
00216
00217
00218
00219 if (buffer == 0) {
00220 UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00221 (*dcb->dcb_rx_start) ();
00222 return 0;
00223 }
00224
00225
00226
00227
00228
00229 for (;;) {
00230
00231 NutEnterCritical();
00232 avail = rbf->rbf_cnt;
00233 NutExitCritical();
00234 if (avail) {
00235 break;
00236 }
00237
00238
00239
00240
00241 (*dcb->dcb_rx_start) ();
00242 if (NutEventWait(&rbf->rbf_que, dcb->dcb_rtimeout)) {
00243 return 0;
00244 }
00245
00246 if (rbf->rbf_siz == 0) {
00247 return -1;
00248 }
00249 }
00250
00251
00252
00253
00254 if (dcb->dcb_modeflags & USART_MF_COOKEDMODE) {
00255 for (rc = 0; rc < (size_t) size;) {
00256 if (taken >= avail) {
00257 break;
00258 }
00259 ch = *rbf->rbf_tail++;
00260 if (rbf->rbf_tail == rbf->rbf_last) {
00261 rbf->rbf_tail = rbf->rbf_start;
00262 }
00263 taken++;
00264 if (ch == '\r' || ch == '\n') {
00265 if (dcb->dcb_last_eol == 0 || dcb->dcb_last_eol == ch) {
00266 dcb->dcb_last_eol = ch;
00267 *cp++ = '\n';
00268 rc++;
00269 }
00270 } else {
00271 dcb->dcb_last_eol = 0;
00272 *cp++ = ch;
00273 rc++;
00274 }
00275 }
00276 }
00277
00278
00279
00280
00281 else {
00282 if ((rc = size) > avail)
00283 rc = avail;
00284 for (taken = 0; taken < rc; taken++) {
00285 *cp++ = *rbf->rbf_tail++;
00286 if (rbf->rbf_tail == rbf->rbf_last) {
00287 rbf->rbf_tail = rbf->rbf_start;
00288 }
00289 }
00290 }
00291
00292 if (taken) {
00293 NutEnterCritical();
00294 rbf->rbf_cnt -= taken;
00295 NutExitCritical();
00296 if (rbf->rbf_cnt < rbf->rbf_lwm) {
00297 (*dcb->dcb_rx_start) ();
00298 }
00299 }
00300 return (int) rc;
00301 }
00302
00321 static size_t UsartFlushOutput(USARTDCB *dcb, size_t added, size_t left)
00322 {
00323 size_t rc;
00324 RINGBUF *rbf = &dcb->dcb_tx_rbf;
00325
00326
00327
00328
00329 NutEnterCritical();
00330 rbf->rbf_cnt += added;
00331 rc = rbf->rbf_cnt;
00332 NutExitCritical();
00333
00334 while (rc > left) {
00335
00336 (*dcb->dcb_tx_start) ();
00337 if (NutEventWait(&rbf->rbf_que, dcb->dcb_wtimeout)) {
00338 break;
00339 }
00340
00341 NutEnterCritical();
00342 rc = rbf->rbf_cnt;
00343 NutExitCritical();
00344 };
00345 return rc;
00346 }
00347
00360 static int UsartPut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00361 {
00362 int rc;
00363 CONST uint8_t *cp;
00364 uint8_t lbmode;
00365 ureg_t cooked;
00366 uint8_t ch;
00367 size_t cnt;
00368 size_t added;
00369 USARTDCB *dcb = dev->dev_dcb;
00370 RINGBUF *rbf = &dcb->dcb_tx_rbf;
00371
00372
00373
00374
00375 if (rbf->rbf_siz == 0) {
00376 return -1;
00377 }
00378
00379
00380
00381
00382
00383 if (buffer == 0) {
00384 return UsartFlushOutput(dcb, 0, 0);
00385 }
00386
00387 if (dcb->dcb_modeflags & USART_MF_LINEBUFFER)
00388 lbmode = 1;
00389 else
00390 lbmode = 0;
00391
00392 if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00393 cooked = 1;
00394 else
00395 cooked = 0;
00396
00397
00398
00399
00400
00401 NutEnterCritical();
00402 cnt = rbf->rbf_cnt;
00403 NutExitCritical();
00404
00405
00406
00407
00408 cp = buffer;
00409 added = 0;
00410 for (rc = 0; rc < len;) {
00411
00412
00413
00414
00415 if (cnt + added >= rbf->rbf_hwm) {
00416 cnt = UsartFlushOutput(dcb, added, rbf->rbf_lwm);
00417 added = 0;
00418
00419 if(cnt > rbf->rbf_lwm) {
00420 break;
00421 }
00422 }
00423
00424
00425
00426
00427
00428 ch = pflg ? PRG_RDB(cp) : *cp;
00429
00430
00431
00432
00433
00434 if (cooked == 1 && ch == '\n') {
00435 cooked = 2;
00436 ch = '\r';
00437 if (lbmode == 1)
00438 lbmode = 2;
00439 } else {
00440 if (cooked == 2)
00441 cooked = 1;
00442 cp++;
00443 rc++;
00444 }
00445 *rbf->rbf_head++ = ch;
00446 if (rbf->rbf_head == rbf->rbf_last) {
00447 rbf->rbf_head = rbf->rbf_start;
00448 }
00449 added++;
00450 }
00451
00452 if (added) {
00453 NutEnterCritical();
00454 rbf->rbf_cnt += added;
00455 NutExitCritical();
00456 (*dcb->dcb_tx_start) ();
00457 }
00458
00459 return rc;
00460 }
00461
00481 int UsartWrite(NUTFILE * fp, CONST void *buffer, int len)
00482 {
00483 return UsartPut(fp->nf_dev, buffer, len, 0);
00484 }
00485
00507 int UsartWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00508 {
00509 return UsartPut(fp->nf_dev, (CONST char *) buffer, len, 1);
00510 }
00511
00525 int UsartClose(NUTFILE * fp)
00526 {
00527 NUTDEVICE *dev = fp->nf_dev;
00528 USARTDCB *dcb = dev->dev_dcb;
00529
00530 if (fp == 0 || fp == NUTFILE_EOF)
00531 return -1;
00532
00533 (*dcb->dcb_set_status) (UART_RTSDISABLED);
00534 free(fp);
00535 UsartResetBuffer(&dcb->dcb_tx_rbf, 0, 0, 0);
00536 UsartResetBuffer(&dcb->dcb_rx_rbf, 0, 0, 0);
00537
00538 NutEventBroadcast(&dcb->dcb_rx_rbf.rbf_que);
00539
00540 return 0;
00541 }
00542
00561 NUTFILE *UsartOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00562 {
00563 USARTDCB *dcb = dev->dev_dcb;
00564 NUTFILE *fp;
00565
00566
00567
00568
00569 if ((mode & 0x0003) != _O_RDONLY) {
00570 if (UsartResetBuffer(&dcb->dcb_tx_rbf, USART_TXBUFSIZ, USART_TXLOWMARK, USART_TXHIWMARK)) {
00571 return NUTFILE_EOF;
00572 }
00573 }
00574
00575
00576
00577
00578 if ((mode & 0x0003) != _O_WRONLY) {
00579 if (UsartResetBuffer(&dcb->dcb_rx_rbf, USART_RXBUFSIZ, USART_RXLOWMARK, USART_RXHIWMARK)) {
00580 free(dcb->dcb_tx_rbf.rbf_start);
00581 return NUTFILE_EOF;
00582 }
00583 }
00584
00585
00586
00587
00588 if ((fp = malloc(sizeof(NUTFILE))) == 0) {
00589 free(dcb->dcb_tx_rbf.rbf_start);
00590 free(dcb->dcb_rx_rbf.rbf_start);
00591 return NUTFILE_EOF;
00592 }
00593
00594
00595 if ((mode & 0xC000) == _O_BINARY) {
00596 dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00597 } else {
00598 dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00599 }
00600
00601
00602
00603
00604
00605
00606 fp->nf_next = 0;
00607 fp->nf_dev = dev;
00608 fp->nf_fcb = 0;
00609
00610 if ((mode & 0x0003) != _O_WRONLY) {
00611 (*dcb->dcb_rx_start) ();
00612 }
00613
00614 return fp;
00615 }
00616
00678 int UsartIOCtl(NUTDEVICE * dev, int req, void *conf)
00679 {
00680 int rc = 0;
00681 USARTDCB *dcb;
00682 RINGBUF *rbf;
00683 uint32_t *lvp = (uint32_t *) conf;
00684 uint32_t lv = *lvp;
00685 uint8_t bv = (uint8_t) lv;
00686
00687 dcb = dev->dev_dcb;
00688
00689 switch (req) {
00690 case UART_SETSPEED:
00691 rc = (*dcb->dcb_set_speed) (lv);
00692 break;
00693 case UART_GETSPEED:
00694 *lvp = (*dcb->dcb_get_speed) ();
00695 break;
00696
00697 case UART_SETDATABITS:
00698 rc = (*dcb->dcb_set_data_bits) (bv);
00699 break;
00700 case UART_GETDATABITS:
00701 *lvp = (*dcb->dcb_get_data_bits) ();
00702 break;
00703
00704 case UART_SETPARITY:
00705 rc = (*dcb->dcb_set_parity) (bv);
00706 break;
00707 case UART_GETPARITY:
00708 *lvp = (*dcb->dcb_get_parity) ();
00709 break;
00710
00711 case UART_SETSTOPBITS:
00712 rc = (*dcb->dcb_set_stop_bits) (bv);
00713 break;
00714 case UART_GETSTOPBITS:
00715 *lvp = (*dcb->dcb_get_stop_bits) ();
00716 break;
00717
00718 case UART_SETSTATUS:
00719
00720
00721
00722
00723
00724 if (lv & UART_RXBUFFEREMPTY) {
00725 rbf = &dcb->dcb_rx_rbf;
00726 UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00727 (*dcb->dcb_rx_start) ();
00728 }
00729 if (lv & UART_TXBUFFEREMPTY) {
00730 rbf = &dcb->dcb_tx_rbf;
00731 UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00732 }
00733 rc = (*dcb->dcb_set_status) (lv & ~(UART_RXBUFFEREMPTY | UART_TXBUFFEREMPTY));
00734 break;
00735 case UART_GETSTATUS:
00736 *lvp = (*dcb->dcb_get_status) ();
00737
00738
00739
00740 if (dcb->dcb_rx_rbf.rbf_cnt == 0) {
00741 *lvp |= UART_RXBUFFEREMPTY;
00742 }
00743 if (dcb->dcb_tx_rbf.rbf_cnt == 0) {
00744 *lvp |= UART_TXBUFFEREMPTY;
00745 }
00746 break;
00747
00748 case UART_SETREADTIMEOUT:
00749 dcb->dcb_rtimeout = lv;
00750 break;
00751 case UART_GETREADTIMEOUT:
00752 *lvp = dcb->dcb_rtimeout;
00753 break;
00754
00755 case UART_SETWRITETIMEOUT:
00756 dcb->dcb_wtimeout = lv;
00757 break;
00758 case UART_GETWRITETIMEOUT:
00759 *lvp = dcb->dcb_wtimeout;
00760 break;
00761
00762 case UART_SETLOCALECHO:
00763 if (bv)
00764 dcb->dcb_modeflags |= USART_MF_LOCALECHO;
00765 else
00766 dcb->dcb_modeflags &= ~USART_MF_LOCALECHO;
00767 break;
00768 case UART_GETLOCALECHO:
00769 if (dcb->dcb_modeflags & USART_MF_LOCALECHO)
00770 *lvp = 1;
00771 else
00772 *lvp = 0;
00773 break;
00774
00775 case UART_SETFLOWCONTROL:
00776 rc = (*dcb->dcb_set_flow_control) (lv);
00777 break;
00778 case UART_GETFLOWCONTROL:
00779 *lvp = (*dcb->dcb_get_flow_control) ();
00780 break;
00781
00782 case UART_SETCOOKEDMODE:
00783 if (bv)
00784 dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00785 else
00786 dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00787 break;
00788 case UART_GETCOOKEDMODE:
00789 if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00790 *lvp = 1;
00791 else
00792 *lvp = 0;
00793 break;
00794
00795 case UART_SETHDPXMODE:
00796 if (bv)
00797 dcb->dcb_modeflags |= USART_MF_HALFDUPLEX;
00798 else
00799 dcb->dcb_modeflags &= ~USART_MF_HALFDUPLEX;
00800 break;
00801 case UART_GETHDPXMODE:
00802 if (dcb->dcb_modeflags & USART_MF_HALFDUPLEX)
00803 *lvp = 1;
00804 else
00805 *lvp = 0;
00806 break;
00807
00808 case UART_SETCLOCKMODE:
00809 rc = (*dcb->dcb_set_clock_mode) (lv);
00810 break;
00811 case UART_GETCLOCKMODE:
00812 *lvp = (*dcb->dcb_get_clock_mode) ();
00813 break;
00814
00815 case UART_SETTXBUFSIZ:
00816 rbf = &dcb->dcb_tx_rbf;
00817 rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00818 if (rc == 0) {
00819 (*dcb->dcb_rx_start) ();
00820 }
00821 break;
00822 case UART_GETTXBUFSIZ:
00823 *lvp = dcb->dcb_tx_rbf.rbf_siz;
00824 break;
00825
00826 case UART_SETRXBUFSIZ:
00827 rbf = &dcb->dcb_rx_rbf;
00828 rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00829 break;
00830 case UART_GETRXBUFSIZ:
00831 *lvp = dcb->dcb_rx_rbf.rbf_siz;
00832 break;
00833
00834 case UART_SETTXBUFLWMARK:
00835 NutEnterCritical();
00836 dcb->dcb_tx_rbf.rbf_lwm = (size_t) lv;
00837 NutExitCritical();
00838 break;
00839 case UART_GETTXBUFLWMARK:
00840 *lvp = dcb->dcb_tx_rbf.rbf_lwm;
00841 break;
00842
00843 case UART_SETTXBUFHWMARK:
00844 NutEnterCritical();
00845 dcb->dcb_tx_rbf.rbf_hwm = (size_t) lv;
00846 NutExitCritical();
00847 break;
00848 case UART_GETTXBUFHWMARK:
00849 *lvp = dcb->dcb_tx_rbf.rbf_hwm;
00850 break;
00851
00852 case UART_SETRXBUFLWMARK:
00853 NutEnterCritical();
00854 dcb->dcb_rx_rbf.rbf_lwm = (size_t) lv;
00855 NutExitCritical();
00856 break;
00857 case UART_GETRXBUFLWMARK:
00858 *lvp = dcb->dcb_rx_rbf.rbf_lwm;
00859 break;
00860
00861 case UART_SETRXBUFHWMARK:
00862 NutEnterCritical();
00863 dcb->dcb_rx_rbf.rbf_hwm = (size_t) lv;
00864 NutExitCritical();
00865 break;
00866 case UART_GETRXBUFHWMARK:
00867 *lvp = dcb->dcb_rx_rbf.rbf_hwm;
00868 break;
00869
00870 default:
00871 rc = -1;
00872 break;
00873 }
00874 return rc;
00875 }
00876
00888 long UsartSize (NUTFILE *fp)
00889 {
00890 long avail;
00891 NUTDEVICE *dev = fp->nf_dev;
00892 USARTDCB *dcb = dev->dev_dcb;
00893 RINGBUF *rbf = &dcb->dcb_rx_rbf;
00894
00895
00896 NutEnterCritical();
00897 avail = rbf->rbf_cnt;
00898 NutExitCritical();
00899
00900 return avail;
00901 }
00902
00903