/*
 * Copyright (C) 2007 Speecys Corporation
 *		Toshiaki Nozawa <nozawa@speecys.com>
 * All rights reserved.
 *
 * exec: > env LD_LIBRARY_PATH=.. ./cutcheck
 */

#include <cut-2/cut.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <err.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <assert.h>
#include <netinet/in.h>
#include <math.h>
#include <stdbool.h>
#include <errno.h>

#include "../libled.h"
#include "../scifTrafMain.h"
#include "../libutil.h"
#include "clientUtil.h"

/*
 * static scope variable
 */
static int sock;
static int seqTx;
static int seqRx = 0;

#ifdef STOP_LED_SWITCH_STATE_READ_ON_SERVER
static int serialP;
#endif


/*
 * static scope function prototype
 */
static void respDevStsDump(const struct devStsElm *elm);
static void headerChk(const struct cmnHeader *hd, u_int seq,
    enum e_Priority pri, enum e_RespCat cat, u_int datLen);
static void nackChk(const struct cmnHeader *hd, const char *buf, u_int seq,
    enum e_Priority pri, const char *reason);


/*
 *
 */
void __CUT_BRINGUP__scifTrafMain(void)
{
    printf("\n%s start\n", __func__);
#ifdef STOP_LED_SWITCH_STATE_READ_ON_SERVER
    const char *dev = "/dev/cuaU1";
#endif
    ASSERT((sock = open_cli_sock("rpu50", "6809")) >= 0, "cli_sock()");
    seqTx = seqTx + sock * 10;	/** can start any number	*/

#ifdef STOP_LED_SWITCH_STATE_READ_ON_SERVER
    // monitoring serial port open & config
    // see tty(4), tcsetattr(3)
    PERR_CHK((serialP = open(dev, O_RDWR)), < 0);
    struct termios term;
    PERR_CHK(ioctl(serialP, TIOCGETA, &term), == -1);
    PERR_CHK(cfsetspeed(&term, B115200),  == -1);
    cfmakeraw(&term);
    PERR_CHK(ioctl(serialP, TIOCSETA, &term), == -1);
#endif
}

void __CUT__ReqOnce_SOUND(void)
{
    printf("\n%s start\n", __func__);
    const char *fn = "/etc/local/bid/2_reconfirm.raw";
    unsigned char reqbuf[strlen(fn) + sizeof(struct reqOnce)];
    struct reqOnce *reqP = (struct reqOnce *)reqbuf;


    /** immediate request(one shoot)	*/
    reqP->flg = FLG_SOUND_REQ;
    memcpy(reqP->cmd, fn, strlen(fn));
    ASSERT(writeReqOncePacket(sock, seqTx++, true, CmnHF_noFlg
	, reqP, strlen(fn), true) > 0 , "SOUND immediate request packet send");

    struct cmnHeader hd;
    char buf[256];
    struct iovec rdBuf[] = {
	[PcHdr] = {&hd , sizeof hd},
	[PcData] = {buf, sizeof buf}
	/**
	 * 'sizeof buf' is temporary but necessary in readPacket(),
	 * will over write in readPacket()
	 */
    };
    readPacket(sock, rdBuf, true, true);
    headerChk(&hd, seqTx - 1, PrioReqOnce, RespAck, 0);

    rdBuf[PcData].iov_len = sizeof buf;
    readPacket(sock, rdBuf, true, true);
    headerChk(&hd, seqRx++, PrioReqOnce, RespEndOfReqOnce, 0);
}

void __CUT__ReqCmd_ledFix(void)
{
    printf("\n%s start\n", __func__);
    int seqTxAtStart = seqTx;

    for (int flg = 0; flg < 2; flg++) {
	for (enum e_ledPattern pat = BLANK; pat < NUM_e_ledPattern; pat++) {
	    int pri = pat % NUM_e_Priority;
	    if (flg == 1 && pri == PrioReqOnce)
		pri++;	// disable PrioReqOnce at flg == 1
	    struct reqCmd req = {
		.cmd =	ledDisp,
		.id =	rs485ID_LED_BREST,
		.arg.arg32_t = (u_long)pat
	    };

	    ASSERT(writeReqCmdPacket(sock, seqTx++, pri
		, (flg == 0) ? 0 : 1 << (flg - 1), &req, true) > 0
		, "ReqCmd ledDisp packet send");


	    /** recv acknowledge check	*/
	    /** read one packet	*/
	    struct cmnHeader hd;
	    char buf[256];
	    struct iovec rdBuf[] = {
		[PcHdr] = {&hd , sizeof hd},
		[PcData] = {buf, sizeof buf}
		/**
		 * 'sizeof buf' is temporary but necessary in readPacket(),
		 * will over write in readPacket()
		 */
	    };

	    /**
	     * non-block read
	     */
	    if (flg != 1) {
		while(readPacket(sock, rdBuf, true, false) < 0
		    && errno == EAGAIN)
		{
		    usleep(100);
		}

		if (pri != PrioReqOnce) {
		    headerChk(&hd, seqTxAtStart + flg * NUM_e_ledPattern + pat
			, pri, RespAck, 0);
		} else {
		    nackChk(&hd, buf, seqTxAtStart + pat, pri,
			"[ReqCmd]: priority value error(PrioReqOnce).");
		}
	    }
	    usleep(100000 * ((flg == 0) ? 1:10));	//100ms
	}
    }
}

void __CUT__ReqCmd_servo(void)
{
    printf("\n%s start\n", __func__);
    struct reqCmd req;
    const u_char neck = 2;

    struct cmnHeader hd;
    char buf[256];
    struct iovec rdBuf[] = {
	[PcHdr] = {&hd , sizeof hd},
	[PcData] = {buf, sizeof buf}
	/**
	 * 'sizeof buf' is temporary but necessary in readPacket(),
	 * will over write in readPacket()
	 */
    };
    
    // power on
    req.cmd = servoPower;
    req.id = neck;
    req.arg.arg8_t[0] = 1;

    ASSERT(writeReqCmdPacket(sock, seqTx++, PrioMid, CmnHF_noFlg, &req, true)
	> 0, "ReqCmd servoPower(power on) packet send");
    readPacket(sock, rdBuf, true, true);
    headerChk(&hd, seqTx - 1, PrioMid, RespAck, 0);


    // servo move
    short angle[] = {300, -300, 0};	//1/10 deg unit
    for (u_int i = 0; i < ARR_LEN(angle); i++) {
	req.cmd = servoMove;
	req.id = neck;
	req.arg.arg16_t[0] = (u_short)angle[i];
	req.arg.arg16_t[1] = 30;	// 3 sec

	ASSERT(writeReqCmdPacket(sock, seqTx++, PrioMid, CmnHF_noFlg, &req
	    , true) > 0, "ReqCmd servoMove packet send");
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx - 1, PrioMid, RespAck, 0);
	sleep(3);
    }


    // power off
    req.cmd = servoPower;
    req.id = neck;
    req.arg.arg8_t[0] = 0;

    ASSERT(writeReqCmdPacket(sock, seqTx++, PrioMid, CmnHF_noFlg, &req, true)
	> 0, "ReqCmd servoPower(power on) packet send");
    readPacket(sock, rdBuf, true, true);
    headerChk(&hd, seqTx - 1, PrioMid, RespAck, 0);
}

void __CUT__ReqDevSts(void)
{
    printf("\n%s start\n", __func__);
    struct reqDevSts req;
    const u_char neck = 2;

    struct cmnHeader hd;
    char buf[256];
    struct iovec rdBuf[] = {
	[PcHdr] = {&hd , sizeof hd},
	[PcData] = {buf, sizeof buf}
	/**
	 * 'sizeof buf' is temporary but necessary in readPacket(),
	 * will over write in readPacket()
	 */
    };

    {
	// req one device, status only
	enum e_Priority reqPri = PrioLow;

	req.idcat = DSIDCat_dev;	// *
	req.id = neck;
	req.reqStsFlg = DSFlg_sts;	// *

	ASSERT(writeReqDevStsPacket(sock, seqTx++, reqPri, CmnHF_noFlg, &req
	    , true) > 0, "ReqDevSts packet send");

	// recv ack
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx - 1, reqPri, RespAck, 0);

	// recv sts
	rdBuf[PcData].iov_len = sizeof buf;
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqRx++, reqPri, RespDevSts
		, sizeof(struct respDevSts) + sizeof(struct devStsElm));

	struct respDevSts *sts = rdBuf[PcData].iov_base;
	ASSERT(sts->id == neck,		"check device ID");
	ASSERT(sts->num == 1,		"check sts->num");	// *
	ASSERT(htonl(sts->elm[0].respStsCat) == DSCat_sts,	// *
					"check respStsCat");
	ASSERT(sts->elm[0].len == 10,	"check status length");	// *

	respDevStsDump(&sts->elm[0]);
    }

    {
	// req one device, param only
	enum e_Priority reqPri = PrioLow;

	req.idcat = DSIDCat_dev;	// *
	req.id = neck;
	req.reqStsFlg = DSFlg_params;	// *

	ASSERT(writeReqDevStsPacket(sock, seqTx++, reqPri, CmnHF_noFlg, &req
	    , true) > 0, "ReqDevSts packet send");

	// recv ack
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx - 1, reqPri, RespAck, 0);

	// recv sts
	rdBuf[PcData].iov_len = sizeof buf;
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqRx++, reqPri, RespDevSts
		, sizeof(struct respDevSts) + sizeof(struct devStsElm));

	struct respDevSts *sts = rdBuf[PcData].iov_base;
	ASSERT(sts->id == neck,		"check device ID");
	ASSERT(sts->num == 1,		"check sts->num");
	ASSERT(htonl(sts->elm[0].respStsCat) == DSCat_params,	//*
					"check respStsCat");
	ASSERT(sts->elm[0].len == 8,	"check status length");	//*

	respDevStsDump(&sts->elm[0]);
    }

    const u_int devStsReadInf[NUM_e_ReqDevStsCat] = {
	[DSCat_params]	= 8,
	[DSCat_sts]	= 10
    };

    {
	// req one device, both params and status
	enum e_Priority reqPri = PrioLow;

	req.idcat = DSIDCat_dev;
	req.id = neck;
	req.reqStsFlg = DSFlg_params | DSFlg_sts;	//*

	ASSERT(writeReqDevStsPacket(sock, seqTx++, reqPri, CmnHF_noFlg, &req
	    , true) > 0, "ReqDevSts packet send");

	// recv ack
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx - 1, reqPri, RespAck, 0);

	// recv sts
	rdBuf[PcData].iov_len = sizeof buf;
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqRx++, reqPri, RespDevSts
		, sizeof(struct respDevSts) + sizeof(struct devStsElm) * 2);

	struct respDevSts *sts = rdBuf[PcData].iov_base;
	ASSERT(sts->id == neck,		"check device ID");
	ASSERT(sts->num == 2,		"check sts->num");	//*

	for (enum e_ReqDevStsCat cat = 0; cat < sts->num; cat++) {
	    ASSERT(htonl(sts->elm[cat].respStsCat) == cat,	//*
					"check respStsCat(elm[i])");
	    ASSERT(sts->elm[cat].len == devStsReadInf[cat],	//*
	    				"check status length");
	    respDevStsDump(&sts->elm[cat]);
	}
    }
    
    {
	// req device group, both params and status
	printf("\nrequest by device group\n");

	enum e_Priority reqPri = PrioLow;

	req.idcat = DSIDCat_grp;
	req.id = DG_BodySrv;
	req.reqStsFlg = DSFlg_params | DSFlg_sts;	//*

	ASSERT(writeReqDevStsPacket(sock, seqTx++, reqPri, CmnHF_noFlg, &req
	    , true) > 0, "ReqDevSts packet send");

	// recv ack
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx - 1, reqPri, RespAck, 0);

	enum e_rs485ID ids[] = {rs485ID_BDY1, rs485ID_NEK1};
	for (u_int i = 0; i < ARR_LEN(ids); i++) {
	    // recv sts
	    rdBuf[PcData].iov_len = sizeof buf;
	    readPacket(sock, rdBuf, true, true);
	    headerChk(&hd, seqRx++, reqPri, RespDevSts
		    , sizeof(struct respDevSts) + sizeof(struct devStsElm) * 2);

	    struct respDevSts *sts = rdBuf[PcData].iov_base;
	    ASSERT(sts->id == ids[i],		"check device ID");
	    ASSERT(sts->num == 2,		"check sts->num");	//*
	    for (enum e_ReqDevStsCat cat = 0; cat < sts->num; cat++) {
		ASSERT(htonl(sts->elm[cat].respStsCat) == cat,	//*
					    "check respStsCat(elm[i])");
		ASSERT(sts->elm[cat].len == devStsReadInf[cat],	//*
					    "check status length");
		respDevStsDump(&sts->elm[cat]);
	    }
	}
    }
}
    
static void
respDevStsDump(const struct devStsElm *elm)
{
    printf("\nDevSts Dump\n");
    for (int i = 0; i < elm->len; i++)
	printf("%#x ", elm->sts[i]);
    printf("\n");
}

void __CUT__ReqCmd_ledServo(void)
{
    printf("\n%s start\n", __func__);
    struct reqCmd req;

    struct cmnHeader hd;
    char buf[256];
    struct iovec rdBuf[] = {
	[PcHdr] = {&hd , sizeof hd},
	[PcData] = {buf, sizeof buf}
	/**
	 * 'sizeof buf' is temporary but necessary in readPacket(),
	 * will over write in readPacket()
	 */
    };
    
    for (enum e_rs485ID id = rs485ID_LED_LEFT; id <= rs485ID_LED_RIGHT; id++) {
	// power on
	req.cmd = ledSrvOn;
	req.id = id;
	req.arg.arg32_t = 1;

	ASSERT(writeReqCmdPacket(sock, seqTx++, PrioMid, CmnHF_noFlg, &req
	    , true) > 0, "ReqCmd ledSrvOn(power on) packet send");
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx - 1, PrioMid, RespAck, 0);


	// LED servo Move
	u_short deg[] = {300, 0};
	for (u_int i = 0; i < ARR_LEN(deg); i++, sleep(3)) {
	    req.cmd = ledSrvMv;
	    req.id = id;
	    req.arg.arg16_t[0] = deg[i];
	    req.arg.arg16_t[1] = 0;
	    ASSERT(writeReqCmdPacket(sock, seqTx++, PrioMid, CmnHF_noFlg, &req
		, true) > 0, "ReqCmd ledSrvMv packet send");
	    readPacket(sock, rdBuf, true, true);
	    headerChk(&hd, seqTx - 1, PrioMid, RespAck, 0);
	}

	sleep(1);
	// power off
	req.cmd = ledSrvOn;
	req.id = id;
	req.arg.arg32_t = 0;
	ASSERT(writeReqCmdPacket(sock, seqTx++, PrioMid, CmnHF_noFlg, &req
	    , true) > 0, "ReqCmd ledSrvOn(power off) packet send");
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx - 1, PrioMid, RespAck, 0);
    }
}

void __CUT__ReqOnce_ledDisp(void)
{
    printf("\n%s start\n", __func__);
    int seqTxAtStart = seqTx;
    unsigned char pat[LED_DATA_LEN];
    const int lTims = LED_COLUMN * 10;
    const int intvl = 100;	//msec
    unsigned char reqbuf[COM_BUF_SIZE(LED_DATA_LEN) + sizeof(struct reqOnce)];
    struct reqOnce *reqP = (struct reqOnce *)reqbuf;
    const int bufLen = sizeof reqbuf - sizeof(struct reqOnce);

    struct cmnHeader hd;
    char buf[256];
    struct iovec rdBuf[] = {
	[PcHdr] = {&hd , sizeof hd},
	[PcData] = {buf, sizeof buf}
	/**
	 * 'sizeof buf' is temporary but necessary in readPacket(),
	 * will over write in readPacket()
	 */
    };

    for (enum e_LedColorCode col = LED_RED; col <= LED_GREEN; col++){
	for (int cnt = 0; cnt < lTims; cnt++) {
	    int clm = (LED_COLUMN - 1) * (cnt / LED_COLUMN % 2)
		+ pow(-1, (cnt / LED_COLUMN % 2)) * (cnt % LED_COLUMN);
	    ledVertLineDisp(clm, col, pat);

	    reqP->flg =  (cnt == 0) ? FLG_RESET_BASETIME
		: ((cnt == lTims -1) ? FLG_END_OF_SEQ : 0);
	    /**
	     * IMPORTANT!!!!!!!!!!!!!!!
	     *
	     * direct NEXT packet timecode
	     */
	    reqP->msec = (cnt + 1) * intvl;
	    reqP->revive_msec = 0;	// use previous valuse

	    int len = editLedDispReq(BREST_LED, pat, reqP->cmd, bufLen); 
	    assert(len <= bufLen);
	    ASSERT(writeReqOncePacket(sock, seqTx++, false
		, (col == LED_RED) ? CmnHF_noFlg : CmnHF_noAck, reqP, len
		, true) > 0, "ReqOnce packet send");

	    if (cnt == 0) {
		const char *fn = "/etc/local/bid/2_spVolCtrl.raw";
		unsigned char reqbuf[strlen(fn) + sizeof(struct reqOnce)];
		struct reqOnce *reqP = (struct reqOnce *)reqbuf;


		reqP->flg = FLG_SOUND_REQ;
		reqP->msec = 0;	/* same time with motion(LED req)	*/
		reqP->revive_msec = 0;	// use previous valuse
		memcpy(reqP->cmd, fn, strlen(fn));

		ASSERT(writeReqOncePacket(sock, seqTx++, false
		, (col == LED_RED) ? CmnHF_noFlg : CmnHF_noAck, reqP, strlen(fn)
		, true) > 0 , "SOUND ReqOnce packet send");
	    }

    #ifdef STOP_LED_SWITCH_STATE_READ_ON_SERVER
	    //recv data from serial port
	    ledVertLineDisp(cnt % LED_COLUMN,  LED_GREEN, pat);
	    int len;
	    unsigned char sendDat[32];
	    assert((len = editLedDispReq(BREST_LED, pat, sendDat, sizeof sendDat))
		<= sizeof sendDat);

	    unsigned char rBuf[32];
	    assert(rs485_read_fd(serialP, e_hd_toDev, rBuf, sizeof rBuf, 1)
		<= sizeof rBuf);
	    ASSERT(memcmp(rBuf, sendDat, len) == 0, "Serial loop back data error");
    #endif
	}


	for (int cnt = 0;
	    cnt < lTims + 1 && col == LED_RED/* +1 is SOUND Out req*/;
	    cnt++)
	{
	    /**
	     * IMPORTANT!!!!!!!!!!!!!!!
	     *
	     * Must send all ReqOnce packet
	     * from FLG_RESET_BASETIME to FLG_END_OF_SEQ 
	     * , then recv ACK/NAK of request packet.
	     * Otherwise, the case to send request that a timing passed comes out,
	     * and a server is hung up.
	     */

	    /** recv acknowledge and check it.	*/
	    rdBuf[PcData].iov_len = sizeof buf;
	    readPacket(sock, rdBuf, true, true);
	    headerChk(&hd, seqTxAtStart + cnt, PrioReqOnce, RespAck, 0);
	}

	/** recv EndOfReqOnce	*/
	rdBuf[PcData].iov_len = sizeof buf;
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqRx++, PrioReqOnce, RespEndOfReqOnce, 0);
    }



    int len = editLedDispFixpat(BREST_LED, BLANK, reqP->cmd, bufLen);
    assert(len <= bufLen);

    /** generate SIG_BUFCLR by sequence number error	*/
    ASSERT(writeReqOncePacket(sock, 0, true, CmnHF_noFlg, reqP, len, true) > 0
	, "ledBlankReq send, BUT SIG_BUFCLR occur by seqNo error");
    rdBuf[PcData].iov_len = sizeof buf;
    /** recv NAK check	*/
    readPacket(sock, rdBuf, true, true);

#ifdef __FOR_FreeBSD_Server
    /**
     * IMPORTANT!!!!!!!!!!!!!!!
     * this response is cleared by SIG_BUFCLR
     */
    const char *reason = "[header]: sequence number error.";
    ASSERT(strncmp(reason, rdBuf[PcData].iov_base, strlen(reason)) == 0
	, "NAK check at SIG_BUFCLR");
#endif

    printf("\nsleeping 5 sec to become aware of SIG_BUFCLR\n");
    sleep(5);


    /** immediate request start	*/
    ASSERT(writeReqOncePacket(sock, seqTx++, true, CmnHF_noFlg, reqP, len
	, true) > 0, "ledBlankReq by immediate request");
    /** recv acknowledge check	*/
    readPacket(sock, rdBuf, true, true);
    headerChk(&hd, seqTx - 1, PrioReqOnce, RespAck, 0);
    /** recv EndOfReqOnce	*/
    rdBuf[PcData].iov_len = sizeof buf;
    readPacket(sock, rdBuf, true, true);
    headerChk(&hd, seqRx++, PrioReqOnce, RespEndOfReqOnce, 0);
    /** immediate request end	*/





    //TODO check to timing passed data
    // check to receive timing passed message




}

void __CUT__ReqOnce_longPacket(void)
{
    printf("\n%s start\n", __func__);


    struct {
	u_char id;
	u_char on;
    } srvOn[] = {
	{rs485ID_NEK1, 1},
	{rs485ID_LAM2, 1},
	{rs485ID_LAM3, 1},
	{rs485ID_RAM2, 1},
	{rs485ID_RAM3, 1}
    };

    int seqTx_at_start = seqTx;

    {
	unsigned char reqbuf[COM_BUF_SIZE(sizeof srvOn)
	    + sizeof(struct reqOnce)];
	struct reqOnce *reqP = (struct reqOnce *)reqbuf;
	const int bufLen = sizeof reqbuf - sizeof(struct reqOnce);

	reqP->flg = FLG_RESET_BASETIME;
	reqP->msec = 1000;
	reqP->revive_msec = 0;	// use previous valuse

	const u_char oneP = sizeof(srvOn[0]); 
	int len = rs485_make_long_packet(reqP->cmd, 0, SMM_EnblTorque, oneP
	    , sizeof srvOn / oneP, (u_char *)srvOn);
	assert(len <= bufLen);

	ASSERT(writeReqOncePacket(sock, seqTx++, false, CmnHF_noFlg, reqP, len
	    , true) > 0, "ReqOnce packet send");
    }

    const u_short ang[] = {100, -100, 0};
    for (u_int i = 0; i < ARR_LEN(ang); i++) {
	const u_char oneP = sizeof(char) + sizeof(short) + sizeof(short);
	struct {
	    u_char id;
	    u_char ang[sizeof(short)];
	    u_char tim[sizeof(short)];
	} longDat[ARR_LEN(srvOn)];

	for (u_int j = 0; j < ARR_LEN(longDat); j++) {
	    longDat[j].id = srvOn[j].id;
	    ASSERT(set485devShort(longDat[j].ang, ang[i]) == ang[i]
		, "set short data");
	    ASSERT(set485devShort(longDat[j].tim, 50) == 50
		, "set short data");
	}

	unsigned char reqbuf[COM_BUF_SIZE(sizeof longDat)
	    + sizeof(struct reqOnce)];
	struct reqOnce *reqP = (struct reqOnce *)reqbuf;
	const int bufLen = sizeof reqbuf - sizeof(struct reqOnce);

	reqP->flg = 0;
	reqP->msec = 1000 * (i + 2);
	reqP->revive_msec = 0;	// use previous valuse

	int len = rs485_make_long_packet(reqP->cmd, 0, SMM_GPos_L, oneP
	    , sizeof longDat / oneP, (u_char *)longDat);
	assert(len <= bufLen);

	ASSERT(writeReqOncePacket(sock, seqTx++, false, CmnHF_noFlg, reqP, len
	    , true) > 0, "ReqOnce packet send");
    }

    {
	// servo power off
	unsigned char reqbuf[COM_BUF_SIZE(sizeof srvOn)
	    + sizeof(struct reqOnce)];
	struct reqOnce *reqP = (struct reqOnce *)reqbuf;
	const int bufLen = sizeof reqbuf - sizeof(struct reqOnce);

	const u_char oneP = 2; 
	for (u_int i = 0; i < ARR_LEN(srvOn); i++) {
	    srvOn[i].on = 0;
	}

	int len = rs485_make_long_packet(reqP->cmd, 0, SMM_EnblTorque, oneP
	    , sizeof srvOn / oneP, (u_char *)srvOn);
	assert(len <= bufLen);

	reqP->flg = FLG_END_OF_SEQ;
	reqP->msec = 0;
	reqP->revive_msec = 0;	// use previous valuse
	ASSERT(writeReqOncePacket(sock, seqTx++, false, CmnHF_noFlg, reqP, len
	    , true) > 0, "ReqOnce packet send");
    }

    struct cmnHeader hd;
    char buf[256];
    struct iovec rdBuf[] = {
	[PcHdr] = {&hd , sizeof hd},
	[PcData] = {buf, sizeof buf}
	/**
	 * 'sizeof buf' is temporary but necessary in readPacket(),
	 * will over write in readPacket()
	 */
    };

    //recv ACK
    for (u_int i = 0; i < ARR_LEN(ang) + 2; i++) {
	rdBuf[PcData].iov_len = sizeof buf;
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx_at_start + i, PrioReqOnce, RespAck, 0);
    }

    //recv RespEndOfReqOnce
    rdBuf[PcData].iov_len = sizeof buf;
    readPacket(sock, rdBuf, true, true);
    headerChk(&hd, seqRx++, PrioReqOnce, RespEndOfReqOnce, 0);
}

void __CUT__ReqEventHndl_LEDBtn(void)
{
    printf("\n%s start\n", __func__);
    struct cmnHeader hd;
    char buf[256];
    struct iovec rdBuf[] = {
	[PcHdr] = {&hd , sizeof hd},
	[PcData] = {buf, sizeof buf}
	/**
	 * 'sizeof buf' is temporary but necessary in readPacket(),
	 * will over write in readPacket()
	 */
    };
    //const u_int intvl = 500;
    const u_int intvl = 200;

    { //ReqDevPolling
	struct reqDevPoll reqPoll = {
	    .grp = DG_LedBtn,
	    .enb = true,
	    .intervalMs = intvl
	};

	ASSERT(writeReqDevPollPacket(sock, seqTx++, PrioHigh, CmnHF_noFlg
	    , &reqPoll, true) > 0, "ReqDevPolling packet send");


	/** recv acknowledge check	*/
	/** read one packet	*/
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx -1, PrioHigh, RespAck, 0);
    }

    {
	u_int th = 2000 / intvl; // 2000ms
	for (enum e_LedBoardID led = BREST_LED; led <= RIGHT_LED; led++) {
	    //ReqEventHndl
	    struct reqEventHndl reqHndl = {
		.id = led,
		.cat = EHC_ledBtn,
		.th.arg32_t = th
	    };

	    ASSERT(writeReqEventHndlPacket(sock, seqTx++, PrioHigh, CmnHF_noFlg
		    , &reqHndl, true) > 0, "ReqEventHndl packet send");

	    /** recv acknowledge check	*/
	    /** read one packet	*/
	    readPacket(sock, rdBuf, true, true);
	    headerChk(&hd, seqTx -1, PrioHigh, RespAck, 0);
	}

	const int maxLoop = 3;
	printf("\n\tPush any brest and finger button while 2 sec.\n");
	printf("pushed %d times, then event input test end.\n", maxLoop);

	for (int i = 0; i < maxLoop; i++) {
destruct:
	    rdBuf[PcData].iov_len = sizeof buf;
	    /** recv acknowledge check	*/
	    /** read one packet	*/
	    readPacket(sock, rdBuf, true, true);
	    headerChk(&hd, seqRx++, PrioHigh, RespEvent
		, sizeof(struct respEvent));

	    struct respEvent *resp = (struct respEvent *)buf;

	    if (resp->id == rs485ID_Accel) {
		printf("recv Accel Sens response\n");
		goto destruct;
	    }

	    ASSERT(resp->id >= BREST_LED && resp->id <= RIGHT_LED
		, "response RS485ID check");

	    enum e_LedSwAlign sw;
	    for (sw = LedSwAlign_BRight; sw < NUM_PUSH_SWITCH_ON_LED; sw++) {
		if (ntohs(resp->val.ledSw[sw].pushCnt) == 1 &&
		    ntohs(resp->val.ledSw[sw].contTimes) == 1)
		{
		    printf("\ndetect button pushed [id:%#x][btn:%d]\n"
			, resp->id, sw);
		} else if (ntohs(resp->val.ledSw[sw].pushCnt) == 0xffff &&
		    ntohs(resp->val.ledSw[sw].contTimes) == 0xffff)
		{
		    printf("\ndetect button released [id:%#x][btn:%d]\n"
			, resp->id, sw);
		    break;
		}
		if (ntohs(resp->val.ledSw[sw].contTimes) >= th) {
		    printf("\nrecv event sw is [id:%#x][btn:%d]\n"
			, resp->id, sw);
		}
	    }

	    if (sw >= NUM_PUSH_SWITCH_ON_LED) goto destruct;
	}
    }

    { //stop event handling
	struct reqEventHndl reqHndl = {
	    .id = BREST_LED,
	    .cat = EHC_stop,
	    .th.arg32_t = 0
	};

	ASSERT(writeReqEventHndlPacket(sock, seqTx++, PrioHigh, CmnHF_noFlg
	    , &reqHndl, true) > 0, "ReqEventHndl(EHC_stop) packet send");


	/** recv acknowledge check	*/
	/** read one packet	*/
	rdBuf[PcData].iov_len = sizeof buf;
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx -1, PrioHigh, RespAck, 0);
    }
    
    { //no ReqDevPolling
	struct {
	    struct reqEventHndl reqHndl;
	    char *nakStr;
	} tbl[] = {
	    {
		.reqHndl = {.id = 59,	.cat = EHC_gt,
			    .th.arg32_t = 20 },
		.nakStr = "[ReqEventHndl]: RS485ID is incorrect."
	    },
	    {
		.reqHndl = {.id = rs485ID_BDY1,	.cat = NUM_e_reqEventHndlCat,
			    .th.arg32_t = 20 },
		.nakStr = "[ReqEventHndl]: cat is incorrect."
	    },
	    {
		.reqHndl = {.id = rs485ID_BDY1,	.cat = EHC_gt,
			    .th.arg32_t = 20 },
		.nakStr = 
		"[ReqEventHndl]: ReqDevPolling disable about this RS485ID."
	    },

	    {
		.reqHndl = {.id = BREST_LED,	.cat = EHC_lt,
			    .th.arg32_t = 20},
		.nakStr = "[ReqEventHndl]: cat is incorrect of LED Button."
	    }
	};


	for (u_int i = 0; i < ARR_LEN(tbl); i++) {
	    ASSERT(writeReqEventHndlPacket(sock, seqTx++, PrioHigh, CmnHF_noFlg
		, &tbl[i].reqHndl, true) > 0, "ReqEventHndl(Nak) packet send");


	    /** recv acknowledge check	*/
	    /** read one packet	*/
	    rdBuf[PcData].iov_len = sizeof buf;
	    readPacket(sock, rdBuf, true, true);
	    nackChk(&hd, buf, seqTx -1, PrioHigh, tbl[i].nakStr);
	}
    }

    { //ReqDevPolling Stop
	struct reqDevPoll reqPoll = {
	    .grp = DG_LedBtn,
	    .enb = false,
	    .intervalMs = 0
	};

	ASSERT(writeReqDevPollPacket(sock, seqTx++, PrioHigh, CmnHF_noFlg
	    , &reqPoll, true) > 0, "ReqDevPolling packet send");


	/** recv acknowledge check	*/
	/** read one packet	*/
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx -1, PrioHigh, RespAck, 0);
    }
}

void __CUT__ReqEventHndl_Accel(void)
{
    printf("\n%s start\n", __func__);
    struct cmnHeader hd;
    char buf[256];
    struct iovec rdBuf[] = {
	[PcHdr] = {&hd , sizeof hd},
	[PcData] = {buf, sizeof buf}
	/**
	 * 'sizeof buf' is temporary but necessary in readPacket(),
	 * will over write in readPacket()
	 */
    };

    { //ReqDevPolling
	struct reqDevPoll reqPoll = {
	    .grp = DG_Accel,
	    .enb = true,
	    //.intervalMs = 50
	    .intervalMs = 20
	};

	ASSERT(writeReqDevPollPacket(sock, seqTx++, PrioHigh, CmnHF_noFlg
	    , &reqPoll, true) > 0, "ReqDevPolling packet send");


	/** recv acknowledge check	*/
	/** read one packet	*/
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx -1, PrioHigh, RespAck, 0);
    }

    {
	//ReqEventHndl
	struct reqEventHndl reqHndl = {
	    .id = rs485ID_Accel,
	    .cat = EHC_ob,
	    .th.arg16_t[0] = 100,
	    .th.arg16_t[1] = 450
	};

	ASSERT(writeReqEventHndlPacket(sock, seqTx++, PrioHigh, CmnHF_noFlg
	    , &reqHndl, true) > 0, "ReqEventHndl packet send");

	/** recv acknowledge check	*/
	/** read one packet	*/
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx -1, PrioHigh, RespAck, 0);
    }

    printf("lay-down to check accelaration sensor event response!!\n"
	"(in 10 sec)\n");

    {
	struct timeval start, now, diff;
	gettimeofday(&start, NULL);
	gettimeofday(&now, NULL);
	timersub(&start, &now, &diff);
	while (diff.tv_sec < 10) {
	    gettimeofday(&now, NULL);
	    timersub(&now, &start, &diff);

	    rdBuf[PcData].iov_len = sizeof buf;
	    int rb;
	    if ((rb = readPacket(sock, rdBuf, true, false)) < 0
		&& errno == EAGAIN)
	    {
		//printf("usleep() by read() returns 'EAGAIN'\n");
		usleep(1000);
	    } else {
		headerChk(&hd, seqRx++, PrioHigh, RespEvent
		    , sizeof(struct respEvent));

		struct respEvent *resp = (struct respEvent *)buf;
		ASSERT(resp->id == rs485ID_Accel, "recv Accel Sens response\n");
	    }
	}
    }
}

void __CUT__ReqEventHndl_LEDBtn_and_Accel(void)
{
    //sleep(10);
    //be slow status read after this line.
    /**
     * Though you can read the both status of LED-button
     * and accelaration sensor,
     * but very slow rate to read status.
     * Therefore you should choose a device reading status in a minimum.
     */
    printf("\n%s start\n", __func__);
    __CUT__ReqEventHndl_LEDBtn();
}

void __CUT__ReqEventHndl_Accel_stop(void)
{
    printf("\n%s start\n", __func__);
    struct cmnHeader hd;
    char buf[256];
    struct iovec rdBuf[] = {
	[PcHdr] = {&hd , sizeof hd},
	[PcData] = {buf, sizeof buf}
	/**
	 * 'sizeof buf' is temporary but necessary in readPacket(),
	 * will over write in readPacket()
	 */
    };

    { //stop event handling
	struct reqEventHndl reqHndl = {
	    .id = rs485ID_Accel,
	    .cat = EHC_stop,
	    .th.arg32_t = 0
	};

	ASSERT(writeReqEventHndlPacket(sock, seqTx++, PrioHigh, CmnHF_noFlg
	    , &reqHndl, true) > 0, "ReqEventHndl(EHC_stop) packet send");


	/** recv acknowledge check	*/
	/** read one packet	*/
	rdBuf[PcData].iov_len = sizeof buf;
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx -1, PrioHigh, RespAck, 0);
    }

    { //ReqDevPolling Stop
	struct reqDevPoll reqPoll = {
	    .grp = DG_Accel,
	    .enb = false,
	    .intervalMs = 0
	};

	ASSERT(writeReqDevPollPacket(sock, seqTx++, PrioHigh, CmnHF_noFlg
	    , &reqPoll, true) > 0, "ReqDevPolling packet send");


	/** recv acknowledge check	*/
	/** read one packet	*/
	readPacket(sock, rdBuf, true, true);
	headerChk(&hd, seqTx -1, PrioHigh, RespAck, 0);
    }
}

static void
headerChk(const struct cmnHeader *hd, u_int seq, enum e_Priority pri,
    enum e_RespCat cat, u_int datLen)
{
    ASSERT(
	hd->seq == seq && hd->pri == pri &&
	hd->cat == cat && hd->datLen == datLen
	, "header check"
    );
}

static void
nackChk(const struct cmnHeader *hd, const char *buf, u_int seq,
    enum e_Priority pri, const char *reason)
{
    headerChk(hd, seq, pri, RespNack, strlen(reason));
    ASSERT(strncmp(buf, reason, strlen(reason)) == 0, "Nak reason chk");
}

//TODO check SIG_EMRREQ


void __CUT_TAKEDOWN__scifTrafMain(void)
{
    assert(close(sock) == 0);
#ifdef STOP_LED_SWITCH_STATE_READ_ON_SERVER
    assert(close(serialP) == 0);
#endif
}
