#ifndef _WIN32 #pragma section @@CODE ROM_CODE #pragma nop #pragma ei #pragma di #pragma sfr #endif #ifdef _WIN32 typedef unsigned char bit; typedef unsigned char u8; #endif /****************************************************************************** タスクシステム? なるほど、iTRONにはコンフィギュレータがあるはずだ。 →作りました ctr_mcu_config.rb 参照。 task_config.hが作成されます。 *****************************************************************************/ #include "renge.h" #include "renge_task_intval.h" #include "renge_task_immediate.h" #include "..\WDT.h" #include "..\config.h" #include "..\user_define.h" #include "..\util_funcs.h" #ifdef _WIN32 #include "../sim/simOnWin.h" #endif //#define _renge_test_ #define true 1 #define false 0 //****************************************************************************** u8 renge_flg_interval; bit renge_task_interval_run_force; bit renge_task_immediate_not_empty; #include "..\bsr_system.h" extern system_status_ system_status; //****************************************************************************** static void renge_task_immed_init(); static void renge_task_immed_del(); //****************************************************************************** task_status_immed ( *tasks_immed[ TASK_IMMED_RUN_LIST_MAX ] )(); /****************************************************************************** 初期化 ・タスクシステムの動的部分の初期化 ・インターバルタイマ *****************************************************************************/ void renge_init(){ renge_task_immed_init(); /* イベントタイマのセットなど 今回はRTCを流用しているのでコメントアウト #define renge_tick 19xxxxxxx [ms] renge_interval_init(); → RTC_init(); */ } /****************************************************************************** システムチックを進める *****************************************************************************/ /* void renge_interval(){ // RTCがやってくれる →__interrupt void int_rtc_int(); } */ /****************************************************************************** コンパイル時に決まっている、インターバル起動のタスク そのうち、逐次起動と混ぜるかもしれない。 *****************************************************************************/ __callt err renge_task_interval_run(){ u8 i; // インターバル起動 DI_wt_chk(); if(( renge_flg_interval != 0 ) || ( renge_task_interval_run_force )) /// 統合したかったな… { renge_task_interval_run_force = false; // 今から起動するタスク、割り込むタスクでフラグが立つかもなので if( renge_flg_interval != 0 ) { renge_flg_interval --; WDT_Restart( ); } EI(); for( i = 0; i != TSK_LAST; i ++ ) { tasks[ i ](); // 逐次起動タスクがあったら間に挟む renge_task_immed_run(); } } EI(); return( ERR_SUCCESS ); } /***************************************************************************** ■逐一起動タスク■ ●task_immed を返す関数。 ●システムtick、何らかの割り込み(I2C通信完了など)で スリープから復帰したタイミングで実行されます。 ■返値 TSKI_FINISHED タスクを削除     それ以外 次のタイミングでまた実行 *****************************************************************************/ /************************************** **************************************/ void renge_task_immed_init(){ u8 i; for( i = 0; i < TASK_IMMED_RUN_LIST_MAX; i++ ){ tasks_immed[ i ] = TSK_IMM_EMPTY_; } } /************************************** 逐次実行タスクの登録 割り込み禁止 36us → **************************************/ __callt err renge_task_immed_add( task_status_immed (*new_task)() ){ u8 i; // リストの空きの先頭に登録 // 削除したばかりのタスクは、削除マーク(TSK_IMM_DELETED_)となり、空きとは明示的に区別される // 重複登録を避ける for( i = 0; i < TASK_IMMED_RUN_LIST_MAX; i ++ ) { DI_wt_chk(); if( tasks_immed[ i ] == TSK_IMM_EMPTY_ ) { // 空きを見つけた tasks_immed[ i ] = new_task; EI(); return( ERR_SUCCESS ); } else { // 重複登録チェック /// 歯抜けになってない、前詰めされてる前提 if( tasks_immed[ i ] == new_task ) { // 重複登録はしない EI(); return( ERR_ERR ); } } EI(); } // タスク登録しすぎ(無いはず return( ERR_ERR ); } /************************************** 逐次実行タスクの実行 **************************************/ __callt err renge_task_immed_run(){ u8 list_id; // while( tasks_immed[ 0 ] != TSK_IMM_EMPTY_ ) if( tasks_immed[ 0 ] != TSK_IMM_EMPTY_ ) { DI_wt_chk(); for( list_id = 0; list_id < TASK_IMMED_RUN_LIST_MAX; list_id ++ ){ if( tasks_immed[ list_id ] == TSK_IMM_EMPTY_ ){ // リスト完了 EI(); break; } #ifdef _renge_test_ else if( tasks_immed[ list_id ] == TSK_IMM_DELETED_ ) { EI(); NOP(); // タスク管理の不備 // 存在しないタスクを実行しようとした // タスクの削除後の処理がまずい // 予期しないタイミングで immed_run が呼ばれた } #endif else { u8 rv; EI(); rv = tasks_immed[ list_id ](); // タスク実行 if( rv == ERR_SUCCESS ) { tasks_immed[ list_id ] = TSK_IMM_DELETED_; } // きわどいタイミングで同じタスクの登録があると困るのでDI状態でかえって来る事がある } DI_wt_chk(); } // リスト上のタスクを一通り実行した // タスク削除 // { u8 i = 0; // リストの並べ替え先 u8 j = 1; // 必ず i < j、j < TASK_IMMED_RUN_LIST_MAX (でないとタスクあふれ) while( 1 ) { if( tasks_immed[ i ] == TSK_IMM_EMPTY_ ) { // 前詰め完了 && リスト空っぽ // break; goto imm_list_sort_fin; } else if( tasks_immed[ i ] == TSK_IMM_DELETED_ ) { for( ; j < TASK_IMMED_RUN_LIST_MAX; j++ ) { if( tasks_immed[ j ] == TSK_IMM_DELETED_ ) { // 隣(?)も削除対象だった // next j } else { DI_wt_chk(); if( tasks_immed[ j ] == TSK_IMM_EMPTY_ ) { do{ j --; tasks_immed[ j ] = TSK_IMM_EMPTY_; // リスト前詰め完了 }while( i < j ); EI(); goto imm_list_sort_fin; } else { // 前詰めすべきタスクを見つけた tasks_immed[ i ] = tasks_immed[ j ]; tasks_immed[ j ] = TSK_IMM_DELETED_; i ++; EI(); } } } } else { // このタスク、滞留 } i ++; } } } imm_list_sort_fin: // ここまでで完全に前詰めされている #ifdef _renge_test_ /// ほんと? { u8 a,b; a = 0; for( b = 0 ; b < TASK_IMMED_RUN_LIST_MAX; b++ ) { if( tasks_immed[ b ] == TSK_IMM_EMPTY_ ) { a = 1; } else { if( a != 0 ) { NOP(); // EMPTYより後ろにタスクやdeletedが有る } } } } #else NOP(); // なんか無いとリンカが怒る #endif // } return( ERR_SUCCESS ); }