// -------------------------------------------------- // 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; }