source: uKadecot/trunk/ssp/syssvc/serial.c@ 108

Last change on this file since 108 was 108, checked in by coas-nagasima, 9 years ago

MIMEプロパティの変更

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-chdr; charset=SHIFT_JIS
File size: 15.1 KB
RevLine 
[101]1/*
2 * TOPPERS/SSP Kernel
3 * Smallest Set Profile Kernel
4 *
5 * Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
6 * Toyohashi Univ. of Technology, JAPAN
7 * Copyright (C) 2006-2008 by Embedded and Real-Time Systems Laboratory
8 * Graduate School of Information Science, Nagoya Univ., JAPAN
9 * Copyright (C) 2010-2012 by Meika Sugimoto
10 * Copyright (C) 2015 by Naoki Saito
11 * Nagoya Municipal Industrial Research Institute, JAPAN
12 *
13 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
14 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
15 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
16 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
17 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
18 * スコード中に含まれていること.
19 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
20 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
21 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
22 * の無保証規定を掲載すること.
23 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
24 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
25 * と.
26 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
27 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
28 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
29 * 報告すること.
30 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
31 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
32 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
33 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
34 * 免責すること.
35 *
36 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
37 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
38 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
39 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
40 * の責任を負わない.
41 */
42
43/*
44 * シリアルインタフェースドライバ
45 */
46
47#include <kernel.h>
48#include "target_syssvc.h"
49#include "target_serial.h"
50#include "serial.h"
51#include "kernel_cfg.h"
52
53/*
54 * バッファサイズのデフォルト値とバッファの定義
55 */
56#ifndef SERIAL_RCV_BUFSZ1
57#define SERIAL_RCV_BUFSZ1 64 /* ポート1の受信バッファサイズ */
58#endif /* SERIAL_RCV_BUFSZ1 */
59
60#ifndef SERIAL_SND_BUFSZ1
61#define SERIAL_SND_BUFSZ1 256 /* ポート1の送信バッファサイズ */
62#endif /* SERIAL_SND_BUFSZ1 */
63
64static char rcv_buffer1[SERIAL_RCV_BUFSZ1];
65static char snd_buffer1[SERIAL_SND_BUFSZ1];
66
67#if TNUM_PORT >= 2 /* ポート2に関する定義 */
68
69#ifndef SERIAL_RCV_BUFSZ2
70#define SERIAL_RCV_BUFSZ2 64 /* ポート2の受信バッファサイズ */
71#endif /* SERIAL_RCV_BUFSZ2 */
72
73#ifndef SERIAL_SND_BUFSZ2
74#define SERIAL_SND_BUFSZ2 64 /* ポート2の送信バッファサイズ */
75#endif /* SERIAL_SND_BUFSZ2 */
76
77static char rcv_buffer2[SERIAL_RCV_BUFSZ2];
78static char snd_buffer2[SERIAL_SND_BUFSZ2];
79
80#endif /* TNUM_PORT >= 2 */
81
82#if TNUM_PORT >= 3 /* ポート3に関する定義 */
83
84#ifndef SERIAL_RCV_BUFSZ3
85#define SERIAL_RCV_BUFSZ3 64 /* ポート3の受信バッファサイズ */
86#endif /* SERIAL_RCV_BUFSZ3 */
87
88#ifndef SERIAL_SND_BUFSZ3
89#define SERIAL_SND_BUFSZ3 64 /* ポート3の送信バッファサイズ */
90#endif /* SERIAL_SND_BUFSZ3 */
91
92static char rcv_buffer3[SERIAL_RCV_BUFSZ3];
93static char snd_buffer3[SERIAL_SND_BUFSZ3];
94
95#endif /* TNUM_PORT >= 3 */
96
97/*
98 * シリアルポート初期化ブロック
99 */
100typedef struct serial_port_initialization_block {
101 uint_t rcv_bufsz; /* 受信バッファサイズ */
102 char *rcv_buffer; /* 受信バッファ */
103 uint_t snd_bufsz; /* 送信バッファサイズ */
104 char *snd_buffer; /* 送信バッファ */
105} SPINIB;
106
107static const SPINIB spinib_table[TNUM_PORT] = {
108 { SERIAL_RCV_BUFSZ1, rcv_buffer1,
109 SERIAL_SND_BUFSZ1, snd_buffer1 },
110#if TNUM_PORT >= 2
111 { SERIAL_RCV_BUFSZ2, rcv_buffer2,
112 SERIAL_SND_BUFSZ2, snd_buffer2 },
113#endif /* TNUM_PORT >= 2 */
114#if TNUM_PORT >= 3
115 { SERIAL_RCV_BUFSZ3, rcv_buffer3,
116 SERIAL_SND_BUFSZ3, snd_buffer3 },
117#endif /* TNUM_PORT >= 3 */
118};
119
120/*
121 * シリアルポート管理ブロック
122 */
123typedef struct serial_port_control_block {
124 const SPINIB *p_spinib; /* シリアルポート初期化ブロック */
125 SIOPCB *p_siopcb; /* シリアルI/Oポート管理ブロック */
126 bool_t openflag; /* オープン済みフラグ */
127 bool_t errorflag; /* エラーフラグ */
128 uint_t ioctl; /* 動作制御の設定値 */
129
130 uint_t rcv_read_ptr; /* 受信バッファ読出しポインタ */
131 uint_t rcv_write_ptr; /* 受信バッファ書込みポインタ */
132 uint_t rcv_count; /* 受信バッファ中の文字数 */
133
134 uint_t snd_read_ptr; /* 送信バッファ読出しポインタ */
135 uint_t snd_write_ptr; /* 送信バッファ書込みポインタ */
136 uint_t snd_count; /* 送信バッファ中の文字数 */
137} SPCB;
138
139static SPCB spcb_table[TNUM_PORT];
140
141/*
142 * シリアルポートIDからシリアルポート管理ブロックを取り出すためのマクロ
143 */
144#define INDEX_PORT(portid) ((uint_t)((portid) - 1))
145#define get_spcb(portid) (&(spcb_table[INDEX_PORT(portid)]))
146
147/*
148 * ポインタのインクリメント
149 */
150#define INC_PTR(ptr, bufsz) { if (++(ptr) == (bufsz)) { (ptr) = 0; }}
151
152/*
153 * サービスコール呼出しマクロ
154 *
155 * サービスコール呼出しを含む式expを評価し,返値がエラー(負の値)の場
156 * 合には,ercにercd_expを評価した値を代入し,error_exitにgotoする.
157 */
158#define SVC(exp, ercd_exp) \
159 { if ((exp) < 0) { ercd = (ercd_exp); goto error_exit; }}
160
161/*
162 * E_SYSエラーの生成
163 */
164static ER
165gen_ercd_sys(SPCB *p_spcb)
166{
167 p_spcb->errorflag = true;
168 return(E_SYS);
169}
170
171
172/*
173 * シリアルインタフェースドライバの初期化ルーチン
174 */
175void
176serial_initialize(intptr_t exinf)
177{
178 uint_t i;
179 SPCB *p_spcb;
180
181 for (i = 0; i < TNUM_PORT; i++) {
182 p_spcb = &(spcb_table[i]);
183 p_spcb->p_spinib = &(spinib_table[i]);
184 p_spcb->openflag = false;
185 }
186}
187
188/*
189 * シリアルインターフェースドライバの終了ルーチン
190 */
191
192void
193serial_terminate(intptr_t exinf)
194{
195 uint_t i;
196 SPCB *p_spcb;
197
198 /* バッファに残っている全ての文字を出力する */
199 for (i = 0; i < TNUM_PORT; i++) {
200 p_spcb = &(spcb_table[i]);
201
202 while(p_spcb->snd_count != 0U)
203 {
204 if(sio_snd_chr(p_spcb->p_siopcb,
205 p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr]) == true)
206 {
207 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
208 p_spcb->snd_count--;
209 }
210 }
211 }
212
213}
214
215/*
216 * シリアルポートのオープン(サービスコール)
217 */
218ER
219serial_opn_por(ID portid)
220{
221 SPCB *p_spcb;
222 ER ercd;
223
224 if (sns_dpn()) { /* コンテキストのチェック */
225 return(E_CTX);
226 }
227 if (!(1 <= portid && portid <= TNUM_PORT)) {
228 return(E_ID); /* ポート番号のチェック */
229 }
230 p_spcb = get_spcb(portid);
231
232 SVC(dis_dsp(), gen_ercd_sys(p_spcb));
233 if (p_spcb->openflag) { /* オープン済みかのチェック */
234 ercd = E_OBJ;
235 }
236 else {
237 /*
238 * 変数の初期化
239 */
240 p_spcb->ioctl = (IOCTL_ECHO | IOCTL_CRLF);
241
242 p_spcb->rcv_read_ptr = p_spcb->rcv_write_ptr = 0U;
243 p_spcb->rcv_count = 0U;
244
245 p_spcb->snd_read_ptr = p_spcb->snd_write_ptr = 0U;
246 p_spcb->snd_count = 0U;
247
248 /*
249 * これ以降,割込みを禁止する.
250 */
251 if (loc_cpu() < 0) {
252 ercd = E_SYS;
253 goto error_exit_enadsp;
254 }
255
256 /*
257 * ハードウェア依存のオープン処理
258 */
259 p_spcb->p_siopcb = sio_opn_por(portid, (intptr_t) p_spcb);
260
261 /*
262 * 受信通知コールバックを許可する.
263 */
264 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_RCV);
265 p_spcb->openflag = true;
266 p_spcb->errorflag = false;
267
268 if (unl_cpu() < 0) {
269 p_spcb->errorflag = true;
270 ercd = E_SYS;
271 goto error_exit_enadsp;
272 }
273 ercd = E_OK;
274 }
275
276 error_exit_enadsp:
277 SVC(ena_dsp(), gen_ercd_sys(p_spcb));
278
279 error_exit:
280 return(ercd);
281}
282
283/*
284 * シリアルポートのクローズ(サービスコール)
285 */
286ER
287serial_cls_por(ID portid)
288{
289 SPCB *p_spcb;
290 ER ercd;
291 bool_t eflag = false;
292
293 if (sns_dpn()) { /* コンテキストのチェック */
294 return(E_CTX);
295 }
296 if (!(1 <= portid && portid <= TNUM_PORT)) {
297 return(E_ID); /* ポート番号のチェック */
298 }
299 p_spcb = get_spcb(portid);
300
301 SVC(dis_dsp(), gen_ercd_sys(p_spcb));
302 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
303 ercd = E_OBJ;
304 }
305 else {
306 /*
307 * ハードウェア依存のクローズ処理
308 */
309 if (loc_cpu() < 0) {
310 eflag = true;
311 }
312 sio_cls_por(p_spcb->p_siopcb);
313 p_spcb->openflag = false;
314 if (unl_cpu() < 0) {
315 eflag = true;
316 }
317
318 /*
319 * エラーコードの設定
320 */
321 if (eflag) {
322 ercd = gen_ercd_sys(p_spcb);
323 }
324 else {
325 ercd = E_OK;
326 }
327 }
328 SVC(ena_dsp(), gen_ercd_sys(p_spcb));
329
330 error_exit:
331 return(ercd);
332}
333
334/*
335 * シリアルポートへの文字送信
336 *
337 * p_spcbで指定されるシリアルI/Oポートに対して,文字cを送信する.文字
338 * を送信レジスタにいれた場合にはtrueを返す.そうでない場合には,送信
339 * レジスタが空いたことを通知するコールバック関数を許可し,falseを返す.
340 * この関数は,CPUロック状態で呼び出される.
341 */
342Inline bool_t
343serial_snd_chr(SPCB *p_spcb, char c)
344{
345 if (sio_snd_chr(p_spcb->p_siopcb, c)) {
346 return(true);
347 }
348 else {
349 sio_ena_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
350 return(false);
351 }
352}
353
354/*
355 * シリアルポートへの1文字送信
356 * 指定された文字の送信を試みる.
357 * デバイスへの送信が成功した場合またはバッファに空きがあり格納できた場合は false,
358 * バッファがフルで格納できなかった場合は true を返す.
359 * それ以外のエラーが発生した場合は ER 型のエラーコードを返す.
360 */
361static ER_BOOL
362serial_wri_chr(SPCB *p_spcb, char c)
363{
364 bool_t buffer_full;
365 ER ercd, rercd;
366
367 /*
368 * LFの前にCRを送信する.
369 * ただし,1文字以下の空きしかない場合はバッファフルとみなし,送信しない.
370 */
371 if (c == '\n' && (p_spcb->ioctl & IOCTL_CRLF) != 0U) {
372 if(p_spcb->snd_count + 1U < p_spcb->p_spinib->snd_bufsz) {
373 SVC(rercd = serial_wri_chr(p_spcb, '\r'), rercd);
374 }
375 else {
376 return (ER_BOOL) true;
377 }
378 }
379
380 SVC(loc_cpu(), gen_ercd_sys(p_spcb));
381 if ((p_spcb->snd_count == 0U) && serial_snd_chr(p_spcb, c)) {
382 /*
383 * シリアルI/Oデバイスの送信レジスタに文字を入れることに成功し
384 * た場合.
385 */
386 buffer_full = false;
387 }
388 else {
389 /*
390 * 空きがあれば,送信バッファに文字を入れる.
391 * 空きがない場合,送信しない.
392 */
393 if(p_spcb->snd_count < p_spcb->p_spinib->snd_bufsz) {
394 p_spcb->p_spinib->snd_buffer[p_spcb->snd_write_ptr] = c;
395 INC_PTR(p_spcb->snd_write_ptr, p_spcb->p_spinib->snd_bufsz);
396 p_spcb->snd_count++;
397 buffer_full = false;
398 }
399 else {
400 buffer_full = true;
401 }
402 }
403
404 SVC(unl_cpu(), gen_ercd_sys(p_spcb));
405 ercd = (ER_BOOL) buffer_full;
406
407 error_exit:
408 return(ercd);
409}
410
411bool_t
412serial_rcvbuf_empty(SPCB *p_spcb)
413{
414 return (p_spcb->rcv_count == 0u);
415}
416
417/*
418 * シリアルポートへの文字列送信(サービスコール)
419 */
420ER_UINT
421serial_wri_dat(ID portid, const char *buf, uint_t len)
422{
423 SPCB *p_spcb;
424 bool_t buffer_full;
425 uint_t wricnt = 0U;
426 ER ercd, rercd;
427
428 if (sns_dpn()) { /* コンテキストのチェック */
429 return(E_CTX);
430 }
431 if (!(1 <= portid && portid <= TNUM_PORT)) {
432 return(E_ID); /* ポート番号のチェック */
433 }
434
435 p_spcb = get_spcb(portid);
436 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
437 return(E_OBJ);
438 }
439 if (p_spcb->errorflag) { /* エラー状態かのチェック */
440 return(E_SYS);
441 }
442
443 /*
444 * len まで1文字ずつ送信を試みる.
445 * 途中でバッファフルになったら中断する.
446 */
447 SVC((rercd = dis_dsp()) , rercd);
448 for(wricnt = 0U; wricnt < len; wricnt++) {
449 SVC(rercd = serial_wri_chr(p_spcb, *buf++), rercd);
450 buffer_full = (bool_t)rercd;
451 if(buffer_full) {
452 break;
453 }
454 }
455 SVC((rercd = ena_dsp()) , rercd);
456
457 ercd = E_OK;
458 error_exit:
459 return(wricnt > 0U ? (ER_UINT) wricnt : ercd);
460}
461
462/*
463 * シリアルポートからの1文字受信
464 * 文字の受信を試みる.
465 * バッファにデータが存在し,取得できた場合は false,
466 * バッファが空で取得できなかった場合は true を返す.
467 * それ以外のエラーが発生した場合は ER 型のエラーコードを返す.
468 */
469static ER_BOOL
470serial_rea_chr(SPCB *p_spcb, char *p_c)
471{
472 bool_t buffer_empty;
473 ER ercd;
474
475 SVC(loc_cpu(), gen_ercd_sys(p_spcb));
476
477 /*
478 * データが存在すれば,受信バッファから文字を取り出す.
479 * なければ取り出さない.
480 */
481 if(p_spcb->rcv_count > 0U) {
482 *p_c = p_spcb->p_spinib->rcv_buffer[p_spcb->rcv_read_ptr];
483 INC_PTR(p_spcb->rcv_read_ptr, p_spcb->p_spinib->rcv_bufsz);
484 p_spcb->rcv_count--;
485 buffer_empty = false;
486 }
487 else {
488 buffer_empty = true;
489 }
490
491 SVC(unl_cpu(), gen_ercd_sys(p_spcb));
492 ercd = (ER_BOOL) buffer_empty;
493
494 error_exit:
495 return(ercd);
496}
497
498/*
499 * シリアルポートからの文字列受信(サービスコール)
500 */
501ER_UINT
502serial_rea_dat(ID portid, char *buf, uint_t len)
503{
504 SPCB *p_spcb;
505 bool_t buffer_empty;
506 uint_t reacnt = 0U;
507 char c = '\0'; /* コンパイラの警告を抑止するために初期化する */
508 ER ercd, rercd;
509
510 if (sns_dpn()) { /* コンテキストのチェック */
511 return(E_CTX);
512 }
513 if (!(1 <= portid && portid <= TNUM_PORT)) {
514 return(E_ID); /* ポート番号のチェック */
515 }
516
517 p_spcb = get_spcb(portid);
518 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
519 return(E_OBJ);
520 }
521 if (p_spcb->errorflag) { /* エラー状態かのチェック */
522 return(E_SYS);
523 }
524
525 /*
526 * len まで受信を試みる.
527 * バッファが空で読み出せなかった場合は中断する
528 */
529 SVC((rercd = dis_dsp()) , rercd);
530 for(reacnt = 0U; reacnt < len; reacnt++) {
531 SVC(rercd = serial_rea_chr(p_spcb, &c), rercd);
532 buffer_empty = (bool_t)rercd;
533
534 if(buffer_empty) {
535 break;
536 }
537 else {
538 /*
539 * エコーバック処理.
540 */
541 if ((p_spcb->ioctl & IOCTL_ECHO) != 0U) {
542 SVC(rercd = serial_wri_chr(p_spcb, c), rercd);
543 }
544 *buf++ = c;
545 }
546 }
547 SVC((rercd = ena_dsp()) , rercd);
548
549 ercd = E_OK;
550 error_exit:
551 return(reacnt > 0U ? (ER_UINT) reacnt : ercd);
552}
553
554/*
555 * シリアルポートの制御(サービスコール)
556 */
557ER
558serial_ctl_por(ID portid, uint_t ioctl)
559{
560 SPCB *p_spcb;
561
562 if (sns_dpn()) { /* コンテキストのチェック */
563 return(E_CTX);
564 }
565 if (!(1 <= portid && portid <= TNUM_PORT)) {
566 return(E_ID); /* ポート番号のチェック */
567 }
568
569 p_spcb = get_spcb(portid);
570 if (!(p_spcb->openflag)) { /* オープン済みかのチェック */
571 return(E_OBJ);
572 }
573 if (p_spcb->errorflag) { /* エラー状態かのチェック */
574 return(E_SYS);
575 }
576
577 p_spcb->ioctl = ioctl;
578 return(E_OK);
579}
580
581/*
582 * シリアルポートからの送信可能コールバック
583 */
584void
585sio_irdy_snd(intptr_t exinf)
586{
587 SPCB *p_spcb;
588
589 p_spcb = (SPCB *) exinf;
590
591 if (p_spcb->snd_count > 0U) {
592 /*
593 * 送信バッファ中から文字を取り出して送信する.
594 */
595 (void) sio_snd_chr(p_spcb->p_siopcb,
596 p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr]);
597 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
598 p_spcb->snd_count--;
599 }
600 else {
601 /*
602 * 送信すべき文字がない場合は,送信可能コールバックを禁止する.
603 */
604 sio_dis_cbr(p_spcb->p_siopcb, SIO_RDY_SND);
605 }
606}
607
608/*
609 * シリアルポートからの受信通知コールバック
610 */
611void
612sio_irdy_rcv(intptr_t exinf)
613{
614 SPCB *p_spcb;
615 char c;
616
617 p_spcb = (SPCB *) exinf;
618 c = (char) sio_rcv_chr(p_spcb->p_siopcb);
619
620 if (p_spcb->rcv_count != p_spcb->p_spinib->rcv_bufsz) {
621 /*
622 * 受信した文字を受信バッファに入れる.
623 * バッファフルの場合,受信した文字を捨てる.
624 */
625 p_spcb->p_spinib->rcv_buffer[p_spcb->rcv_write_ptr] = c;
626 INC_PTR(p_spcb->rcv_write_ptr, p_spcb->p_spinib->rcv_bufsz);
627 p_spcb->rcv_count++;
628 }
629}
630
631/*
632 * シリアルインタフェースドライバからの未送信文字の取出し
633 */
634bool_t
635serial_get_chr(ID portid, char *p_c)
636{
637 SPCB *p_spcb;
638
639 if (1 <= portid && portid <= TNUM_PORT) { /* ポート番号のチェック */
640 p_spcb = get_spcb(portid);
641 if (p_spcb->openflag) { /* オープン済みかのチェック */
642 if (p_spcb->snd_count > 0U) {
643 *p_c = p_spcb->p_spinib->snd_buffer[p_spcb->snd_read_ptr];
644 INC_PTR(p_spcb->snd_read_ptr, p_spcb->p_spinib->snd_bufsz);
645 p_spcb->snd_count--;
646 return(true);
647 }
648 }
649 }
650 return(false);
651}
Note: See TracBrowser for help on using the repository browser.