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 #include <compiler.h>
00066 #include <stdlib.h>
00067 #include <string.h>
00068
00069 #include <sys/atom.h>
00070 #include <sys/heap.h>
00071 #include <sys/event.h>
00072 #include <sys/timer.h>
00073
00074 #include <dev/irqreg.h>
00075 #include <dev/usart.h>
00076
00077 #include <fcntl.h>
00078
00079
00080
00081
00082
00083 #ifndef _IOFBF
00084 #define _IOFBF 0x00
00085 #define _IOLBF 0x01
00086 #define _IONBF 0x02
00087 #endif
00088
00093
00107 int UsartInit(NUTDEVICE * dev)
00108 {
00109 int rc;
00110 USARTDCB *dcb = dev->dev_dcb;
00111
00112
00113 if ((rc = (*dcb->dcb_init) ()) == 0) {
00114
00115 (*dcb->dcb_set_speed) (USART_INITSPEED);
00116 }
00117 return rc;
00118 }
00119
00130 static int UsartResetBuffer(RINGBUF * rbf, size_t size, size_t lowm, size_t hiwm)
00131 {
00132 uint8_t *xbp = rbf->rbf_start;
00133 size_t xsz = rbf->rbf_siz;
00134
00135
00136 NutEnterCritical();
00137 rbf->rbf_siz = 0;
00138 NutExitCritical();
00139
00140
00141 if (xsz != size) {
00142 if (xsz && xbp) {
00143 free(xbp);
00144 }
00145 if (size && (xbp = malloc(size)) == 0) {
00146 return -1;
00147 }
00148 }
00149
00150
00151 if (size) {
00152 rbf->rbf_start = xbp;
00153 rbf->rbf_head = xbp;
00154 rbf->rbf_tail = xbp;
00155 rbf->rbf_last = xbp + size;
00156 rbf->rbf_lwm = lowm;
00157 rbf->rbf_hwm = hiwm;
00158 rbf->rbf_cnt = 0;
00159
00160
00161 NutEnterCritical();
00162 rbf->rbf_siz = size;
00163 NutExitCritical();
00164 }
00165 return 0;
00166 }
00167
00194 int UsartRead(NUTFILE * fp, void *buffer, int size)
00195 {
00196 size_t rc;
00197 size_t avail;
00198 size_t taken = 0;
00199 uint8_t ch;
00200 uint8_t *cp = buffer;
00201 NUTDEVICE *dev = fp->nf_dev;
00202 USARTDCB *dcb = dev->dev_dcb;
00203 RINGBUF *rbf = &dcb->dcb_rx_rbf;
00204
00205
00206
00207
00208 if (rbf->rbf_siz == 0) {
00209 return -1;
00210 }
00211
00212
00213
00214
00215 if (buffer == 0) {
00216 UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00217 (*dcb->dcb_rx_start) ();
00218 return 0;
00219 }
00220
00221
00222
00223
00224
00225 for (;;) {
00226
00227 NutEnterCritical();
00228 avail = rbf->rbf_cnt;
00229 NutExitCritical();
00230 if (avail) {
00231 break;
00232 }
00233
00234
00235
00236
00237 (*dcb->dcb_rx_start) ();
00238 if (NutEventWait(&rbf->rbf_que, dcb->dcb_rtimeout)) {
00239 return 0;
00240 }
00241 }
00242
00243
00244
00245
00246 if (dcb->dcb_modeflags & USART_MF_COOKEDMODE) {
00247 for (rc = 0; rc < (size_t) size;) {
00248 if (taken >= avail) {
00249 break;
00250 }
00251 ch = *rbf->rbf_tail++;
00252 if (rbf->rbf_tail == rbf->rbf_last) {
00253 rbf->rbf_tail = rbf->rbf_start;
00254 }
00255 taken++;
00256 if (ch == '\r' || ch == '\n') {
00257 if (dcb->dcb_last_eol == 0 || dcb->dcb_last_eol == ch) {
00258 dcb->dcb_last_eol = ch;
00259 *cp++ = '\n';
00260 rc++;
00261 }
00262 } else {
00263 dcb->dcb_last_eol = 0;
00264 *cp++ = ch;
00265 rc++;
00266 }
00267 }
00268 }
00269
00270
00271
00272
00273 else {
00274 if ((rc = size) > avail)
00275 rc = avail;
00276 for (taken = 0; taken < rc; taken++) {
00277 *cp++ = *rbf->rbf_tail++;
00278 if (rbf->rbf_tail == rbf->rbf_last) {
00279 rbf->rbf_tail = rbf->rbf_start;
00280 }
00281 }
00282 }
00283
00284 if (taken) {
00285 NutEnterCritical();
00286 rbf->rbf_cnt -= taken;
00287 NutExitCritical();
00288 if (rbf->rbf_cnt < rbf->rbf_lwm) {
00289 (*dcb->dcb_rx_start) ();
00290 }
00291 }
00292 return (int) rc;
00293 }
00294
00313 static size_t UsartFlushOutput(USARTDCB *dcb, size_t added, size_t left)
00314 {
00315 size_t rc;
00316 RINGBUF *rbf = &dcb->dcb_tx_rbf;
00317
00318
00319
00320
00321 NutEnterCritical();
00322 rbf->rbf_cnt += added;
00323 rc = rbf->rbf_cnt;
00324 NutExitCritical();
00325
00326 while (rc > left) {
00327
00328 (*dcb->dcb_tx_start) ();
00329 if (NutEventWait(&rbf->rbf_que, dcb->dcb_wtimeout)) {
00330 break;
00331 }
00332
00333 NutEnterCritical();
00334 rc = rbf->rbf_cnt;
00335 NutExitCritical();
00336 };
00337 return rc;
00338 }
00339
00352 static int UsartPut(NUTDEVICE * dev, CONST void *buffer, int len, int pflg)
00353 {
00354 int rc;
00355 CONST uint8_t *cp;
00356 uint8_t lbmode;
00357 ureg_t cooked;
00358 uint8_t ch;
00359 size_t cnt;
00360 size_t added;
00361 USARTDCB *dcb = dev->dev_dcb;
00362 RINGBUF *rbf = &dcb->dcb_tx_rbf;
00363
00364
00365
00366
00367 if (rbf->rbf_siz == 0) {
00368 return -1;
00369 }
00370
00371
00372
00373
00374
00375 if (buffer == 0) {
00376 return UsartFlushOutput(dcb, 0, 0);
00377 }
00378
00379 if (dcb->dcb_modeflags & USART_MF_LINEBUFFER)
00380 lbmode = 1;
00381 else
00382 lbmode = 0;
00383
00384 if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00385 cooked = 1;
00386 else
00387 cooked = 0;
00388
00389
00390
00391
00392
00393 NutEnterCritical();
00394 cnt = rbf->rbf_cnt;
00395 NutExitCritical();
00396
00397
00398
00399
00400 cp = buffer;
00401 added = 0;
00402 for (rc = 0; rc < len;) {
00403
00404
00405
00406
00407 if (cnt + added >= rbf->rbf_hwm) {
00408 cnt = UsartFlushOutput(dcb, added, rbf->rbf_lwm);
00409 added = 0;
00410
00411 if(cnt > rbf->rbf_lwm) {
00412 break;
00413 }
00414 }
00415
00416
00417
00418
00419
00420 ch = pflg ? PRG_RDB(cp) : *cp;
00421
00422
00423
00424
00425
00426 if (cooked == 1 && ch == '\n') {
00427 cooked = 2;
00428 ch = '\r';
00429 if (lbmode == 1)
00430 lbmode = 2;
00431 } else {
00432 if (cooked == 2)
00433 cooked = 1;
00434 cp++;
00435 rc++;
00436 }
00437 *rbf->rbf_head++ = ch;
00438 if (rbf->rbf_head == rbf->rbf_last) {
00439 rbf->rbf_head = rbf->rbf_start;
00440 }
00441 added++;
00442 }
00443
00444 if (added) {
00445 NutEnterCritical();
00446 rbf->rbf_cnt += added;
00447 NutExitCritical();
00448 (*dcb->dcb_tx_start) ();
00449 }
00450
00451 return rc;
00452 }
00453
00473 int UsartWrite(NUTFILE * fp, CONST void *buffer, int len)
00474 {
00475 return UsartPut(fp->nf_dev, buffer, len, 0);
00476 }
00477
00499 int UsartWrite_P(NUTFILE * fp, PGM_P buffer, int len)
00500 {
00501 return UsartPut(fp->nf_dev, (CONST char *) buffer, len, 1);
00502 }
00503
00517 int UsartClose(NUTFILE * fp)
00518 {
00519 NUTDEVICE *dev = fp->nf_dev;
00520 USARTDCB *dcb = dev->dev_dcb;
00521
00522 if (fp == 0 || fp == NUTFILE_EOF)
00523 return -1;
00524
00525 free(fp);
00526 UsartResetBuffer(&dcb->dcb_tx_rbf, 0, 0, 0);
00527 UsartResetBuffer(&dcb->dcb_rx_rbf, 0, 0, 0);
00528
00529 return 0;
00530 }
00531
00550 NUTFILE *UsartOpen(NUTDEVICE * dev, CONST char *name, int mode, int acc)
00551 {
00552 USARTDCB *dcb = dev->dev_dcb;
00553 NUTFILE *fp;
00554
00555
00556
00557
00558 if ((mode & 0x0003) != _O_RDONLY) {
00559 if (UsartResetBuffer(&dcb->dcb_tx_rbf, USART_TXBUFSIZ, USART_TXLOWMARK, USART_TXHIWMARK)) {
00560 return NUTFILE_EOF;
00561 }
00562 }
00563
00564
00565
00566
00567 if ((mode & 0x0003) != _O_WRONLY) {
00568 if (UsartResetBuffer(&dcb->dcb_rx_rbf, USART_RXBUFSIZ, USART_RXLOWMARK, USART_RXHIWMARK)) {
00569 free(dcb->dcb_tx_rbf.rbf_start);
00570 return NUTFILE_EOF;
00571 }
00572 }
00573
00574
00575
00576
00577 if ((fp = malloc(sizeof(NUTFILE))) == 0) {
00578 free(dcb->dcb_tx_rbf.rbf_start);
00579 free(dcb->dcb_rx_rbf.rbf_start);
00580 return NUTFILE_EOF;
00581 }
00582
00583
00584 if ((mode & 0xC000) == _O_BINARY) {
00585 dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00586 } else {
00587 dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00588 }
00589
00590
00591
00592
00593
00594
00595 fp->nf_next = 0;
00596 fp->nf_dev = dev;
00597 fp->nf_fcb = 0;
00598
00599 if ((mode & 0x0003) != _O_WRONLY) {
00600 (*dcb->dcb_rx_start) ();
00601 }
00602
00603 return fp;
00604 }
00605
00665 int UsartIOCtl(NUTDEVICE * dev, int req, void *conf)
00666 {
00667 int rc = 0;
00668 USARTDCB *dcb;
00669 RINGBUF *rbf;
00670 uint32_t *lvp = (uint32_t *) conf;
00671 uint32_t lv = *lvp;
00672 uint8_t bv = (uint8_t) lv;
00673
00674 dcb = dev->dev_dcb;
00675
00676 switch (req) {
00677 case UART_SETSPEED:
00678 rc = (*dcb->dcb_set_speed) (lv);
00679 break;
00680 case UART_GETSPEED:
00681 *lvp = (*dcb->dcb_get_speed) ();
00682 break;
00683
00684 case UART_SETDATABITS:
00685 rc = (*dcb->dcb_set_data_bits) (bv);
00686 break;
00687 case UART_GETDATABITS:
00688 *lvp = (*dcb->dcb_get_data_bits) ();
00689 break;
00690
00691 case UART_SETPARITY:
00692 rc = (*dcb->dcb_set_parity) (bv);
00693 break;
00694 case UART_GETPARITY:
00695 *lvp = (*dcb->dcb_get_parity) ();
00696 break;
00697
00698 case UART_SETSTOPBITS:
00699 rc = (*dcb->dcb_set_stop_bits) (bv);
00700 break;
00701 case UART_GETSTOPBITS:
00702 *lvp = (*dcb->dcb_get_stop_bits) ();
00703 break;
00704
00705 case UART_SETSTATUS:
00706
00707
00708
00709
00710
00711 if (lv & UART_RXBUFFEREMPTY) {
00712 rbf = &dcb->dcb_rx_rbf;
00713 UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00714 (*dcb->dcb_rx_start) ();
00715 }
00716 if (lv & UART_TXBUFFEREMPTY) {
00717 rbf = &dcb->dcb_tx_rbf;
00718 UsartResetBuffer(rbf, rbf->rbf_siz, rbf->rbf_lwm, rbf->rbf_hwm);
00719 }
00720 rc = (*dcb->dcb_set_status) (lv & ~(UART_RXBUFFEREMPTY | UART_TXBUFFEREMPTY));
00721 break;
00722 case UART_GETSTATUS:
00723 *lvp = (*dcb->dcb_get_status) ();
00724
00725
00726
00727 if (dcb->dcb_rx_rbf.rbf_cnt == 0) {
00728 *lvp |= UART_RXBUFFEREMPTY;
00729 }
00730 if (dcb->dcb_tx_rbf.rbf_cnt == 0) {
00731 *lvp |= UART_TXBUFFEREMPTY;
00732 }
00733 break;
00734
00735 case UART_SETREADTIMEOUT:
00736 dcb->dcb_rtimeout = lv;
00737 break;
00738 case UART_GETREADTIMEOUT:
00739 *lvp = dcb->dcb_rtimeout;
00740 break;
00741
00742 case UART_SETWRITETIMEOUT:
00743 dcb->dcb_wtimeout = lv;
00744 break;
00745 case UART_GETWRITETIMEOUT:
00746 *lvp = dcb->dcb_wtimeout;
00747 break;
00748
00749 case UART_SETLOCALECHO:
00750 if (bv)
00751 dcb->dcb_modeflags |= USART_MF_LOCALECHO;
00752 else
00753 dcb->dcb_modeflags &= ~USART_MF_LOCALECHO;
00754 break;
00755 case UART_GETLOCALECHO:
00756 if (dcb->dcb_modeflags & USART_MF_LOCALECHO)
00757 *lvp = 1;
00758 else
00759 *lvp = 0;
00760 break;
00761
00762 case UART_SETFLOWCONTROL:
00763 rc = (*dcb->dcb_set_flow_control) (lv);
00764 break;
00765 case UART_GETFLOWCONTROL:
00766 *lvp = (*dcb->dcb_get_flow_control) ();
00767 break;
00768
00769 case UART_SETCOOKEDMODE:
00770 if (bv)
00771 dcb->dcb_modeflags |= USART_MF_COOKEDMODE;
00772 else
00773 dcb->dcb_modeflags &= ~USART_MF_COOKEDMODE;
00774 break;
00775 case UART_GETCOOKEDMODE:
00776 if (dcb->dcb_modeflags & USART_MF_COOKEDMODE)
00777 *lvp = 1;
00778 else
00779 *lvp = 0;
00780 break;
00781
00782 case UART_SETCLOCKMODE:
00783 rc = (*dcb->dcb_set_clock_mode) (lv);
00784 break;
00785 case UART_GETCLOCKMODE:
00786 *lvp = (*dcb->dcb_get_clock_mode) ();
00787 break;
00788
00789 case UART_SETTXBUFSIZ:
00790 rbf = &dcb->dcb_tx_rbf;
00791 rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00792 if (rc == 0) {
00793 (*dcb->dcb_rx_start) ();
00794 }
00795 break;
00796 case UART_GETTXBUFSIZ:
00797 *lvp = dcb->dcb_tx_rbf.rbf_siz;
00798 break;
00799
00800 case UART_SETRXBUFSIZ:
00801 rbf = &dcb->dcb_rx_rbf;
00802 rc = UsartResetBuffer(rbf, (size_t) lv, rbf->rbf_lwm, rbf->rbf_hwm);
00803 break;
00804 case UART_GETRXBUFSIZ:
00805 *lvp = dcb->dcb_rx_rbf.rbf_siz;
00806 break;
00807
00808 case UART_SETTXBUFLWMARK:
00809 NutEnterCritical();
00810 dcb->dcb_tx_rbf.rbf_lwm = (size_t) lv;
00811 NutExitCritical();
00812 break;
00813 case UART_GETTXBUFLWMARK:
00814 *lvp = dcb->dcb_tx_rbf.rbf_lwm;
00815 break;
00816
00817 case UART_SETTXBUFHWMARK:
00818 NutEnterCritical();
00819 dcb->dcb_tx_rbf.rbf_hwm = (size_t) lv;
00820 NutExitCritical();
00821 break;
00822 case UART_GETTXBUFHWMARK:
00823 *lvp = dcb->dcb_tx_rbf.rbf_hwm;
00824 break;
00825
00826 case UART_SETRXBUFLWMARK:
00827 NutEnterCritical();
00828 dcb->dcb_rx_rbf.rbf_lwm = (size_t) lv;
00829 NutExitCritical();
00830 break;
00831 case UART_GETRXBUFLWMARK:
00832 *lvp = dcb->dcb_rx_rbf.rbf_lwm;
00833 break;
00834
00835 case UART_SETRXBUFHWMARK:
00836 NutEnterCritical();
00837 dcb->dcb_rx_rbf.rbf_hwm = (size_t) lv;
00838 NutExitCritical();
00839 break;
00840 case UART_GETRXBUFHWMARK:
00841 *lvp = dcb->dcb_rx_rbf.rbf_hwm;
00842 break;
00843
00844 default:
00845 rc = -1;
00846 break;
00847 }
00848 return rc;
00849 }
00850
00862 long UsartSize (NUTFILE *fp)
00863 {
00864 long avail;
00865 NUTDEVICE *dev = fp->nf_dev;
00866 USARTDCB *dcb = dev->dev_dcb;
00867 RINGBUF *rbf = &dcb->dcb_rx_rbf;
00868
00869
00870 NutEnterCritical();
00871 avail = rbf->rbf_cnt;
00872 NutExitCritical();
00873
00874 return avail;
00875 }
00876
00877