Windowsシミュレータで学ぶuITRON (2) - イベントフラグ

# はじめに

**uITRON（FreeRTOSベース）Windowsシミュレータ - Qiita**
https://qiita.com/imagou/items/42c687402e6e58fccddb

今回のお題は、何かあったことを伝える**イベントフラグ**です。

# 本編

## 1. 環境

[こちらの記事](https://qiita.com/imagou/items/42c687402e6e58fccddb#1-1-%E7%92%B0%E5%A2%83)を参照ください。

## 2. 動かしてみる

こちらは[初回記事](https://qiita.com/imagou/items/de102b81d0049b819532#2-%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B)を参照。

### 2-1. タスクでのイベント設定・待ち

改めて[**「2-2. 送信タスク・受信タスク」**](https://qiita.com/imagou/items/de102b81d0049b819532#2-2-%E9%80%81%E4%BF%A1%E3%82%BF%E3%82%B9%E3%82%AF%E5%8F%97%E4%BF%A1%E3%82%BF%E3%82%B9%E3%82%AF)の動作を確認してください。

### 2-2. 割り込みでのイベント設定

次にコンソールで「cyclic」と入力してみます。

```Console
[TimerTask]: DELAY 3000ms
cyclic
[SendTask]: RECV EVENT (00000001)
[SendTask]: Cyclic Timer Expired (1)
[TimerTask]: DELAY 3000ms
[SendTask]: RECV EVENT (00000001)
[SendTask]: Cyclic Timer Expired (2)
[SendTask]: RECV EVENT (00000001)
[SendTask]: Cyclic Timer Expired (3)
[SendTask]: RECV EVENT (00000001)
[SendTask]: Cyclic Timer Expired (4)
[TimerTask]: DELAY 3000ms
[SendTask]: RECV EVENT (00000001)
[SendTask]: Cyclic Timer Expired (5)
```
どうやら、1000msecおきに「Cyclic Timer Expired」が発生するようになったようです。

## 3. 解説

### 3-1. 概要

イベントフラグとは、前述したように**「何かが発生したことを伝える仕組み」**です。

型は32-bitであり、それぞれのビットにイベントを割り当てることができます。

### 3-2. コードによる説明

以降は、プログラムコード - `main.c`を引用して説明します。

#### 3-2-1. イベント定義

イベントの定義は以下。

```C
/*--- Event ---*/
#define EVENT_ALL       (0x00FFFFFF)    /* FreeRTOS仕様制限で、最大で24-bit */
#define EVENT_CYCLIC    (0x00000001)
/* Reserved bit1 - bit15 */
#define EVENT_STOP      (0x00010000)
#define EVENT_RESTART   (0x00020000)
```

コメントにあるように、FreeRTOS制限で24-bitしか使えないのですが（笑）、日本語で書くと以下の割り当てとなっています。

|bit|説明|
|---|---|
|bit0|CYCLICイベント（周期タイマを開始するイベント）|
|bit1 - bit15|予約（数値を通知するイベント）|
|bit16|停止イベント|
|bit17|再開イベント|

#### 3-2-2. イベントフラグ生成

`cre_flg()`で生成します。

```C
    T_CFLG cflg;
    cflg.flgatr = TA_WSGL;
    cflg.iflgptn = 0;
    cre_flg(FLAG_ID(SEND), &cflg);
```

`cre_flg()`のパラメータは下表：

|パラメータ番号|名称|説明|
|---|---|---|
|第1パラメータ|イベントフラグID|単なるID。<br>以降はこのIDでもってイベントフラグ設定・待ちを実施。|
|第2パラメータ|T_CFLG構造体変数|以下で説明|

T_CFLGのメンバは下表：

|名称|指定可能な値|説明|
|---|---|---|
|flgatr|TA_WSGL &#124; TA_WMUL|イベントフラグ属性。<br>それぞれ、1つのタスクで待つか・複数のタスクで待つか。<br>たいていの場合はTA_WSGLでよい。|
|iflgptn|イベントフラグ初期値|左記の通り。たいていの場合は0でよいだろう。|

**※なお、flgatrはこれ以外の値も指定可能（だが、TA_WSGLで必要十分と考える）。**

#### 3-2-3. イベントフラグ設定

通常のタスクでは`set_flg()`を使います。

```C
        /* Numeric Event (1 To 15) */
        if ((0 < num) && (num < 16)) {
            set_flg(FLAG_ID(SEND), (1 << num));
        }
#define EQUALS_(x) (0 == strcmp(str, #x))
        /* Suspend */
        else if (EQUALS_(stop)) {
            set_flg(FLAG_ID(SEND), EVENT_STOP);
        }
        /* Resume */
        else if (EQUALS_(start)) {
            set_flg(FLAG_ID(SEND), EVENT_RESTART);
        }
```

上記コードでは、以下のイベントを設定しています：

- 数値が指定されたら、対応するビットを立てたイベント
- 「stop」「start」が指定されたら、それぞれ停止・再開イベント

対して、割り込みでは`iset_flg()`を用います。

```C
static void UserCyclicHandler(void* params)
{
    /* Just to remove compiler warning. */
    (void)params;

    iset_flg(FLAG_ID(SEND), EVENT_CYCLIC);
}
```

こちらは、CYCLICイベントを設定しています。


#### 3-2-4. イベント待ち

`wai_flg()`を使用します。

```C
        FLGPTN flgptn;
        wai_flg(FLAG_ID(SEND), EVENT_ALL, TWF_ORW, &flgptn);
        DEBUG_PRINT("[%s]: RECV EVENT (%08X)", __func__, flgptn);

        /* Suspend Task */
        if (flgptn & EVENT_STOP) {
            sus_tsk(TASK_ID(RECV));
            continue;
        }
        /* Resume Task */
        if (flgptn & EVENT_RESTART) {
            rsm_tsk(TASK_ID(RECV));
            continue;
        }

        /* Cyclic Event */
        if (flgptn & EVENT_CYCLIC) {
            static int32_t expired = 0;
            DEBUG_PRINT("[%s]: Cyclic Timer Expired (%d)", __func__, ++expired);
            continue;
        }
```

`wai_flg()`のパラメータで重要なものは以下：

|パラメータ番号|指定可能な値|説明|
|---|---|---|
|第2パラメータ|待ち合わせるビットパターン|本デモではすべてのビットを指定|
|第3パラメータ|TWF_ANDW / TWF_ORW|指定したビットがすべて立つまで待つ / いずれか1つが立つまで待つ|
|第4パラメータ|受信したビットパターン||

第4パラメータ`flgptn`でもって、それ以降の判定を実施しています。

また、数値用イベントのコードは抜粋していませんので、コードを直接参照ください（雑）。

### 3-3. TBD

TBD（今後追加していく予定）

# おわりに

1ビットだけでは情報が足りない場合は、メールボックス（メッセージ）を使いましょう（次回への伏線）。

# 参考

**Micro-ITRON4.0 Specification (in Japanese)**
http://www.ertl.jp/ITRON/SPEC/mitron4-j.html