source: EcnlProtoTool/trunk/asp3_dcre/sample/tSample2.c@ 439

Last change on this file since 439 was 429, checked in by coas-nagasima, 4 years ago

ASP3, TINET, mbed を更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 18.3 KB
Line 
1/*
2 * TOPPERS/ASP Kernel
3 * Toyohashi Open Platform for Embedded Real-Time Systems/
4 * Advanced Standard Profile Kernel
5 *
6 * Copyright (C) 2015-2016 by Ushio Laboratory
7 * Graduate School of Engineering Science, Osaka Univ., JAPAN
8 * Copyright (C) 2015-2019 by Embedded and Real-Time Systems Laboratory
9 * Graduate School of Information Science, Nagoya Univ., JAPAN
10 *
11 * 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ
12 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
13 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
14 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
15 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
16 * スコード中に含まれていること.
17 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
18 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
19 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
20 * の無保証規定を掲載すること.
21 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
22 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
23 * と.
24 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
25 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
26 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
27 * 報告すること.
28 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
29 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
30 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
31 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
32 * 免責すること.
33 *
34 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
35 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
36 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
37 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
38 * の責任を負わない.
39 *
40 * $Id$
41 */
42
43/*
44 * サンプルプログラム(2)の本体
45 *
46 * ASPカーネルの基本的な動作を確認するためのサンプルプログラム(TECS版).
47 *
48 * プログラムの概要:
49 *
50 * ユーザインタフェースを受け持つメインタスク(MainTask)と,3つの並
51 * 行実行されるタスク(Task1~Task3),例外処理タスク(ExceptionTask)
52 * の5つのタスクを用いる.これらの他に,システムログタスクが動作する.
53 * また,周期ハンドラ,アラームハンドラ,割込みサービスルーチン,CPU
54 * 例外ハンドラをそれぞれ1つ用いる.
55 *
56 * 並行実行されるタスクは,task_loop回のループを実行する度に,タスク
57 * が実行中であることをあらわすメッセージを表示する.ループを実行する
58 * のは,プログラムの動作を確認しやすくするためである.また,低速なシ
59 * リアルポートを用いてメッセージを出力する場合に,すべてのメッセージ
60 * が出力できるように,メッセージの量を制限するという理由もある.
61 *
62 * 周期ハンドラ,アラームハンドラ,割込みサービスルーチンは,3つの優
63 * 先度(HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY)のレディキューを
64 * 回転させる.周期ハンドラは,プログラムの起動直後は停止状態になって
65 * いる.
66 *
67 * CPU例外ハンドラは,CPU例外からの復帰が可能な場合には,例外処理タス
68 * クを起動する.例外処理タスクは,CPU例外を起こしたタスクに対して,
69 * 終了要求を行う.
70 *
71 * メインタスクは,シリアルポートからの文字入力を行い(文字入力を待っ
72 * ている間は,並行実行されるタスクが実行されている),入力された文字
73 * に対応した処理を実行する.入力された文字と処理の関係は次の通り.
74 * Control-Cまたは'Q'が入力されると,プログラムを終了する.
75 *
76 * '1' : 対象タスクをTASK1に切り換える(初期設定).
77 * '2' : 対象タスクをTASK2に切り換える.
78 * '3' : 対象タスクをTASK3に切り換える.
79 * 'a' : 対象タスクをcTask_activateにより起動する.
80 * 'A' : 対象タスクに対する起動要求をcTask_cancelActivateによりキャンセルする.
81 * 'e' : 対象タスクにexitTaskを呼び出させ,終了させる.
82 * 't' : 対象タスクをcTask_terminateにより強制終了する.
83 * '>' : 対象タスクの優先度をHIGH_PRIORITYにする.
84 * '=' : 対象タスクの優先度をMID_PRIORITYにする.
85 * '<' : 対象タスクの優先度をLOW_PRIORITYにする.
86 * 'G' : 対象タスクの優先度をcTask_getPriorityで読み出す.
87 * 's' : 対象タスクにsleepを呼び出させ,起床待ちにさせる.
88 * 'S' : 対象タスクにsleepTimeout10秒)を呼び出させ,起床待ちにさせる.
89 * 'w' : 対象タスクをcTask_wakeupにより起床する.
90 * 'W' : 対象タスクに対する起床要求をcTask_cancelWakeupによりキャンセルする.
91 * 'l' : 対象タスクをcTask_releaseWaitにより強制的に待ち解除にする.
92 * 'u' : 対象タスクをcTask_suspendにより強制待ち状態にする.
93 * 'm' : 対象タスクの強制待ち状態をcTask_resumeにより解除する.
94 * 'd' : 対象タスクにdelay(10秒)を呼び出させ,時間経過待ちにさせる.
95 * 'x' : 対象タスクにraiseTerminateにより終了要求する.
96 * 'y' : 対象タスクにdisableTerminateを呼び出させ,タスク終了を禁止する.
97 * 'Y' : 対象タスクにenableTerminateを呼び出させ,タスク終了を許可する.
98 * 'r' : 3つの優先度(HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY)のレ
99 * ディキューを回転させる.
100 * 'c' : 周期ハンドラを動作開始させる.
101 * 'C' : 周期ハンドラを動作停止させる.
102 * 'b' : アラームハンドラを5秒後に起動するよう動作開始させる.
103 * 'B' : アラームハンドラを動作停止させる.
104 * 'z' : 対象タスクにCPU例外を発生させる(ターゲットによっては復帰可能).
105 * 'Z' : 対象タスクにCPUロック状態でCPU例外を発生させる(復帰不可能).
106 * 'V' : 短いループを挟んで,fetchHighResolutionTimerで高分解能タイマを
107 * 2回読む.
108 * 'v' : 発行したシステムコールを表示する(デフォルト).
109 * 'q' : 発行したシステムコールを表示しない.
110 */
111
112#include "tSample2_tecsgen.h"
113#include <kernel.h>
114#include <t_syslog.h>
115#include <t_stdlib.h>
116#include "kernel_cfg.h"
117#include "tSample2.h"
118
119/*
120 * サービスコールのエラーのログ出力
121 */
122Inline void
123svc_perror(const char *file, int_t line, const char *expr, ER ercd)
124{
125 if (ercd < 0) {
126 t_perror(LOG_ERROR, file, line, expr, ercd);
127 }
128}
129
130#define SVC_PERROR(expr) svc_perror(__FILE__, __LINE__, #expr, (expr))
131
132/*
133 * プロセッサ時間の消費
134 *
135 * ループによりプロセッサ時間を消費する.最適化ができないように,ルー
136 * プ内でvolatile変数を読み込む.
137 */
138static volatile long_t volatile_var;
139
140static void
141consume_time(ulong_t ctime)
142{
143 ulong_t i;
144
145 for (i = 0; i < ctime; i++) {
146 (void) volatile_var;
147 }
148}
149
150/*
151 * 並行実行されるタスクへのメッセージ領域
152 */
153char message[3];
154
155/*
156 * ループ回数
157 */
158ulong_t task_loop; /* タスク内でのループ回数 */
159
160/*
161 * 並行実行されるタスク
162 */
163void
164eSampleTask_main(int_t subscript)
165{
166 int_t n = 0;
167 int_t tskno = subscript + 1;
168 const char *graph[] = { "|", " +", " *" };
169 char c;
170
171 while (true) {
172 syslog(LOG_NOTICE, "task%d is running (%03d). %s",
173 tskno, ++n, graph[tskno-1]);
174 consume_time(task_loop);
175 c = message[tskno-1];
176 message[tskno-1] = 0;
177 switch (c) {
178 case 'e':
179 syslog(LOG_INFO, "#%d#exit()", tskno);
180 SVC_PERROR(exit());
181 assert(0);
182 case 's':
183 syslog(LOG_INFO, "#%d#sleep()", tskno);
184 SVC_PERROR(sleep());
185 break;
186 case 'S':
187 syslog(LOG_INFO, "#%d#sleepTimeout(10000)", tskno);
188 SVC_PERROR(sleepTimeout(10000));
189 break;
190 case 'd':
191 syslog(LOG_INFO, "#%d#delay(10000)", tskno);
192 SVC_PERROR(delay(10000));
193 break;
194 case 'y':
195 syslog(LOG_INFO, "#%d#disableTerminate()", tskno);
196 SVC_PERROR(disableTerminate());
197 break;
198 case 'Y':
199 syslog(LOG_INFO, "#%d#enableTerminate()", tskno);
200 SVC_PERROR(enableTerminate());
201 break;
202#ifdef CPUEXC1
203 case 'z':
204 syslog(LOG_NOTICE, "#%d#raise CPU exception", tskno);
205 RAISE_CPU_EXCEPTION;
206 break;
207 case 'Z':
208 SVC_PERROR(lockCpu());
209 syslog(LOG_NOTICE, "#%d#raise CPU exception", tskno);
210 RAISE_CPU_EXCEPTION;
211 SVC_PERROR(unlockCpu());
212 break;
213#endif /* CPUEXC1 */
214 default:
215 break;
216 }
217 }
218}
219
220/*
221 * 割込みサービスルーチン
222 *
223 * HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY の各優先度のレディキュー
224 * を回転させる.
225 */
226#ifdef INTNO1
227
228void
229eiISR_main(void)
230{
231 intno1_clear();
232 SVC_PERROR(ciKernel_rotateReadyQueue(HIGH_PRIORITY));
233 SVC_PERROR(ciKernel_rotateReadyQueue(MID_PRIORITY));
234 SVC_PERROR(ciKernel_rotateReadyQueue(LOW_PRIORITY));
235}
236
237#endif /* INTNO1 */
238
239/*
240 * CPU例外ハンドラ
241 */
242ID cpuexc_tskid; /* CPU例外を起こしたタスクのID */
243
244#ifdef CPUEXC1
245
246void
247eiCpuExceptionHandler_main(const void *p_excinf)
248{
249
250 syslog(LOG_NOTICE, "CPU exception handler (p_excinf = %08p).", p_excinf);
251 if (ciKernel_senseContext() != true) {
252 syslog(LOG_WARNING, "ciKernel_senseContext() is not true"
253 " in CPU exception handler.");
254 }
255 if (ciKernel_senseDispatchPendingState() != true) {
256 syslog(LOG_WARNING, "ciKernel_senseDispatchPendingState() is not true"
257 " in CPU exception handler.");
258 }
259 syslog(LOG_INFO, "ciKernel_senseLock() = %d, ciKernel_senseDispatch() = %d",
260 ciKernel_senseLock(), ciKernel_senseDispatch());
261 syslog(LOG_INFO, "ciKernel_exceptionSenseDispatchPendingState() = %d",
262 ciKernel_exceptionSenseDispatchPendingState(p_excinf));
263
264 if (ciKernel_exceptionSenseDispatchPendingState(p_excinf)) {
265 syslog(LOG_NOTICE, "Sample program ends with exception.");
266 SVC_PERROR(ciKernel_exitKernel());
267 assert(0);
268 }
269
270 SVC_PERROR(ciKernel_getTaskId(&cpuexc_tskid));
271 cExceptionTask_activate();
272}
273
274#endif /* CPUEXC1 */
275
276/*
277 * 周期ハンドラ
278 *
279 * HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY の各優先度のレディキュー
280 * を回転させる.
281 */
282void
283eiCyclicHandler_main(void)
284{
285 SVC_PERROR(ciKernel_rotateReadyQueue(HIGH_PRIORITY));
286 SVC_PERROR(ciKernel_rotateReadyQueue(MID_PRIORITY));
287 SVC_PERROR(ciKernel_rotateReadyQueue(LOW_PRIORITY));
288}
289
290/*
291 * アラームハンドラ
292 *
293 * HIGH_PRIORITY,MID_PRIORITY,LOW_PRIORITY の各優先度のレディキュー
294 * を回転させる.
295 */
296void
297eiAlarmHandler_main(void)
298{
299 SVC_PERROR(ciKernel_rotateReadyQueue(HIGH_PRIORITY));
300 SVC_PERROR(ciKernel_rotateReadyQueue(MID_PRIORITY));
301 SVC_PERROR(ciKernel_rotateReadyQueue(LOW_PRIORITY));
302}
303
304/*
305 * 例外処理タスク
306 */
307void
308eExceptionTask_main(void)
309{
310 SVC_PERROR(ras_ter(cpuexc_tskid));
311}
312
313/*
314 * メインタスク
315 */
316void
317eMainTask_main(void)
318{
319 char c;
320 int_t tskno = 1;
321 ER_UINT ercd;
322 PRI tskpri;
323#ifndef TASK_LOOP
324 SYSTIM stime1, stime2;
325#endif /* TASK_LOOP */
326 HRTCNT hrtcnt1, hrtcnt2;
327
328 SVC_PERROR(cSysLog_mask(LOG_UPTO(LOG_INFO), LOG_UPTO(LOG_EMERG)));
329 syslog(LOG_NOTICE, "Sample program starts.");
330
331 /*
332 * シリアルポートの初期化
333 *
334 * システムログタスクと同じシリアルポートを使う場合など,シリアル
335 * ポートがオープン済みの場合にはここでE_OBJエラーになるが,支障は
336 * ない.
337 */
338 ercd = cSerialPort_open();
339 if (ercd < 0 && MERCD(ercd) != E_OBJ) {
340 syslog(LOG_ERROR, "%s (%d) reported by `cSerialPort_open'.",
341 itron_strerror(ercd), SERCD(ercd));
342 }
343 SVC_PERROR(cSerialPort_control(IOCTL_CRLF | IOCTL_FCSND | IOCTL_FCRCV));
344
345 /*
346 * ループ回数の設定
347 *
348 * 並行実行されるタスク内でのループの回数(task_loop)は,ループ
349 * の実行時間が約0.4秒になるように設定する.この設定のために,
350 * LOOP_REF回のループの実行時間を,その前後でgetTimeを呼ぶことで
351 * 測定し,その測定結果から空ループの実行時間が0.4秒になるループ
352 * 回数を求め,task_loopに設定する.
353 *
354 * LOOP_REFは,デフォルトでは1,000,000に設定しているが,想定した
355 * より遅いプロセッサでは,サンプルプログラムの実行開始に時間がか
356 * かりすぎるという問題を生じる.逆に想定したより速いプロセッサで
357 * は,LOOP_REF回のループの実行時間が短くなり,task_loopに設定す
358 * る値の誤差が大きくなるという問題がある.そこで,そのようなター
359 * ゲットでは,target_test.hで,LOOP_REFを適切な値に定義すること
360 * とする.
361 *
362 * また,task_loopの値を固定したい場合には,その値をTASK_LOOPにマ
363 * クロ定義する.TASK_LOOPがマクロ定義されている場合,上記の測定
364 * を行わずに,TASK_LOOPに定義された値をループの回数とする.
365 *
366 * ターゲットによっては,ループの実行時間の1回目の測定で,本来より
367 * も長めになるものがある.このようなターゲットでは,MEASURE_TWICE
368 * をマクロ定義することで,1回目の測定結果を捨てて,2回目の測定結
369 * 果を使う.
370 */
371#ifdef TASK_LOOP
372 task_loop = TASK_LOOP;
373#else /* TASK_LOOP */
374
375#ifdef MEASURE_TWICE
376 SVC_PERROR(getTime(&stime1));
377 consume_time(LOOP_REF);
378 SVC_PERROR(getTime(&stime2));
379#endif /* MEASURE_TWICE */
380
381 SVC_PERROR(getTime(&stime1));
382 consume_time(LOOP_REF);
383 SVC_PERROR(getTime(&stime2));
384 task_loop = LOOP_REF * 400LU / (ulong_t)(stime2 - stime1) * 1000LU;
385
386#endif /* TASK_LOOP */
387
388 /*
389 * タスクの起動
390 */
391 SVC_PERROR(cTask_activate(1));
392 SVC_PERROR(cTask_activate(2));
393 SVC_PERROR(cTask_activate(3));
394
395 /*
396 * メインループ
397 */
398 do {
399 SVC_PERROR(cSerialPort_read(&c, 1));
400 switch (c) {
401 case 'e':
402 case 's':
403 case 'S':
404 case 'd':
405 case 'y':
406 case 'Y':
407 case 'z':
408 case 'Z':
409 message[tskno-1] = c;
410 break;
411 case '1':
412 tskno = 1;
413 break;
414 case '2':
415 tskno = 2;
416 break;
417 case '3':
418 tskno = 3;
419 break;
420 case 'a':
421 syslog(LOG_INFO, "#cTask_activate(%d)", tskno);
422 SVC_PERROR(cTask_activate(tskno));
423 break;
424 case 'A':
425 syslog(LOG_INFO, "#cTask_cancelActivate(%d)", tskno);
426 SVC_PERROR(ercd = cTask_cancelActivate(tskno));
427 if (ercd >= 0) {
428 syslog(LOG_NOTICE, "cTask_cancelActivate(%d) returns %d",
429 tskno, ercd);
430 }
431 break;
432 case 't':
433 syslog(LOG_INFO, "#cTask_terminate(%d)", tskno);
434 SVC_PERROR(cTask_terminate(tskno));
435 break;
436 case '>':
437 syslog(LOG_INFO, "#cTask_changePriority(%d, HIGH_PRIORITY)", tskno);
438 SVC_PERROR(cTask_changePriority(tskno, HIGH_PRIORITY));
439 break;
440 case '=':
441 syslog(LOG_INFO, "#cTask_changePriority(%d, MID_PRIORITY)", tskno);
442 SVC_PERROR(cTask_changePriority(tskno, MID_PRIORITY));
443 break;
444 case '<':
445 syslog(LOG_INFO, "#(cTask_changePriority(%d, LOW_PRIORITY)", tskno);
446 SVC_PERROR(cTask_changePriority(tskno, LOW_PRIORITY));
447 break;
448 case 'G':
449 syslog(LOG_INFO, "#cTask_getPriority(%d, &tskpri)", tskno);
450 SVC_PERROR(ercd = cTask_getPriority(tskno, &tskpri));
451 if (ercd >= 0) {
452 syslog(LOG_NOTICE, "priority of task %d is %d", tskno, tskpri);
453 }
454 break;
455 case 'w':
456 syslog(LOG_INFO, "#cTask_wakeup(%d)", tskno);
457 SVC_PERROR(cTask_wakeup(tskno));
458 break;
459 case 'W':
460 syslog(LOG_INFO, "#cTask_cancelWakeup(%d)", tskno);
461 SVC_PERROR(ercd = cTask_cancelWakeup(tskno));
462 if (ercd >= 0) {
463 syslog(LOG_NOTICE, "cTask_cancelWakeup(%d) returns %d",
464 tskno, ercd);
465 }
466 break;
467 case 'l':
468 syslog(LOG_INFO, "#cTask_releaseWait(%d)", tskno);
469 SVC_PERROR(cTask_releaseWait(tskno));
470 break;
471 case 'u':
472 syslog(LOG_INFO, "#cTask_suspend(%d)", tskno);
473 SVC_PERROR(cTask_suspend(tskno));
474 break;
475 case 'm':
476 syslog(LOG_INFO, "#cTask_resume(%d)", tskno);
477 SVC_PERROR(cTask_resume(tskno));
478 break;
479 case 'x':
480 syslog(LOG_INFO, "#cTask_raiseTerminate(%d)", tskno);
481 SVC_PERROR(cTask_raiseTerminate(tskno));
482 break;
483 case 'X':
484 syslog(LOG_INFO, "#cTask_raiseTerminate(%d)", tskno);
485 SVC_PERROR(cTask_raiseTerminate(tskno));
486 break;
487 case 'r':
488 syslog(LOG_INFO, "#rotateReadyQueue(three priorities)");
489 SVC_PERROR(rotateReadyQueue(HIGH_PRIORITY));
490 SVC_PERROR(rotateReadyQueue(MID_PRIORITY));
491 SVC_PERROR(rotateReadyQueue(LOW_PRIORITY));
492 break;
493 case 'c':
494 syslog(LOG_INFO, "#cCyclic_start()");
495 SVC_PERROR(cCyclic_start());
496 break;
497 case 'C':
498 syslog(LOG_INFO, "#cCyclic_stop()");
499 SVC_PERROR(cCyclic_stop());
500 break;
501 case 'b':
502 syslog(LOG_INFO, "#cAlarm_start(5000000)");
503 SVC_PERROR(cAlarm_start(5000000));
504 break;
505 case 'B':
506 syslog(LOG_INFO, "#cAlarm_stop()");
507 SVC_PERROR(cAlarm_stop());
508 break;
509
510 case 'V':
511 hrtcnt1 = fetchHighResolutionTimer();
512 consume_time(1000LU);
513 hrtcnt2 = fetchHighResolutionTimer();
514 syslog(LOG_NOTICE, "hrtcnt1 = %tu, hrtcnt2 = %tu",
515 (uint32_t) hrtcnt1, (uint32_t) hrtcnt2);
516 break;
517
518 case 'v':
519 SVC_PERROR(cSysLog_mask(LOG_UPTO(LOG_INFO),
520 LOG_UPTO(LOG_EMERG)));
521 break;
522 case 'q':
523 SVC_PERROR(cSysLog_mask(LOG_UPTO(LOG_NOTICE),
524 LOG_UPTO(LOG_EMERG)));
525 break;
526
527 case '\003':
528 case 'Q':
529 break;
530
531 default:
532 syslog(LOG_INFO, "Unknown command: '%c'.", c);
533 break;
534 }
535 } while (c != '\003' && c != 'Q');
536
537 syslog(LOG_NOTICE, "Sample program ends.");
538 SVC_PERROR(exitKernel());
539 assert(0);
540}
Note: See TracBrowser for help on using the repository browser.