﻿/*
 *  UDP クライアントによるスイッチの状態通知
 *
 *  OS: T-Kernel
 *
 */

#include <tk/tkernel.h>  /* T-Kernel ヘッダ */
#include <tk/sysdef.h>   /* ハードウェア定義 */
#include <tm/tmonitor.h> /* tm_printf() など */
#include <libstr.h>      /* memcpy() など */
#include <utkn/utkn.h>   /* 6LoWPAN */

/* オブジェクト ID 番号 */
LOCAL ID tidA;           /* タスク A の ID */

/* スイッチから入力するように設定する */
LOCAL void init_sw(void)
{
    PIO_CR(A) &= ~(1 << 3); PIO_IE(A) |= (1 << 3); /* SW3 (PA3) */
    PIO_CR(E) &= ~(1 << 7); PIO_IE(E) |= (1 << 7); /* SW4 (PE7) */
}

/* スイッチの状態を読み込む */
/* n: スイッチ番号 (3, 4) */
/* 戻値: 0:押されていない, 1:押されている */
LOCAL INT get_sw(INT n)
{
    switch (n) {
    case 3: /* SW3 (PA3) */
        return (PIO_DATA(A) & (1 << 3)) == 0;
    case 4: /* SW4 (PE7) */
        return (PIO_DATA(E) & (1 << 7)) == 0;
    }
    return 0;
}

/* タスク A */
LOCAL void taskA(INT stacd, void *exinf)
{
    static const utkn_6ln_init_t param = {
        .channel = RF_CHANNEL_ANY,
        .scan_type = WPAN_SCAN_ACTIVE,
        .scan_duration = 4,
        .options = 0,
        .tmout = TMO_FEVR,
    };
    static const udp6_cep_t dst = {
        .addr = {{0x20, 0x01, 0x0d, 0xb8,
                  0x00, 0x00, 0x00, 0x00,
                  0xb0, 0xe7, 0x41, 0xb7,
                  0xb6, 0xc0, 0x36, 0xf7, /* UDP サーバの IPv6 アドレス */
            }},
        .port = htons(9000), /* UDP サーバのポート番号 */
    };
    static udp6_cep_t cep;
    ID cepid;
    INT len, n;
    static UB buf[16];

    /* 6LoWPAN プロトコルスタックを初期化する */
    utkn_6ln_init(&param);

    /* UDP 通信端点をオープンする */
    cep.addr = ip6_addr_unspec;
    cep.port = UDP6_PORT_ANY;
    cepid = udp6_open(&cep);

    init_sw(); /* スイッチから入力するように設定する */

    for (;; tk_dly_tsk(1000)) {
        for (n = 3; n <= 4; n++) {
            /* UDP 送信する */
            /* sw3,4=0,1 */
            len = 5;
            memcpy(buf, "sw3=0", len);
            buf[2] = n + '0';
            buf[4] = get_sw(n) + '0';
            udp6_send(cepid, buf, len, &dst, 5000);
            tm_printf((UB*)"%.*s\n", len, buf);

            /* UDP 受信する */
            udp6_recv(cepid, buf, sizeof(buf), NULL, NULL, NULL, 5000);
        }
    }

    /* このタスクは終了しない */
}

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

    /* タスク 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) return tidA;   /* タスク生成失敗時 */

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

    return E_OK;
}
