serial.c

説明を見る。
00001 /*
00002  *  TOPPERS/FDMP Kernel
00003  *      Toyohashi Open Platform for Embedded Real-Time Systems/
00004  *      Function Distributed Multiprocessor Kernel
00005  * 
00006  *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
00007  *                              Toyohashi Univ. of Technology, JAPAN
00008  * 
00009  *  上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation 
00010  *  によって公表されている GNU General Public License の Version 2 に記
00011  *  述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア
00012  *  を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下,
00013  *  利用と呼ぶ)することを無償で許諾する.
00014  *  (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
00015  *      権表示,この利用条件および下記の無保証規定が,そのままの形でソー
00016  *      スコード中に含まれていること.
00017  *  (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
00018  *      用できる形で再配布する場合には,再配布に伴うドキュメント(利用
00019  *      者マニュアルなど)に,上記の著作権表示,この利用条件および下記
00020  *      の無保証規定を掲載すること.
00021  *  (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
00022  *      用できない形で再配布する場合には,次のいずれかの条件を満たすこ
00023  *      と.
00024  *    (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
00025  *        作権表示,この利用条件および下記の無保証規定を掲載すること.
00026  *    (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
00027  *        報告すること.
00028  *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
00029  *      害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
00030  * 
00031  *  本ソフトウェアは,無保証で提供されているものである.上記著作権者お
00032  *  よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も
00033  *  含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直
00034  *  接的または間接的に生じたいかなる損害に関しても,その責任を負わない.
00035  * 
00036  *  @(#) $Id: serial.c,v 1.1 2005/04/03 13:33:19 honda Exp $
00037  */
00038 
00043 #include <t_services.h>
00044 #include <serial.h>
00045 #include <hw_serial.h>
00046 #include "kernel_id.h"
00047 
00048 /*
00049  *  バッファサイズとフロー制御に関連する定数
00050  */
00051 
00052 #define SERIAL_BUFSZ    256     /* ドライバのバッファサイズ */
00053 
00054 #define FC_STOP     '\023'      /* コントロール-S */
00055 #define FC_START    '\021'      /* コントロール-Q */
00056 
00057 #define BUFCNT_STOP (SERIAL_BUFSZ - 64) /* STOPを送る基準文字数 */
00058 #define BUFCNT_START    (SERIAL_BUFSZ - 128)    /* STARTを送る基準文字数 */
00059 
00060 /*
00061  *  クローズの際に送信を待つ最大時間(msec単位)
00062  */
00063 #define MAX_FLUSH_WAIT  1000
00064 
00065 /*
00066  *  シリアルポート初期化ブロック
00067  */
00068 typedef struct serial_port_initialization_block {
00069     ID  rcv_semid;  /* 受信バッファ管理用セマフォのID */
00070     ID  snd_semid;  /* 送信バッファ管理用セマフォのID */
00071 } SPINIB;
00072 
00073 static const SPINIB spinib_table[TNUM_PORT] = {
00074     { SERIAL_RCV_SEM1, SERIAL_SND_SEM1 }
00075 #if TNUM_PORT >= 2
00076     ,{ SERIAL_RCV_SEM2, SERIAL_SND_SEM2 }
00077 #endif
00078 #if TNUM_PORT >= 3
00079     ,{ SERIAL_RCV_SEM3, SERIAL_SND_SEM3 }
00080 #endif
00081 };
00082 
00083 /*
00084  *  シリアルポート管理ブロック
00085  */
00086 typedef struct serial_port_control_block {
00087     const SPINIB *spinib;   /* シリアルポート初期化ブロック */
00088     SIOPCB  *siopcb;    /* シリアルI/Oポート管理ブロック */
00089     BOOL    openflag;   /* オープン済みフラグ */
00090     UINT    ioctl;      /* 動作制御の設定値 */
00091 
00092     UINT    rcv_read_ptr;   /* 受信バッファ読出しポインタ */
00093     UINT    rcv_write_ptr;  /* 受信バッファ書込みポインタ */
00094     UINT    rcv_count;  /* 受信バッファ中の文字数 */
00095     char    rcv_fc_chr; /* 送るべき START/STOP */
00096     BOOL    rcv_stopped;    /* STOP を送った状態か? */
00097 
00098     UINT    snd_read_ptr;   /* 送信バッファ読出しポインタ */
00099     UINT    snd_write_ptr;  /* 送信バッファ書込みポインタ */
00100     UINT    snd_count;  /* 送信バッファ中の文字数 */
00101     BOOL    snd_stopped;    /* STOP を受け取った状態か? */
00102 
00103     char    rcv_buffer[SERIAL_BUFSZ];   /* 受信バッファ */
00104     char    snd_buffer[SERIAL_BUFSZ];   /* 送信バッファ */
00105 } SPCB;
00106 
00107 static SPCB spcb_table[TNUM_PORT];
00108 
00109 /*
00110  *  シリアルポートIDからシリアルポート管理ブロックを取り出すためのマクロ
00111  */
00112 #define INDEX_PORT(portid)  ((UINT)((portid) - 1))
00113 #define get_spcb(portid)    (&(spcb_table[INDEX_PORT(portid)]))
00114 
00118 #define INC_PTR(ptr)        { if (++ptr == SERIAL_BUFSZ) ptr = 0; }
00119 
00120 /*
00121  *  シリアルインタフェースドライバの初期化ルーチン
00122  */
00123 void
00124 serial_initialize(VP_INT exinf)
00125 {
00126     SPCB    *spcb;
00127     UINT    i;
00128 
00129     sio_initialize();
00130     for (spcb = spcb_table, i = 0; i < TNUM_PORT; spcb++, i++) {
00131         spcb->spinib = &(spinib_table[i]);
00132         spcb->openflag = FALSE;
00133     }
00134 }
00135 
00136 /*
00137  *  シリアルポートのオープン
00138  */
00139 ER
00140 serial_opn_por(ID portid)
00141 {
00142     SPCB    *spcb;
00143     ER  ercd;
00144 
00145     if (sns_ctx()) {        /* コンテキストのチェック */
00146         return(E_CTX);
00147     }
00148     if (!(1 <= portid && portid <= TNUM_PORT)) {
00149         return(E_ID);       /* ポート番号のチェック */
00150     }
00151     spcb = get_spcb(portid);
00152 
00153     _syscall(loc_cpu());
00154     if (spcb->openflag) {       /* オープン済みかのチェック */
00155         ercd = E_OBJ;
00156     }
00157     else {
00158         /*
00159          *  変数の初期化
00160          */
00161         spcb->ioctl = (IOCTL_ECHO | IOCTL_CRLF
00162                     | IOCTL_FCSND | IOCTL_FCRCV);
00163 
00164 
00165         spcb->rcv_read_ptr = spcb->rcv_write_ptr = 0;
00166         spcb->rcv_count = 0;
00167         spcb->rcv_fc_chr = '\0';
00168         spcb->rcv_stopped = FALSE;
00169 
00170         spcb->snd_read_ptr = spcb->snd_write_ptr = 0;
00171         spcb->snd_count = 0;
00172         spcb->snd_stopped = FALSE;
00173 
00174         /*
00175          *  ハードウェア依存のオープン処理
00176          */
00177         spcb->siopcb = sio_opn_por(portid, (VP_INT) spcb);
00178 
00179         /*
00180          *  受信通知コールバックを許可する.
00181          */
00182         sio_ena_cbr(spcb->siopcb, SIO_ERDY_RCV);
00183         spcb->openflag = TRUE;
00184         ercd = E_OK;
00185     }
00186     _syscall(unl_cpu());
00187     return(ercd);
00188 }
00189 
00190 /*
00191  *  シリアルポートのクローズ
00192  */
00193 ER
00194 serial_cls_por(ID portid)
00195 {
00196     SPCB    *spcb;
00197     ER  ercd;
00198 
00199     if (sns_ctx()) {        /* コンテキストのチェック */
00200         return(E_CTX);
00201     }
00202     if (!(1 <= portid && portid <= TNUM_PORT)) {
00203         return(E_ID);       /* ポート番号のチェック */
00204     }
00205     spcb = get_spcb(portid);
00206 
00207     _syscall(loc_cpu());
00208     if (!(spcb->openflag)) {    /* オープン済みかのチェック */
00209         ercd = E_OBJ;
00210     }
00211     else {
00212         /*
00213          *  ハードウェア依存のクローズ処理
00214          */
00215         sio_cls_por(spcb->siopcb);
00216         spcb->openflag = FALSE;
00217         ercd = E_OK;
00218     }
00219     _syscall(unl_cpu());
00220     return(ercd);
00221 }
00222 
00223 /*
00224  *  シリアルポートへの文字送信
00225  */
00226 Inline BOOL
00227 serial_snd_chr(SPCB *spcb, char c)
00228 {
00229     if (sio_snd_chr(spcb->siopcb, c)) {
00230         return(TRUE);
00231     }
00232     else {
00233         sio_ena_cbr(spcb->siopcb, SIO_ERDY_SND);
00234         return(FALSE);
00235     }
00236 }
00237 
00238 /*
00239  *  シリアルポートへの送信
00240  */
00241 static BOOL
00242 serial_wri_chr(SPCB *spcb, char c)
00243 {
00244     BOOL    buffer_full;
00245 
00246     /*
00247      *  LF の前に CR を送信する.
00248      */
00249     if (c == '\n' && (spcb->ioctl & IOCTL_CRLF) != 0) {
00250         if (serial_wri_chr(spcb, '\r')) {
00251             _syscall(wai_sem(spcb->spinib->snd_semid));
00252         }
00253     }
00254 
00255     _syscall(loc_cpu());
00256     if (spcb->snd_count == 0 && !(spcb->snd_stopped)
00257                 && serial_snd_chr(spcb, c)) {
00258         /*
00259          *  シリアルI/Oデバイスの送信レジスタに文字を入れるこ
00260          *  とに成功した場合.
00261          */
00262         buffer_full = FALSE;
00263     }
00264     else {
00265         /*
00266          *  送信バッファに文字を入れる.
00267          */
00268         spcb->snd_buffer[spcb->snd_write_ptr] = c;
00269         INC_PTR(spcb->snd_write_ptr);
00270         spcb->snd_count++;
00271         buffer_full = (spcb->snd_count == SERIAL_BUFSZ);
00272     }
00273     _syscall(unl_cpu());
00274     return(buffer_full);
00275 }
00276 
00277 ER_UINT
00278 serial_wri_dat(ID portid, char *buf, UINT len)
00279 {
00280     SPCB    *spcb;
00281     BOOL    buffer_full;
00282     UINT    i;
00283 
00284     if (sns_dpn()) {        /* コンテキストのチェック */
00285         return(E_CTX);
00286     }
00287     if (!(1 <= portid && portid <= TNUM_PORT)) {
00288         return(E_ID);       /* ポート番号のチェック */
00289     }
00290 
00291     spcb = get_spcb(portid);
00292     if (!(spcb->openflag)) {    /* オープン済みかのチェック */
00293         return(E_OBJ);
00294     }
00295 
00296     buffer_full = TRUE;     /* ループの1回めは wai_sem する */
00297     for (i = 0; i < len; i++) {
00298         if (buffer_full) {
00299             _syscall(wai_sem(spcb->spinib->snd_semid));
00300         }
00301         buffer_full = serial_wri_chr(spcb, *buf++);
00302     }
00303     if (!buffer_full) {
00304         _syscall(sig_sem(spcb->spinib->snd_semid));
00305     }
00306     return(len);
00307 }
00308 
00309 /*
00310  *  シリアルポートからの受信
00311  */
00312 static BOOL
00313 serial_rea_chr(SPCB *spcb, char *c)
00314 {
00315     BOOL    buffer_empty;
00316 
00317     _syscall(loc_cpu());
00318 
00319     /*
00320      *  受信バッファから文字を取り出す.
00321      */
00322     *c = spcb->rcv_buffer[spcb->rcv_read_ptr];
00323     INC_PTR(spcb->rcv_read_ptr);
00324     spcb->rcv_count--;
00325     buffer_empty = (spcb->rcv_count == 0);
00326 
00327     /*
00328      *  START を送信する.
00329      */
00330     if (spcb->rcv_stopped && spcb->rcv_count <= BUFCNT_START) {
00331         if (!serial_snd_chr(spcb, FC_START)) {
00332             spcb->rcv_fc_chr = FC_START;
00333         }
00334         spcb->rcv_stopped = FALSE;
00335     }
00336     _syscall(unl_cpu());
00337 
00338     /*
00339      *  エコーバック処理.
00340      */
00341     if ((spcb->ioctl & IOCTL_ECHO) != 0) {
00342         _syscall(wai_sem(spcb->spinib->snd_semid));
00343         if (!serial_wri_chr(spcb, *c)) {
00344             _syscall(sig_sem(spcb->spinib->snd_semid));
00345         }
00346     }
00347     return(buffer_empty);
00348 }
00349 
00350 ER_UINT
00351 serial_rea_dat(ID portid, char *buf, UINT len)
00352 {
00353     SPCB    *spcb;
00354     BOOL    buffer_empty;
00355     UINT    i;
00356 
00357     if (sns_dpn()) {        /* コンテキストのチェック */
00358         return(E_CTX);
00359     }
00360     if (!(1 <= portid && portid <= TNUM_PORT)) {
00361         return(E_ID);       /* ポート番号のチェック */
00362     }
00363 
00364     spcb = get_spcb(portid);
00365     if (!(spcb->openflag)) {    /* オープン済みかのチェック */
00366         return(E_OBJ);
00367     }
00368 
00369     buffer_empty = TRUE;        /* ループの1回めは wai_sem する */
00370     for (i = 0; i < len; i++) {
00371         if (buffer_empty) {
00372             _syscall(wai_sem(spcb->spinib->rcv_semid));
00373         }
00374         buffer_empty = serial_rea_chr(spcb, buf++);
00375     }
00376     if (!buffer_empty) {
00377         _syscall(sig_sem(spcb->spinib->rcv_semid));
00378     }
00379     return(len);
00380 }
00381 
00382 /*
00383  *  シリアルポートの制御
00384  */
00385 ER
00386 serial_ctl_por(ID portid, UINT ioctl)
00387 {
00388     SPCB    *spcb;
00389 
00390     if (sns_ctx()) {        /* コンテキストのチェック */
00391         return(E_CTX);
00392     }
00393     if (!(1 <= portid && portid <= TNUM_PORT)) {
00394         return(E_ID);       /* ポート番号のチェック */
00395     }
00396 
00397     spcb = get_spcb(portid);
00398     if (!(spcb->openflag)) {    /* オープン済みかのチェック */
00399         return(E_OBJ);
00400     }
00401 
00402     spcb->ioctl = ioctl;
00403     return(E_OK);
00404 }
00405 
00406 /*
00407  *  シリアルポート状態の参照
00408  */
00409 ER
00410 serial_ref_por(ID portid, T_SERIAL_RPOR *pk_rpor)
00411 {
00412     SPCB    *spcb;
00413 
00414     if (sns_ctx()) {        /* コンテキストのチェック */
00415         return(E_CTX);
00416     }
00417     if (!(1 <= portid && portid <= TNUM_PORT)) {
00418         return(E_ID);       /* ポート番号のチェック */
00419     }
00420 
00421     spcb = get_spcb(portid);
00422     if (!(spcb->openflag)) {    /* オープン済みかのチェック */
00423         return(E_OBJ);
00424     }
00425 
00426     pk_rpor->reacnt = spcb->rcv_count;
00427     pk_rpor->wricnt = spcb->snd_count;
00428     return(E_OK);
00429 }
00430 
00431 /*
00432  *  シリアルポートからの送信可能コールバック
00433  */
00434 void
00435 sio_ierdy_snd(VP_INT exinf)
00436 {
00437     SPCB    *spcb;
00438 
00439     spcb = (SPCB *) exinf;
00440     if (spcb->rcv_fc_chr != '\0') {
00441         /*
00442          *  START/STOP を送信する.
00443          */
00444         (void) sio_snd_chr(spcb->siopcb, spcb->rcv_fc_chr);
00445         spcb->rcv_fc_chr = '\0';
00446     }
00447     else if (!(spcb->snd_stopped) && spcb->snd_count > 0) {
00448         /*
00449          *  送信バッファ中から文字を取り出して送信する.
00450          */
00451         (void) sio_snd_chr(spcb->siopcb,
00452                 spcb->snd_buffer[spcb->snd_read_ptr]);
00453         INC_PTR(spcb->snd_read_ptr);
00454         if (spcb->snd_count == SERIAL_BUFSZ) {
00455             _syscall(isig_sem(spcb->spinib->snd_semid));
00456         }
00457         spcb->snd_count--;
00458     }
00459     else {
00460         /*
00461          *  送信すべき文字がない場合は,送信可能コールバックを
00462          *  禁止する.
00463          */
00464         sio_dis_cbr(spcb->siopcb, SIO_ERDY_SND);
00465     }
00466 }
00467 
00468 /*
00469  *  シリアルポートからの受信通知コールバック
00470  */
00471 void
00472 sio_ierdy_rcv(VP_INT exinf)
00473 {
00474     SPCB    *spcb;
00475     char    c;
00476 
00477     spcb = (SPCB *) exinf;
00478     c = (char) sio_rcv_chr(spcb->siopcb);
00479     if ((spcb->ioctl & IOCTL_FCSND) != 0 && c == FC_STOP) {
00480         /*
00481          *  送信を一時停止する.送信中の文字はそのまま送信する.
00482          */
00483         spcb->snd_stopped = TRUE;
00484     }
00485     else if (spcb->snd_stopped && (c == FC_START
00486                 || (spcb->ioctl & IOCTL_FCANY) != 0)) {
00487         /*
00488          *  送信を再開する.
00489          */
00490         spcb->snd_stopped = FALSE;
00491         if (spcb->snd_count > 0) {
00492             c = spcb->snd_buffer[spcb->snd_read_ptr];
00493             if (serial_snd_chr(spcb, c)) {
00494                 INC_PTR(spcb->snd_read_ptr);
00495                 if (spcb->snd_count == SERIAL_BUFSZ) {
00496                     _syscall(isig_sem(spcb->spinib
00497                                 ->snd_semid));
00498                 }
00499                 spcb->snd_count--;
00500             }
00501         }
00502     }
00503     else if ((spcb->ioctl & IOCTL_FCSND) != 0 && c == FC_START) {
00504         /*
00505          *  送信に対してフロー制御している場合,START は捨てる.
00506          */
00507     }
00508     else if (spcb->rcv_count == SERIAL_BUFSZ) {
00509         /*
00510          *  バッファフルの場合,受信した文字を捨てる.
00511          */
00512     }
00513     else {
00514         /*
00515          *  受信した文字を受信バッファに入れる.
00516          */
00517         spcb->rcv_buffer[spcb->rcv_write_ptr] = c;
00518         INC_PTR(spcb->rcv_write_ptr);
00519         if (spcb->rcv_count == 0) {
00520             _syscall(isig_sem(spcb->spinib->rcv_semid));
00521         }
00522         spcb->rcv_count++;
00523 
00524         /*
00525          *  STOP を送信する.
00526          */
00527         if ((spcb->ioctl & IOCTL_FCRCV) != 0 && !(spcb->rcv_stopped)
00528                     && (spcb->rcv_count >= BUFCNT_STOP)) {
00529             if (!serial_snd_chr(spcb, FC_STOP)) {
00530                 spcb->rcv_fc_chr = FC_STOP;
00531             }
00532             spcb->rcv_stopped = TRUE;
00533         }
00534     }
00535 }

Copyright © 2006 by TAKAGI Nobuhisa.
このページは Mon Apr 3 23:49:13 2006 に Doxygen によって生成されました。