﻿/* RTP_sp_6-2 */
/*
 *  セマフォによる排他制御
 *
 *  OS: T-Kernel
 *
 */

#include <tk/tkernel.h> /* T-Kernel ヘッダ */
#include <tk/sysdef.h>  /* ハードウェア定義 */
#include <trace/trace.h> /* タスクトレーサ */

/* オブジェクト ID 番号 */
LOCAL ID semid; /* セマフォの ID */
LOCAL ID tidA;  /* タスク A の ID */
LOCAL ID tidB;  /* タスク B の ID */
LOCAL ID tidC;  /* タスク C の ID */

/* LED に出力するように設定する */
LOCAL void init_led(void)
{
    PIO_IE(F)   &= ~(1 << 3); /* LED3 (PF3) */
    PIO_CR(F)   |=  (1 << 3);
    PIO_DATA(F) |=  (1 << 3); /* 消灯 */
    PIO_IE(B)   &= ~(1 << 0); /* LED4 (PB0) */
    PIO_CR(B)   |=  (1 << 0);
    PIO_DATA(B) |=  (1 << 0); /* 消灯 */
    PIO_IE(H)   &= ~(1 << 1); /* D2 (PH1) */
    PIO_CR(H)   |=  (1 << 1);
    PIO_DATA(H) |=  (1 << 1); /* 消灯 */
}

/* n 番めの LED を点灯(v=1),消灯(v=0)する */
LOCAL void set_led(INT n, INT v)
{
    switch (n) {
    case 1: /* LED3 (PF3) */
        if (v) PIO_DATA(F) &= ~(1 << 3); /* 点灯 */
        else   PIO_DATA(F) |=  (1 << 3); /* 消灯 */
        break;
    case 2: /* LED4 (PB0) */
        if (v) PIO_DATA(B) &= ~(1 << 0); /* 点灯 */
        else   PIO_DATA(B) |=  (1 << 0); /* 消灯 */
        break;
    case 3: /* D2 (PH1) */
        if (v) PIO_DATA(H) &= ~(1 << 1); /* 点灯 */
        else   PIO_DATA(H) |=  (1 << 1); /* 消灯 */
        break;
    }
}

/* 排他制御が必要な関数 : n 番めの LED を 200ms 点灯する */
LOCAL void f(INT n)
{
    /* セマフォから資源獲得待ち */
    tk_wai_sem(semid, 1, TMO_FEVR);

    /* n 番めの LED を点灯する */
    set_led(n, 1);

    tk_dly_tsk(200); /* 200ms ディレイする */

    /* n 番めの LED を消灯する */
    set_led(n, 0);

    /* セマフォに資源返却する */
    tk_sig_sem(semid, 1);
}

/* タスク A */
LOCAL void taskA(INT stacd, void *exinf)
{
    tk_sta_tsk(tidB, 0); /* タスク B を起動 */
    tk_sta_tsk(tidC, 0); /* タスク C を起動 */

    /* 関数 f を呼ぶ */
    f(1);

    /* 自タスクを終了・削除する */
    tk_exd_tsk();
}

/* タスク B */
LOCAL void taskB(INT stacd, void *exinf)
{
    /* 関数 f を呼ぶ */
    f(2);

    /* 自タスクを終了・削除する */
    tk_exd_tsk();
}

/* タスク C */
LOCAL void taskC(INT stacd, void *exinf)
{
    /* 関数 f を呼ぶ */
    f(3);

    /* 自タスクを終了・削除する */
    tk_exd_tsk();
}

/* 初期化処理 */
EXPORT INT usermain(void)
{
    ER     er;
    T_CSEM cs;
    T_CTSK ct;

    /* セマフォを生成する */
    cs.exinf = 0;                    /* 拡張情報 */
    cs.sematr = TA_TFIFO | TA_FIRST; /* セマフォ属性 */
    cs.isemcnt = 1;                  /* セマフォの初期値 */
    cs.maxsem = 1;                   /* セマフォの最大値 */
    semid = tk_cre_sem(&cs);
    if (semid < E_OK) { er = semid; goto e4; }

    /* タスク A を生成する */
    ct.exinf = (void*)('t' | 's' << 8 | 'k' << 16 | 'A' << 24); /* 拡張情報 */
    ct.tskatr = TA_HLNG | TA_RNG0;  /* タスク属性 */
    ct.task = taskA;                /* タスク起動アドレス */
    ct.itskpri = 1;                 /* タスク起動時優先度 */
    ct.stksz = 1024;                /* スタックサイズ */
    tidA = tk_cre_tsk(&ct);         /* タスク A を生成 */
    if (tidA < E_OK) { er = tidA; goto e3; } /* タスク生成失敗時 */

    /* タスク B を生成する */
    ct.exinf = (void*)('t' | 's' << 8 | 'k' << 16 | 'B' << 24); /* 拡張情報 */
    ct.tskatr = TA_HLNG | TA_RNG0;  /* タスク属性 */
    ct.task = taskB;                /* タスク起動アドレス */
    ct.itskpri = 1;                 /* タスク起動時優先度 */
    ct.stksz = 1024;                /* スタックサイズ */
    tidB = tk_cre_tsk(&ct);         /* タスク B を生成 */
    if (tidB < E_OK) { er = tidB; goto e2; } /* タスク生成失敗時 */

    /* タスク C を生成する */
    ct.exinf = (void*)('t' | 's' << 8 | 'k' << 16 | 'C' << 24); /* 拡張情報 */
    ct.tskatr = TA_HLNG | TA_RNG0;  /* タスク属性 */
    ct.task = taskC;                /* タスク起動アドレス */
    ct.itskpri = 1;                 /* タスク起動時優先度 */
    ct.stksz = 1024;                /* スタックサイズ */
    tidC = tk_cre_tsk(&ct);         /* タスク C を生成 */
    if (tidC < E_OK) { er = tidC; goto e1; } /* タスク生成失敗時 */

    init_led(); /* LED に出力するように設定する */

    tk_sta_tsk(tidA, 0);            /* タスク A を起動 */

    return E_OK;

e1: tk_del_tsk(tidB);
e2: tk_del_tsk(tidA);
e3: tk_del_sem(semid);
e4: return er;
}
