デーモンプログラム(gvcd.c)

// --------------------------------------------------
// Global Versatile Controler http://www.gvc-on.net/
// --------------------------------------------------
// --------------------------------------------------
// Revision Memo (Y.M.D Editor/Memo)
// --------------------------------------------------
// 
// 2013.06.12 メッセージキュー部分の実装(移植)をする
// 
// 2013.06.10 T.Kabu
// 汎用制御装置 Grobal Versatile Controller Daemon (gvcd)
// 
// gvcd /dev/????? (GVCが接続されているデバイス名)
// 
// デバイスのパラメータは9600N81
//   9600bps
//   ノンパリティ
//   8ビット
//   ストップビット1
//   フロー制御はArduinoではしていないのでOFF
// 
// パラメータはsetserialなどの外部コマンドで設定すればいいとおもう
// 
// sync;gcc -O2 -Wall -lm ./gvcd.c -o gvcd
// 
// Fedora18 では、gcc -O2 -Wall -fno-strict-aliasing ./gvcd_20130625.c -o gvcd、として
// コンパイルしないと、dereferencing type-punned pointer(型またぎすぎみたいな)感じで怒られる。
// 
// 参考URLいろいろ
// http://pinka99.ddo.jp/nanao/work/daemon.html
// http://d.hatena.ne.jp/rero/20041002/p1
// http://linuxmag.sourceforge.jp/Japanese/March2003/article287.shtml
// http://www.geocities.co.jp/Athlete-Samos/7760/study/msgkyu1.html
// http://www.geocities.jp/taka_owl2005/job/UNIX/kernel/ipc.html
// http://d.hatena.ne.jp/ka2yan/20090327
//
// ------------------------------
// BASE
// ------------------------------
// 2011.11.02 T.Kabu gvcd				とりあえず取り掛かる
// 2011.12.01 T.Kabu gvcd2c				幾つかのセンサーに対応して画面に吐き出すようにした
// 2011.12.20 T.Kabu gvcd3				デーモン化、プロセスチェック、ログ吐き出しに取り掛かる
// 2012.02.02 T.Kabu gvcd3b				テストソースからあれこれマージ、プロセス間通信(メッセージキュー)対応
// 2012.02.06 T.Kabu gvcd3c				GVCに対してコマンド送信
// 2012.03.09 T.Kabu gvcd4				スタートフレームと言う定義をやめて、デリミタメッセージにした
// 2013.06.10 T.Kabu gvcd_20130610		Rev.2用に色々修正
// 2013.07.18 T.Kabu gvcd_20130717		赤外線データ(つまりリモコン)の送受信保存再送が出来るようになったのでいったんFix
// 2013.12.20 T.Kabu 					清書と、赤外線データのサイズの関係で扱えるデータサイズをヘッダ込みで最大1600バイトに統一する

//---------------------------------------------------
// include
//---------------------------------------------------
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <syslog.h>
#include <termios.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/ipc.h>
#include <sys/msg.h>
///#include <linux/ipc.h>
///#include <linux/msg.h>
#include <errno.h>

#include "gvcd.h"

// --------------------------------------------------
// Const Define
// --------------------------------------------------

// --------------------------------------------------
// Structure 
// --------------------------------------------------

// --------------------------------------------------
// Prototype Define
// --------------------------------------------------
// ------------------------------
// GVCキュー処理 (main関数の中でのキュー処理テーブル初期化を忘れずに)
// ------------------------------
int gvc_q_job_dummy(void * q_po);				// キューダミー処理

int gvc_q_job_version(void * q_po);				// 0x01:バージョン要求
int gvc_q_job_modulelist(void * q_po);			// 0x02:モジュール一覧要求
int gvc_q_job_moduledata(void * q_po);			// 0x03:モジュールデータ要求
int gvc_q_job_switchoff(void * q_po);			// 0x20:スイッチOFF要求
int gvc_q_job_switchon(void * q_po);			// 0x21:スイッチON要求
int gvc_q_job_switchstatus(void * q_po);		// 0x2f:スイッチ状態要求
int gvc_q_job_masterreset(void * q_po);			// 0x7e:マスターコントローラーリセット要求
int gvc_q_job_masterrestart(void * q_po);		// 0x7e:マスターコントローラーリスタート要求
int gvc_q_job_masterstop(void * q_po);			// 0x7f:マスターコントローラーストップ要求
///int gvc_q_job_lcdoutput(void * q_po);		// 0x81:LCDデータ出力要求
int gvc_q_job_irtx(void * q_po);				// 0x91:リモコンデータ送信要求
int gvc_q_job_irrx(void * q_po);				// 0x92:リモコンデータ受信要求
int gvc_q_job_irset(void * q_po);				// 0x93:リモコンデータ設定要求
int gvc_q_job_irget(void * q_po);				// 0x94:リモコンデータ取得要求
int gvc_q_job_irdel(void * q_po);				// 0x95:リモコンデータ削除要求
///int gvc_q_job_voiceoutput(void * q_po);		// 0xa1:音声合成データ出力要求
int gvc_q_job_daemonstop(void * q_po);			// 0xff:gvcdストップ要求

// ------------------------------
// GVCメッセージ処理 (main関数の中でのメッセージ処理テーブル初期化を忘れずに)
// ------------------------------
int gvc_msg_job_dummy(void * msg_po);           // メッセージダミー処理
int gvc_msg_job_delimiterframe(void * msg_po);  // デリミタメッセージ

//int gvc_msg_job_a(void * msg_po);				// TBD
//int gvc_msg_job_b(void * msg_po);				// TBD
//int gvc_msg_job_c(void * msg_po);				// TBD
int gvc_msg_job_distance(void * msg_po);		// 距離
//int gvc_msg_job_e(void * msg_po);				// TBD
//int gvc_msg_job_f(void * msg_po);				// TBD
//int gvc_msg_job_g(void * msg_po);				// TBD
int gvc_msg_job_humidity(void * msg_po);		// 湿度
int gvc_msg_job_ir(void * msg_po);				// 赤外線
//int gvc_msg_job_j(void * msg_po);				// TBD
//int gvc_msg_job_k(void * msg_po);				// TBD
int gvc_msg_job_light(void * msg_po);			// 照度
//int gvc_msg_job_m(void * msg_po);				// TBD
//int gvc_msg_job_n(void * msg_po);				// TBD
//int gvc_msg_job_o(void * msg_po);				// TBD
int gvc_msg_job_pressure(void * msg_po);		// 大気圧
//int gvc_msg_job_q(void * msg_po);				// TBD
//int gvc_msg_job_r(void * msg_po);				// TBD
//int gvc_msg_job_s(void * msg_po);				// TBD
int gvc_msg_job_temperature(void * msg_po);		// 気温
//int gvc_msg_job_u(void * msg_po);				// TBD
//int gvc_msg_job_v(void * msg_po);				// TBD
//int gvc_msg_job_w(void * msg_po);				// TBD
//int gvc_msg_job_x(void * msg_po);				// TBD
//int gvc_msg_job_y(void * msg_po);				// TBD
//int gvc_msg_job_z(void * msg_po);				// TBD
int gvc_msg_job_other(void * msg_po);			// その他


void signal_alarm();                            // ALARMシグナル処理
void signal_sighup();                           // SIGHUPシグナル処理

void put_log(int, char * logstr);               // ログ出力

// --------------------------------------------------
// Variable Param
// --------------------------------------------------
char daytime_str[DAYTIME_LEN];					// 日時文字列 2011/10/14 12:43:58

int gvc_port;									// GVCを接続しているポート(/dev/ttyUSB0とか)

int gvcd_mode = 0;								// GVCD動作モード 0:通常モード 1:ログファイル別出力モード 99:ダンプモード

int gvc_log_fp;									// GVCログファイルポインタ

// GVCキュー処理テーブル(戻り値:int、メッセージそのものは(void *)に型キャストして渡す(メッセージの中身はそれぞれ異なるため)
int (*gvc_queue_job[0x100])(void * q_po);

// GVCメッセージ処理テーブル(戻り値:int、メッセージそのものは(void *)に型キャストして渡す(メッセージの中身はそれぞれ異なるため)
int (*gvc_msg_job[0x100])(void * msg_po);

// デリミタメッセージ
static char GVC_DELIMITER_MSG[] = {
	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xab, 0xaa
};

// コマンド送信可能状態(0:デリミタ待ち、1:コマンド送信可能)
int gvc_cmd_ready = 0;

// 受信バッファ
unsigned char rx_buffer[BUFF_SIZE];

// 送信バッファ
unsigned char tx_buffer[BUFF_SIZE];

// 赤外線データ格納用ファイル
FILE *datafp;									// データ格納用ファイルポインタ
char datafp_flag;								// データ格納フラグ(0:None, 1:Wait, 2:Complete, etc)

// --------------------------------------------------
// Sub Routine
// --------------------------------------------------
// ------------------------------------------
// Sub Routine/GVCキュー処理
// ------------------------------------------
// --------------------------------
// GVCキュー処理:ダミー
// --------------------------------
int gvc_q_job_dummy(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ログ出力用文字列を生成
	sprintf(logstr, "QUEUE DUMMY : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
		gvc_message_queue->qtype,
		gvc_message_queue->q.gvc_num,
		gvc_message_queue->q.msg_type,
		gvc_message_queue->q.dev_num,
		gvc_message_queue->q.format,
		gvc_message_queue->q.cmd,
		gvc_message_queue->q.data_len
		);
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x01:バージョン要求
// --------------------------------
int gvc_q_job_version(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
///	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	// メッセージキュー、というかLinuxレベルになるとテーブル構造体のアラインメントが行われるから注意すること!!
///	memcpy(tx_buffer, (void *)&(gvc_message_queue->q.msg_type), GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// 送信バッファにGVC_SERIAL_MESSAGE_tをかぶせる
///	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)tx_buffer;
	// ↑とかはできない!! ヽ(`Д´#)ノ ムキー!!
	
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
///	gvc_serial_message->data[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_serial_message->data_len ] = GetCRC8((void *)gvc_serial_message, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_serial_message->data_len);
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT or LONG!? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE VERSION : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// 送信できたバイト数を返す
	return tx_len;
}

// --------------------------------
// GVCキュー処理:0x02:モジュール一覧要求
// --------------------------------
int gvc_q_job_modulelist(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE MODULE LIST : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	return 0;
}

// --------------------------------
// GVCキュー処理:0x03:モジュールデータ要求
// --------------------------------
int gvc_q_job_moduledata(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ログ出力用文字列を生成
	sprintf(logstr, "QUEUE MODULE DATA : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
		gvc_message_queue->qtype,
		gvc_message_queue->q.gvc_num,
		gvc_message_queue->q.msg_type,
		gvc_message_queue->q.dev_num,
		gvc_message_queue->q.format,
		gvc_message_queue->q.cmd,
		gvc_message_queue->q.data_len
		);
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	// GVCに対してコマンド送信
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x20:スイッチOFF要求
// --------------------------------
int gvc_q_job_switchoff(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE SWITCH OFF : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x21:スイッチON要求
// --------------------------------
int gvc_q_job_switchon(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE SWITCH ON : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x2f:スイッチ状態要求
// --------------------------------
int gvc_q_job_switchstatus(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ログ出力用文字列を生成
	sprintf(logstr, "QUEUE SWITCH STATUS : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
		gvc_message_queue->qtype,
		gvc_message_queue->q.gvc_num,
		gvc_message_queue->q.msg_type,
		gvc_message_queue->q.dev_num,
		gvc_message_queue->q.format,
		gvc_message_queue->q.cmd,
		gvc_message_queue->q.data_len
		);
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	// GVCに対してコマンド送信
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x91:リモコンデータ送信要求
// --------------------------------
int gvc_q_job_irtx(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE IR TX : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x92:リモコンデータ受信要求
// --------------------------------
int gvc_q_job_irrx(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE IR RX : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x93:リモコンデータ設定要求
// --------------------------------
int gvc_q_job_irset(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	int hex_count;
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE IR SET : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=%0d, data=",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// QUEUE~data=までの文字列の長さを取得
		tx_len = strlen(logstr);
		// data=の後ろに16進でデータを書いていく
		for (hex_count = 0; hex_count < gvc_message_queue->q.data_len; hex_count++)
		{
			sprintf((char *)logstr + tx_len, "%02X", (int)gvc_message_queue->q.data[hex_count]);
			tx_len += 2;
		}
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x94:リモコンデータ取得要求
// --------------------------------
int gvc_q_job_irget(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// データ長がある場合、リモコンデータを保存するファイルを指定されている可能性があるので、まず開いてみる
	if (gvc_message_queue->q.data_len > 0 && gvc_message_queue->q.data_len == strlen((char *)gvc_message_queue->q.data))
	{
		// そのファイルが開けるか試してみる
		datafp = fopen((char *)gvc_message_queue->q.data, "wb");
		// ファイルが開けなかったら
		if (datafp == NULL)
		{
			// データ格納フラグ初期化
			datafp_flag = 0;
			// データ格納フラグは変化なし
			// LOGメッセージ設定
			sprintf(logstr, "CANNOT OPEN IR DATA FILE: %s", gvc_message_queue->q.data);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		else
		{
			// データ格納フラグを待ち状態に
			datafp_flag = 1;
			// LOGメッセージ設定
			sprintf(logstr, "OPEN IR DATA FILE: %s", gvc_message_queue->q.data);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// データ長リセット、GVCに対してファイル名を送っても意味が無いので。
		// このif{}の外でリセットしないのは、メッセージそのものがおかしかったときに気がつかないと困るから
		gvc_message_queue->q.data_len = 0;
	}
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE IR GET : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x95:リモコンデータ削除要求
// --------------------------------
int gvc_q_job_irdel(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE IR DEL : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x7e:マスターコントローラーリセット要求
// --------------------------------
int gvc_q_job_masterreset(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE MASTER RESET : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x7e:マスターコントローラーリスタート要求
// --------------------------------
int gvc_q_job_masterrestart(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE MASTER RESTART : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0x7f:マスターコントローラーストップ要求
// --------------------------------
int gvc_q_job_masterstop(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	int tx_len = 0;										// 送信できたデータの長さ
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ----------------
	// GVCに対してコマンド送信
	// ----------------
	// 送信バッファにキューメッセージ部分をコピー
	tx_buffer[0] = gvc_message_queue->q.msg_type;			// gvc_serial_message->msg_type
	tx_buffer[1] = gvc_message_queue->q.dev_num;			// gvc_serial_message->dev_num
	tx_buffer[2] = gvc_message_queue->q.format;				// gvc_serial_message->format
	tx_buffer[3] = gvc_message_queue->q.cmd;				// gvc_serial_message->cmd
	*(int *)&(tx_buffer[4]) = gvc_message_queue->q.data_len; // gvc_serial_message->data_len
	memcpy((void *)&(tx_buffer[6]), gvc_message_queue->q.data, GVC_SERIAL_MESSAGE_HEADER_SIZE +  gvc_message_queue->q.data_len);
	
	// CRCを計算して、メッセージの最後に設定
	tx_buffer[ GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len ] = GetCRC8((void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい
	
	// シリアルポートへのライト(checksumまで送信するので長さは+1される)
	tx_len = write(gvc_port, (void *)tx_buffer, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1);
	
	// きちんと送信できていないなら
	if (tx_len < 0)
	{
		// もし割り込みによる中断だったら
		if (errno == EINTR)
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is EINTR. tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
		// それ以外の場合には
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "WRITE is OTHER ERROR !? tx_len=%d, errno=%d", tx_len, errno);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
		}
	}
	// 送信したデータ長が実際と合致しないなら
	else if (tx_len != (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1))
	{
		// LOGメッセージ設定
		sprintf(logstr, "WRITE is SHORT !? tx_len=%d, org_len=%d", tx_len, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_message_queue->q.data_len + 1));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	// きちんと送信できたなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "QUEUE MASTER STOP : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
			gvc_message_queue->qtype,
			gvc_message_queue->q.gvc_num,
			gvc_message_queue->q.msg_type,
			gvc_message_queue->q.dev_num,
			gvc_message_queue->q.format,
			gvc_message_queue->q.cmd,
			gvc_message_queue->q.data_len
			);
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	return 0;
}

// --------------------------------
// GVCキュー処理:0xff:gvcdストップ要求
// --------------------------------
int gvc_q_job_daemonstop(void * q_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_MESSAGE_QUEUE_t * gvc_message_queue;			// GVC メッセージキュー用ポインタ(キューデータにかぶせる)
	
	// キューポインタにGVC_MESSAGE_QUEUE_tをかぶせる
	gvc_message_queue = (GVC_MESSAGE_QUEUE_t *)q_po;
	
	// ログ出力用文字列を生成
	sprintf(logstr, "QUEUE DAEMON STOP : qtype=%lu, gvc_num=%d, msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
		gvc_message_queue->qtype,
		gvc_message_queue->q.gvc_num,
		gvc_message_queue->q.msg_type,
		gvc_message_queue->q.dev_num,
		gvc_message_queue->q.format,
		gvc_message_queue->q.cmd,
		gvc_message_queue->q.data_len
		);
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	// GVCに対してコマンド送信
	
	return 0;
}

// ------------------------------------------
// Sub Routine/GVCメッセージ処理
// ------------------------------------------
// --------------------------------
// GVCメッセージ処理:ダミー
// --------------------------------
int gvc_msg_job_dummy(void * msg_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	// メッセージポインタにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)msg_po;
	
	// ログ出力用文字列を生成
	sprintf(logstr, "MSG DUMMY : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
		 gvc_serial_message->msg_type,
		 gvc_serial_message->dev_num,
		 gvc_serial_message->format,
		 gvc_serial_message->cmd,
		 gvc_serial_message->data_len
		 );
	
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	return 0;
}

// --------------------------------
// GVCメッセージ処理:デリミタメッセージ
// --------------------------------
int gvc_msg_job_delimiterframe(void * msg_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	// メッセージポインタにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)msg_po;
	
	// ログ出力用文字列を生成
	sprintf(logstr, "MSG DELIMITER : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=0x%02x",
		 gvc_serial_message->msg_type,
		 gvc_serial_message->dev_num,
		 gvc_serial_message->format,
		 gvc_serial_message->cmd,
		 gvc_serial_message->data_len
		 );
// 普段はうざいので動かさない
	// ログにメッセージを出力
//	put_log(gvcd_mode, logstr);
	
	// GVCコマンド送信可能状態を送信可能(=1)に設定
	gvc_cmd_ready = 1;
	 
	return 0;
}

// --------------------------------
// GVCメッセージ処理:その他のメッセージ
// --------------------------------
int gvc_msg_job_other(void * msg_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	int  loglen;
	
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	// メッセージポインタにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)msg_po;
	
	// データがバイナリの場合(formatなどで判別すること)には、HEX表示にしたり「.」表示にしたりなど工夫すること!!
	
	// データがあるなら
	if (gvc_serial_message->data_len > 0)
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "MSG OTHER : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=%0d, data=",
			 gvc_serial_message->msg_type,
			 gvc_serial_message->dev_num,
			 gvc_serial_message->format,
			 gvc_serial_message->cmd,
			 gvc_serial_message->data_len);
		loglen = strlen(logstr);
		memcpy(logstr + loglen, gvc_serial_message->data, gvc_serial_message->data_len);
		logstr[loglen + gvc_serial_message->data_len] = 0x00;
	}
	// データがないなら
	else
	{
		// ログ出力用文字列を生成
		sprintf(logstr, "MSG OTHER : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=%0d",
			 gvc_serial_message->msg_type,
			 gvc_serial_message->dev_num,
			 gvc_serial_message->format,
			 gvc_serial_message->cmd,
			 gvc_serial_message->data_len
			 );
	}
	
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	return 0;
}

// --------------------------------
// GVCメッセージ処理:距離
// --------------------------------
int gvc_msg_job_distance(void * msg_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	int  loglen;
	
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	// メッセージポインタにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)msg_po;
	
	// データがバイナリの場合(formatなどで判別すること)には、HEX表示にしたり「.」表示にしたりなど工夫すること!!
	
	// ログ出力用文字列を生成
	sprintf(logstr, "MSG DIST : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=%0d, data=",
		 gvc_serial_message->msg_type,
		 gvc_serial_message->dev_num,
		 gvc_serial_message->format,
		 gvc_serial_message->cmd,
		 gvc_serial_message->data_len);
	loglen = strlen(logstr);
	memcpy(logstr + loglen, gvc_serial_message->data, gvc_serial_message->data_len);
	logstr[loglen + gvc_serial_message->data_len] = 0x00;
	
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	return 0;
}

// --------------------------------
// GVCメッセージ処理:湿度
// --------------------------------
int gvc_msg_job_humidity(void * msg_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	int  loglen;
	
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	// メッセージポインタにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)msg_po;
	
	// データがバイナリの場合(formatなどで判別すること)には、HEX表示にしたり「.」表示にしたりなど工夫すること!!
	
	// ログ出力用文字列を生成
	sprintf(logstr, "MSG HUMI : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=%0d, data=",
		 gvc_serial_message->msg_type,
		 gvc_serial_message->dev_num,
		 gvc_serial_message->format,
		 gvc_serial_message->cmd,
		 gvc_serial_message->data_len);
	loglen = strlen(logstr);
	memcpy(logstr + loglen, gvc_serial_message->data, gvc_serial_message->data_len);
	logstr[loglen + gvc_serial_message->data_len] = 0x00;
	
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	return 0;
}

// --------------------------------
// GVCメッセージ処理:赤外線
// --------------------------------
int gvc_msg_job_ir(void * msg_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	int  loglen;
	int  hex_count;
	
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	// メッセージポインタにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)msg_po;
	
	// ログ出力用文字列を生成
	sprintf(logstr, "MSG IR : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=%0d, data=",
		 gvc_serial_message->msg_type,
		 gvc_serial_message->dev_num,
		 gvc_serial_message->format,
		 gvc_serial_message->cmd,
		 gvc_serial_message->data_len);
	loglen = strlen(logstr);
	
	// もしフォーマットがバイナリなら
	if (gvc_serial_message->format == 0x31)
	{
		// 当面はASCIIに変換してテキスト出力…TBD
		for (hex_count = 0; hex_count < gvc_serial_message->data_len; hex_count++)
		{
			sprintf((char *)logstr + loglen, "%02X", (int)gvc_serial_message->data[hex_count]);
			loglen += 2;
		}
	}
	// そうではないなら
	else
	{
		// 当面はそのままテキスト出力…TBD
		memcpy(logstr + loglen, gvc_serial_message->data, gvc_serial_message->data_len);
		logstr[loglen + gvc_serial_message->data_len] = 0x00;
	}
	
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	// もしデータ格納フラグが待ち状態(=1)で、かつデータファイルがオープンされているなら
	if (datafp_flag == 1 && datafp != NULL)
	{
		// データファイルにデータを出力
		fwrite(gvc_serial_message->data, sizeof(char), gvc_serial_message->data_len, datafp);
		// データファイルを閉じる
		fclose(datafp);
		// データ格納フラグ初期化
		datafp_flag = 0;
	}
	// 出力されたデータを確認するには「od -tx1z 出力ファイル名」のようにするといいよ
	
	return 0;
}

// --------------------------------
// GVCメッセージ処理:照度
// --------------------------------
int gvc_msg_job_light(void * msg_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	int  loglen;
	
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	// メッセージポインタにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)msg_po;
	
	// データがバイナリの場合(formatなどで判別すること)には、HEX表示にしたり「.」表示にしたりなど工夫すること!!
	
	// ログ出力用文字列を生成
	sprintf(logstr, "MSG LIGHT : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=%0d, data=",
		 gvc_serial_message->msg_type,
		 gvc_serial_message->dev_num,
		 gvc_serial_message->format,
		 gvc_serial_message->cmd,
		 gvc_serial_message->data_len);
	loglen = strlen(logstr);
	memcpy(logstr + loglen, gvc_serial_message->data, gvc_serial_message->data_len);
	logstr[loglen + gvc_serial_message->data_len] = 0x00;
	
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	return 0;
}

// --------------------------------
// GVCメッセージ処理:大気圧、圧力
// --------------------------------
int gvc_msg_job_pressure(void * msg_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	int  loglen;
	
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	// メッセージポインタにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)msg_po;
	
	// データがバイナリの場合(formatなどで判別すること)には、HEX表示にしたり「.」表示にしたりなど工夫すること!!
	
	// ログ出力用文字列を生成
	sprintf(logstr, "MSG PRES : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=%0d, data=",
		 gvc_serial_message->msg_type,
		 gvc_serial_message->dev_num,
		 gvc_serial_message->format,
		 gvc_serial_message->cmd,
		 gvc_serial_message->data_len);
	loglen = strlen(logstr);
	memcpy(logstr + loglen, gvc_serial_message->data, gvc_serial_message->data_len);
	logstr[loglen + gvc_serial_message->data_len] = 0x00;
	
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	return 0;
}

// --------------------------------
// GVCメッセージ処理:温度
// --------------------------------
int gvc_msg_job_temperature(void * msg_po)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	int  loglen;
	
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	// メッセージポインタにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)msg_po;
	
	// データがバイナリの場合(formatなどで判別すること)には、HEX表示にしたり「.」表示にしたりなど工夫すること!!
	
	// ログ出力用文字列を生成
	sprintf(logstr, "MSG TEMP : msg_type=0x%02x, dev_num=0x%02x, format=0x%02x, cmd/result=0x%02x, data_len=%0d, data=",
		 gvc_serial_message->msg_type,
		 gvc_serial_message->dev_num,
		 gvc_serial_message->format,
		 gvc_serial_message->cmd,
		 gvc_serial_message->data_len);
	loglen = strlen(logstr);
	memcpy(logstr + loglen, gvc_serial_message->data, gvc_serial_message->data_len);
	logstr[loglen + gvc_serial_message->data_len] = 0x00;
	
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	return 0;
}

// ------------------------------------------
// Sub Routine/その他
// ------------------------------------------
// --------------------------------
// シリアルポートの初期化
// --------------------------------
void serial_reset(int fd)
{
	// http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/termios.3.html
	// 標準ではカノニカルモードで、デリミタもあらかじめ設定されている
	
	// ThinkPadに入れたLinuxとかではなんら問題が無かったが、なぜかRaspberry Piではシリアルポートがうまく
	// 使えず困っていた。Pidora(Fedora Remix)にlogserialというのがあったのでソースを見てみたところ、
	// どうも文字サイズの初期化で「(tio.c_cflag & ~CSIZE)」をORとった上でCS8としないとだめみたいで、
	// ちなみに他のパラメータはどであっても関係なかった
	
	// ----------------
	// ローカル変数定義
	// ----------------
	// termioテーブルローカル宣言
	struct termios tio;
	
	// ローカル変数を0で初期化
	memset(&tio, 0, sizeof(tio));
	
	// 現在の設定値を取得
	tcgetattr(fd, &tio);
	
	// 入力ボーレートを設定
	cfsetispeed(&tio, BAUD_RATE);
	// 出力ボーレートを設定
	cfsetospeed(&tio, BAUD_RATE);
	
	// 文字サイズとして8ビットを設定
	tio.c_cflag = (tio.c_cflag & ~CSIZE) | CS8;
	// モデムの制御線を無視、受信有効、フレームエラーおよびパリティエラーを無視
	tio.c_cflag |= (CLOCAL | CREAD | IGNPAR );
	// ノンパリティ(偶数奇数パリティも外す=この状態だと奇数パリティ)
	tio.c_cflag &= ~(PARENB | PARODD);
	
	// 入力モードの設定
	// 入力中の BREAK 信号を無視
	tio.c_iflag =  IGNBRK;
	// 出力の XON/XOFF フロー制御を無効、入力の XON/XOFF フロー制御を無効、任意の文字を入力すると、停止していた出力を再開したりする機能も無効
	tio.c_iflag &= ~(IXON|IXOFF|IXANY);
	
	// 出力モードは0クリア
	tio.c_oflag = 0;
	
	// ローカルモードも0クリア(非カノニカルモードになる)
	tio.c_lflag = 0;
	
	/// 非カノニカルモードの場合の最小受信文字数
	tio.c_cc[VMIN] = 1;
	/// 非カノニカルモードの場合のタイムアウト時間
	tio.c_cc[VTIME] = 5;
	
	// 端末に関連したパラメータを設定(TCSANOW:すぐに反映)
	tcsetattr(fd, TCSANOW, &tio);
	
// 戻る
}

// --------------------------------
// 現在時間を文字列で得る
// --------------------------------
void get_daytime(char *daytime_str)
{
	// ----------------
	// ローカル変数定義
	// ----------------
	// 日時情報テーブルローカル宣言
	struct timeval tv;
	// タイムゾーンテーブルローカル宣言(実際には使われない)
	struct timezone tz;
	// 文字列日時情報テーブルローカル宣言
	struct tm now;
	
	// ローカル変数を0で初期化
	memset(&tv, 0, sizeof(tv));
	memset(&tz, 0, sizeof(tz));
	// 日時情報文字列を初期化
	memset(daytime_str, 0, DAYTIME_LEN);
	
	// 現在日時を取得
	gettimeofday(&tv, &tz);
	
	// 文字列日時情報に変換
	localtime_r((const time_t*)&(tv.tv_sec), &now);
	
	// 日時情報文字列を引数の文字列ポインタに設定
	sprintf(daytime_str, "%04d/%02d/%02d %02d:%02d:%02d",
		now.tm_year + 1900,
		now.tm_mon + 1,
		now.tm_mday,
		now.tm_hour,
		now.tm_min,
		now.tm_sec );
	
	// 戻る
}

// --------------------------------
// シグナルハンドラ(ALARM)
// --------------------------------
void signal_alarm()
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	
	// SYSLOGメッセージ設定
	sprintf(logstr, "ALARM, Interrupt %s", SOFTNAME);
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
}

// --------------------------------------------------
// シグナルハンドラ(SIGHUP)
// --------------------------------------------------
void signal_sighup()
{
	// ----------------
	// ローカル変数定義
	// ----------------
	char logstr[BUFF_SIZE];
	
	// SYSLOGメッセージ設定
	sprintf(logstr, "SIGHUP, Stopped %s", SOFTNAME);
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	// 終わり
	exit(EXIT_SUCCESS);
}

// --------------------------------
// ログ出力
// --------------------------------
void put_log(int mode, char *logstr)
{
	// 通常モード(SYSLOG出力)なら
	if (mode == 0)
	{
		// syslogにメッセージを出力
		syslog(LOG_NOTICE, logstr);
	}
	// ログファイル別出力モードなら
	else if (mode == 1)
	{
		// 別ファイルに出力
		write(gvc_log_fp, (void *)logstr, strlen(logstr));
	}
	// 上記以外(ダンプモードとか)なら
	else
	{
		// 現在日時と合わせてログ文字列を表示
		printf("[%s] %s", daytime_str, logstr);
	}
}


// --------------------------------------------------
// Main Routine
// --------------------------------------------------
int main(int argc, char *argv[])
{
	// ----------------
	// ローカル変数定義
	// ----------------
	FILE *pidfile;										// PIDファイル用ポインタ
	struct stat pidstat;								// PIDファイル情報
	
	int argnum;											// 引数カウント用
	
	int func_num;										// キュー/メッセージ処理関数番号
	
	// logserial
	fd_set fds;											// file descriptor set for reading
	struct timeval tv;									// struct for time interval for select
	
	int rx_pos = 0;										// 受信データの位置
	int rx_len = 0;										// 受信データの長さ
	int rx_buffer_len = 0;								// 受信バッファの長さ
	int rx_remainder;									// 受信バッファの残りの先頭位置
	int rx_remainder_len = 0;							// 受信バッファの残りの長さ
	
///	int tx_len = 0;										// 送信できたデータの長さ
	
	int check_char;										// 受信バッファのチェック用ポインタ
	GVC_SERIAL_MESSAGE_t * gvc_serial_message;			// GVC シリアルメッセージ用ポインタ(シリアルデータにかぶせる)
	
	GVC_MESSAGE_QUEUE_t rcv_message_queue;				// 受信メッセージキュー
///	GVC_MESSAGE_QUEUE_t send_message_queue;				// 送信メッセージキュー
	int message_qid;									// メッセージキューID
	int msgq_length;									// メッセージの長さ
	key_t msgq_key;										// メッセージキューのキー
	int msgq_result;									// メッセージキュー送受信結果
	
	char logstr[BUFF_SIZE];
	
	// ----------------
	// 引数確認
	// ----------------
	// 引数が2より少ないなら
	if (argc < 2)
	{
		// ソフト名と使い方を表示
		printf("%s %s\n\n", SOFTNAME, VERSION);
		printf("%s [end]\n\n", argv[0]);
		printf(" -> %s /dev/ttyUSB0 [log=file]\n", argv[0]);
		// 終わり
		exit(1);
	}
	
	// 引数を検査
	for (argnum = 1; argnum < argc; argnum++)
	{
		// 引数の中にログファイル別出力指定があるなら
		if (strcasecmp("log=file", argv[argnum]) == 0)
		{
			// 動作モードログファイル別出力モード(1)にする
			gvcd_mode = 01;
		}
		// 引数の中にログファイル別出力指定があるなら
		if (strcasecmp("log=disp", argv[argnum]) == 0)
		{
			// 動作モードログファイル画面出力モード(2)にする
			gvcd_mode = 2;
		}
		// 引数の中にダンプモード指定があるなら
		if (strcasecmp("mode=dump", argv[argnum]) == 0)
		{
			// 動作モードをダンプモード(99)にする
			gvcd_mode = 99;
		}
	}
	
	// 通常モード(ログはSYSLOG出力)なら
	if (gvcd_mode == 0)
	{
		// ----------------
		// SYSLOGへの接続
		// ----------------
		openlog("gvcd", LOG_PID, LOG_DAEMON);
	}
	// ログファイル別出力モードなら
	else if (gvcd_mode == 1)
	{
		// ログファイルを開く
		gvc_log_fp = open(GVC_LOG_FILENAME, O_CREAT | O_APPEND | O_RDWR, 0755);
		// ログファイルが開けなかったら
		if (gvc_log_fp == -1)
		{
			// 最後のシステムエラーを表示
			perror(GVC_LOG_FILENAME);
			// 終わり
			exit(3);
		}
	}
	
	// 通常モードか、ログファイル別出力モードなら
	if ((gvcd_mode == 0) || (gvcd_mode == 1))
	{
		// ----------------
		// 子プロセス作成
		// ----------------
		switch (fork())
		{
			case 0 :     // 子プロセスは処理続行
/// デバッグ用
				// LOGメッセージ設定
///				sprintf(logstr, "Child Process is continue.");
				// ログにメッセージを出力
///				put_log(gvcd_mode, logstr);
				break;
			case -1 :    // fork関数異常終了
/// デバッグ用
				// LOGメッセージ設定
///				sprintf(logstr, "fork() error!?");
				// ログにメッセージを出力
///				put_log(gvcd_mode, logstr);
				return -1;
			default :    // 親プロセスは終了する
/// デバッグ用
				// LOGメッセージ設定
///				sprintf(logstr, "Parent Process is end.");
				// ログにメッセージを出力
///				put_log(gvcd_mode, logstr);
				// 終わり
				exit(0);
		}
		
		// ----------------
		// PIDファイルをチェック
		// ----------------
		// PIDファイルがないなら
		if (stat(GVC_PID_FILENAME, &pidstat) == -1)
		{
			// PIDファイルを新規に開く
			pidfile = fopen(GVC_PID_FILENAME, "w");
			// 開けなかったら
			if (pidfile == NULL)
			{
				// LOGメッセージ設定
				sprintf(logstr, "Could not open pid file : %s", GVC_PID_FILENAME);
				// ログにメッセージを出力
				put_log(gvcd_mode, logstr);
				// 終わり
				exit(EXIT_FAILURE);
			}
			// 開けたなら
			else
			{
/// デバッグ用
				// LOGメッセージ設定
///				sprintf(logstr, "Started Grobal Versatile Controler daemon");
				// ログにメッセージを出力
///				put_log(gvcd_mode, logstr);
			}
		}
		// PIDファイルがあるなら
		else
		{
			// LOGメッセージ設定
			sprintf(logstr, "Found a pid file : %s", GVC_PID_FILENAME);
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
			// 終わり
			exit(EXIT_FAILURE);
		}
		
		// 新しいセッション作成、が失敗したなら
		if (setsid() < 0)
		{
			// LOGメッセージ設定
			sprintf(logstr, "setsid error");
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
			// 終わり
			exit(EXIT_FAILURE);
		}
		else
		{
/// デバッグ用
			// LOGメッセージ設定
///			sprintf(logstr, "setsid OK");
			// ログにメッセージを出力
///			put_log(gvcd_mode, logstr);
		}
		
		// カレントディレクトリをトップに移動
		if (chdir("/") < 0)
		{
			// LOGメッセージ設定
			sprintf(logstr, "chdir / error");
			// ログにメッセージを出力
			put_log(gvcd_mode, logstr);
			// 終わり
			exit(EXIT_FAILURE);
		}
		else
		{
/// デバッグ用
			// LOGメッセージ設定
///			sprintf(logstr, "chdir / OK");
			// ログにメッセージを出力
///			put_log(gvcd_mode, logstr);
		}
		
		// umask をリセット
		umask(0);
		
		// PIDファイルに現在のPIDを出力
		fprintf(pidfile, "%ld\n", (long) getpid());
		fclose(pidfile);
		
		// stdin, stdout, stderrを閉じる
		int fd = 0;
		int fdlimit = sysconf(_SC_OPEN_MAX);
		while (fd < fdlimit)
		{
			close(fd++);
		}
	}
	
	// ----------------
	// 初期処理
	// ----------------
	// 受信バッファをクリア
	memset(rx_buffer, 0, BUFF_SIZE);
	
/// デバッグ用
	// LOGメッセージ設定
///	sprintf(logstr, "Device:%s Open!", argv[1] );
	// ログにメッセージを出力
///	put_log(gvcd_mode, logstr);
	
	// デバイス(シリアルポート)オープン:読み書き用、TTY制御せず
///	gvc_port = open(argv[1], O_RDWR);
	gvc_port = open(argv[1], O_RDWR | O_NOCTTY);
	// デバイスが開けなかったら
	if(gvc_port < 0)
	{
		// 最後のシステムエラーを表示
		perror(argv[1]);
		// 終わり
		exit(2);
	}
	
	// OKなら、シリアルポートを初期化
	serial_reset(gvc_port);
	
	// ----------------
	// GVCキュー処理テーブルの初期化処理(戻り値:int、メッセージそのものは(void *)に型キャストして渡す(メッセージの中身はそれぞれ異なるため)
	// ----------------
	for( func_num = 0; func_num <= 0xff; func_num++ )
	{
		// GVCメッセージ処理テーブルにダミー処理を入れる
		gvc_queue_job[func_num] = &gvc_q_job_dummy;
	}
	
	// ----------------
	// GVCメッセージ処理テーブルの初期化処理(戻り値:int、メッセージそのものは(void *)に型キャストして渡す(メッセージの中身はそれぞれ異なるため)
	// ----------------
	for( func_num = 0; func_num <= 0xff; func_num++ )
	{
		// GVCメッセージ処理テーブルにダミー処理を入れる
		gvc_msg_job[func_num] = &gvc_msg_job_dummy;
	}
	
	// ------------------------------
	// 個別にキュー処理関数のポインタを設定
	// ------------------------------
	gvc_queue_job[0x01] = &gvc_q_job_version;
	gvc_queue_job[0x02] = &gvc_q_job_modulelist;
	gvc_queue_job[0x03] = &gvc_q_job_moduledata;
	gvc_queue_job[0x20] = &gvc_q_job_switchoff;
	gvc_queue_job[0x21] = &gvc_q_job_switchon;
	gvc_queue_job[0x2f] = &gvc_q_job_switchstatus;
	gvc_queue_job[0x91] = &gvc_q_job_irtx;
	gvc_queue_job[0x92] = &gvc_q_job_irrx;
	gvc_queue_job[0x93] = &gvc_q_job_irset;
	gvc_queue_job[0x94] = &gvc_q_job_irget;
	gvc_queue_job[0x95] = &gvc_q_job_irdel;
	gvc_queue_job[0x7e] = &gvc_q_job_masterreset;
	gvc_queue_job[0x7f] = &gvc_q_job_masterstop;
	gvc_queue_job[0xff] = &gvc_q_job_daemonstop;
	
	// ------------------------------
	// 個別にメッセージ処理関数のポインタを設定
	// ------------------------------
	gvc_msg_job[GVC_MSG_DELIMITER] = &gvc_msg_job_delimiterframe;
	gvc_msg_job[GVC_MSG_OTHER] = &gvc_msg_job_other;
	gvc_msg_job[GVC_MSG_DIST] = &gvc_msg_job_distance;
	gvc_msg_job[GVC_MSG_HUMI] = &gvc_msg_job_humidity;
	gvc_msg_job[GVC_MSG_IR] = &gvc_msg_job_ir;
	gvc_msg_job[GVC_MSG_TEMP] = &gvc_msg_job_temperature;
	gvc_msg_job[GVC_MSG_LIGHT] = &gvc_msg_job_light;
	gvc_msg_job[GVC_MSG_PRESS] = &gvc_msg_job_pressure;
	
	// メッセージキューのメッセージの長さを設定
	msgq_length = sizeof(GVC_MESSAGE_QUEUE_t) - sizeof(unsigned long);
	
	// パス名とプロジェクト識別子を System V IPC キーに変換する(命令キュー)
	// gvcdが動いていることが前提なので、gvcdのPIDファイルから生成すればOK。
	msgq_key = ftok(GVC_PID_FILENAME, 'w');
	
	// メッセージキューを作成(新規作成だが、既存だった場合にはエラー…にした方がいいのか、どうなのか?
//	message_qid = msgget(msgq_key, IPC_CREAT | IPC_EXCL | 0660);
	// コマンド(gvc_cmd系)の実行を誰でもできるようにするなら0666とすること)
	message_qid = msgget(msgq_key, IPC_CREAT | 0666);
	
	// メッセージキューが作成できたなら(message_qid!=-1)
	if (message_qid != -1)
	{
/// デバッグ用
		// LOGメッセージ設定
///		sprintf(logstr, "QID = %d, msgq_length=%d", message_qid, msgq_length);
		// ログにメッセージを出力
///		put_log(gvcd_mode, logstr);
	}
	// メッセージキューが作成できなかったら(message_qid=-1)
	else
	{
		// LOGメッセージ設定
		sprintf(logstr, "Message Queue make error : %s", strerror(errno));
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
		// 終わり
		exit(EXIT_FAILURE);
	}
	
	//メッセージキューのメッセージ部分を初期化
	memset((void *)&rcv_message_queue.q, msgq_length, 0x00);
	
	// データ格納フラグ初期化
	datafp_flag = 0;
	
	// ------------------------------
	// メインの無限ループ
	// ------------------------------
	
	// 受信バッファを初期化
	memset((void *)rx_buffer, 0x00, BUFF_SIZE);
	
	// 受信バッファにGVC_SERIAL_MESSAGE_tをかぶせる
	gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)rx_buffer;
	
	// 起動メッセージを受信データに設定
	gvc_serial_message->msg_type = GVC_MSG_OTHER;		// メッセージタイプを設定
	gvc_serial_message->dev_num = 0xFF;					// デバイス番号を設定
	gvc_serial_message->format = 0x01;					// フォーマットを設定(0x01=通常テキスト)
	gvc_serial_message->cmd = 0x01;						// 結果(情報種別)を設定(0x01=初期情報、システム情報)
	sprintf((char *)gvc_serial_message->data, "%s Ver.%s Start (_IO_BUFSIZ=%d)", SOFTNAME, VERSION, _IO_BUFSIZ);	// データを設定
	gvc_serial_message->data_len = strlen((char *)gvc_serial_message->data);		// データ長を設定
	// CRCを計算して、メッセージの最後に設定
	gvc_serial_message->data[ gvc_serial_message->data_len ] = GetCRC8((void *)gvc_serial_message, GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_serial_message->data_len);
	// ↑データを送信する側は、データのCRCを計算したあとで
	//  そのCRCをデータの最後に連結して相手に送ればいい

	// 受信バッファにデータを格納する位置を設定
	rx_pos = GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_serial_message->data_len + 1;
	// 受信バッファの長さを設定
	rx_buffer_len = rx_pos;
	
	while(1)
	{
		// GVCコマンド送信可能状態(=1)なら
		while(gvc_cmd_ready)
		{
			// メッセージ受信…ここではgvcdに対しての命令を送信している
			// 「求めているメッセージがない」こともある.msgflgとしてIPC_NOWAITが指定されてい
			// る場合にはすぐにエラーを返すが,そうでない場合には求めるメッセージが得られるか,
			// キューが消えるか,シグナルで捕獲されるまで待つ.
			msgq_result = msgrcv(message_qid, &rcv_message_queue, msgq_length, COMMAND_Q, IPC_NOWAIT);
			
			// メッセージが受信できたなら(!=-1)
			if (msgq_result != -1)
			{
				// ここで本来は受信したキューメッセージのCRCのチェックをしたいが…
				// メッセージキュー、というかLinuxレベルになるとテーブル構造体のアラインメントが行われるから実質できない。
				
				// 時間を取得(グローバル変数に格納)
				get_daytime(daytime_str);
				// キューに基づいて処理
				gvc_queue_job[ rcv_message_queue.q.cmd ]( (void *)&rcv_message_queue );
				
				// もしENDコマンドがきていたら
				if (rcv_message_queue.q.cmd == 0xff)
				{
					// 終了する
					goto END_JOB;
				} 
			}
			// メッセージが受信できなかったら(=-1)
			else
			{
				// メッセージがない、ではなかったら
				if (errno != ENOMSG)
				{
					// LOGメッセージ設定
					sprintf(logstr, "QUEUE ERROR : %s", strerror(errno));
					// ログにメッセージを出力
					put_log(gvcd_mode, logstr);
					// 終了する
					goto END_JOB;
				}
				// 特にメッセージがないなら
				else
				{
					// メッセージキュー受信から抜ける
					break;
				}
			}
		}
		// GVCコマンド送信可能状態をデリミタ待ち(=0)に設定
		gvc_cmd_ready = 0;
		
		// 受信待ちタイムアウト時間を設定 (1秒まつ)
		tv.tv_sec  = 1;
		tv.tv_usec = 0;
		
		// ファイルディスクリプタをいったん初期化(0リセット)
		FD_ZERO(&fds );
		// ファイルディスクリプタを設定
		FD_SET(gvc_port, &fds);
		
		// 何かデータが来たか、もしくはタイムアウトなら
		if (select(gvc_port + 1, &fds, NULL, NULL, &tv) > 0)
		{
			// シリアルポートからデータを受信バッファに取得
			rx_len = read(gvc_port, rx_buffer + rx_pos, BUFF_SIZE);
			
			// 読み出しエラーなら
			if (rx_len < 0)
			{
				// もし割り込みによる中断だったら
				if (errno == EINTR)
				{
					// LOGメッセージ設定
					sprintf(logstr, "READ is EINTR. rx_len=%d, errno=%d", rx_len, errno);
					// ログにメッセージを出力
					put_log(gvcd_mode, logstr);
				}
				// それ以外の場合には
				else
				{
					// LOGメッセージ設定
					sprintf(logstr, "READ is OTHER ERROR !? rx_len=%d, errno=%d", rx_len, errno);
					// ログにメッセージを出力
					put_log(gvcd_mode, logstr);
					// 終了する
					goto END_JOB;
				}
			}
			// 読み出しサイズがなかった場合には
			else if (rx_len == 0)
			{
				// LOGメッセージ設定
				sprintf(logstr, "READ is ZERO !? rx_len=%d, errno=%d", rx_len, errno);
				// ログにメッセージを出力
				put_log(gvcd_mode, logstr);
				// 受信しなおし
				continue;
			}
			// 正常に読めたときには
			else
			{
				// 次の受信位置を設定
				rx_pos += rx_len;
				// 受信バッファ長を設定
				rx_buffer_len += rx_len;
			}
		}
		
		// マスターコントローラーからのメッセージ待ち
		// rx_buffer_lenが最小メッセージサイズ以上の(5倍くらいの)長さがあるなら、解析処理をする
		if (rx_buffer_len >= GVC_MIN_MESSAGE_LENGTH)
		{
			// 0からrx_len-GVC_MIN_MESSAGE_LENGTHの中に有効なメッセージタイプがあるかどうかスキャン
			for (check_char = 0; check_char <= (rx_buffer_len - GVC_MIN_MESSAGE_LENGTH); check_char ++)
			{
				// 0xaaが合ったら、
				if (rx_buffer[check_char] == 0xaa)
				{
					// rx_buffer_lenがcheck_char+DELIMITER_LENGTH+1以上あるなら
					if (rx_buffer_len >= check_char + (DELIMITER_LENGTH + 1))
					{
						// そこから16バイト比較してデリミタメッセージであり、かつCRCチェックもOKなら
						if (memcmp(rx_buffer + check_char, (void *)GVC_DELIMITER_MSG, DELIMITER_LENGTH) == 0 &&
							GetCRC8((void *)(rx_buffer + check_char), (DELIMITER_LENGTH + 1)) == 0 )
						{
							// 時間を取得(グローバル変数に格納)
							get_daytime(daytime_str);
							// メッセージに基づいて処理
							gvc_msg_job_delimiterframe((void *)rx_buffer + check_char);
							
							// あまったデータの先頭位置を設定
							rx_remainder = check_char + (DELIMITER_LENGTH + 1);
							// あまったデータを計算
							rx_remainder_len = rx_buffer_len - rx_remainder;
							
							// あまったデータがないなら
							if (rx_remainder_len == 0)
							{
								// 次の受信バッファポインタを設定
								rx_pos = 0;
								// 受信バッファ長を設定
								rx_buffer_len = 0;
							}
							// あまったデータがあるなら
							else
							{
								// メッセージの次から残りのデータを受信バッファの先頭にコピー
								memmove(rx_buffer, rx_buffer + rx_remainder, rx_remainder_len);
								// 次の受信バッファポインタを設定
								rx_pos = rx_remainder_len;
								// 受信バッファ長を設定
								rx_buffer_len = rx_remainder_len;
							}
							
							// スキャンループから抜ける
							break;
						}
					}
				}
				// 有効なメッセージタイプがあったら、
				else if (gvc_msg_job[ rx_buffer[check_char] ] != &gvc_msg_job_dummy)
				{
					// 受信バッファにGVC_SERIAL_MESSAGE_tをかぶせる
					gvc_serial_message = (GVC_SERIAL_MESSAGE_t *)(rx_buffer + check_char);
					
					// 受信バッファ内にCRCまで含めたメッセージフレームが収まっているなら
					if ( rx_buffer_len >= check_char + (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_serial_message->data_len + 1) )
					{
						// CRCチェックしてOKなら
						if ( GetCRC8((void *)gvc_serial_message, (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_serial_message->data_len + 1)) == 0 )
						{
							// 時間を取得(グローバル変数に格納)
							get_daytime(daytime_str);
							// メッセージに基づいて処理
							gvc_msg_job[  gvc_serial_message->msg_type ]( (void *)gvc_serial_message );
							
							// あまったデータの先頭位置を設定
							rx_remainder = check_char + (GVC_SERIAL_MESSAGE_HEADER_SIZE + gvc_serial_message->data_len + 1);
							// あまったデータを計算
							rx_remainder_len = rx_buffer_len - rx_remainder;
							
							// あまったデータがないなら
							if (rx_remainder_len == 0)
							{
								// 次の受信バッファポインタを設定
								rx_pos = 0;
								// 受信バッファ長を設定
								rx_buffer_len = 0;
							}
							// あまったデータがあるなら
							else
							{
								// メッセージの次から残りのデータを受信バッファの先頭にコピー
								memmove(rx_buffer, rx_buffer + rx_remainder, rx_remainder_len);
								// 次の受信バッファポインタを設定
								rx_pos = rx_remainder_len;
								// 受信バッファ長を設定
								rx_buffer_len = rx_remainder_len;
							}
							
							// スキャンループから抜ける
							break;
						}
					}
				}
				else
				{
				}
			}
		}
	}
	// 終了する場合にここに飛ぶ
	END_JOB:
	// ポートを閉じる
	close(gvc_port);
	
	// 通常モードか、ログファイル別出力モードなら
	if ((gvcd_mode == 0) || (gvcd_mode == 1))
	{
		// PIDファイルを削除
		unlink(GVC_PID_FILENAME);
		// LOGメッセージ設定
		sprintf(logstr, "DELETED PID FILE");
		// ログにメッセージを出力
		put_log(gvcd_mode, logstr);
	}
	
	// メッセージキューを破棄
	msgctl(message_qid, IPC_RMID, 0);
	// LOGメッセージ設定
	sprintf(logstr, "MESSAGE QUEUE DELETED");
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	// LOGメッセージ設定
	sprintf(logstr, "GVCD END. Thank you! :-)");
	// ログにメッセージを出力
	put_log(gvcd_mode, logstr);
	
	// 終わり
	return 0;
}