--- /dev/null
+/**
+ * @file optparse.c
+ * @author Shinichiro Nakamura
+ * @brief オプション解析モジュールの実装。
+ */
+
+/*
+ * ===============================================================
+ * Option parse library
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include <string.h>
+#include "optparse.h"
+
+int optparse_char(
+ int argc,
+ char **argv,
+ void *extobj,
+ int (*callback)(
+ const char option, const char *argument, void *extobj))
+{
+ int i;
+ for (i = 1; i < argc;) {
+ int r = 0;
+ int c = 0;
+ if (argv[i][0] == '-') {
+ /*
+ * 与えられた文字列は引数である。
+ */
+ if (strlen(argv[i]) > 2) {
+ /*
+ * 同じ箇所にアーギュメントが指定されている。
+ */
+ r = callback(argv[i][1], &argv[i][2], extobj);
+ c = 1;
+ } else {
+ if ((i + 1) < argc) {
+ /*
+ * まだ続きがありそうだ。
+ * 先を見ておこう。
+ */
+ if (argv[i + 1][0] == '-') {
+ /*
+ * その引数にアーギュメントはない。
+ */
+ r = callback(argv[i][1], "", extobj);
+ c = 1;
+ } else {
+ /*
+ * その引数にアーギュメントがある。
+ */
+ r = callback(argv[i][1], argv[i + 1], extobj);
+ c = 2;
+ }
+ } else {
+ /*
+ * もう先がない。
+ * ということはアーギュメントはない。
+ */
+ r = callback(argv[i][1], "", extobj);
+ c = 1;
+ }
+ }
+ } else {
+ /*
+ * 与えられた文字列はオプションでない
+ * 単独アーギュメントである。
+ */
+ r = callback('\x00', &argv[i][0], extobj);
+ c = 1;
+ }
+ i += c;
+ if (r != 0) {
+ break;
+ }
+ }
+ return 0;
+}
+
+int optparse_text(
+ int argc,
+ char **argv,
+ void *extobj,
+ int (*callback)(
+ const char *option, const char *argument, void *extobj))
+{
+ int i;
+ for (i = 1; i < argc;) {
+ int r = 0;
+ int c = 0;
+ if (argv[i][0] == '-') {
+ /*
+ * 与えられた文字列は引数である。
+ */
+ if ((i + 1) < argc) {
+ /*
+ * まだ続きがありそうだ。
+ * 先を見ておこう。
+ */
+ if (argv[i + 1][0] == '-') {
+ /*
+ * その引数にアーギュメントはない。
+ */
+ r = callback(&argv[i][1], "", extobj);
+ c = 1;
+ } else {
+ /*
+ * その引数にアーギュメントがある。
+ */
+ r = callback(&argv[i][1], argv[i + 1], extobj);
+ c = 2;
+ }
+ } else {
+ /*
+ * もう先がない。
+ * ということはアーギュメントはない。
+ */
+ r = callback(&argv[i][1], "", extobj);
+ c = 1;
+ }
+ } else {
+ /*
+ * 与えられた文字列はオプションでない
+ * 単独アーギュメントである。
+ */
+ r = callback("", &argv[i][0], extobj);
+ c = 1;
+ }
+ i += c;
+ if (r != 0) {
+ break;
+ }
+ }
+ return 0;
+}
+
--- /dev/null
+/**
+ * @file optparse.h
+ * @author Shinichiro Nakamura
+ * @brief オプション解析モジュールの定義。
+ */
+
+/*
+ * ===============================================================
+ * Option parse library
+ * Version 0.0.1
+ * ===============================================================
+ * Copyright (c) 2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef OPTPARSE_H
+#define OPTPARSE_H
+
+int optparse_char(
+ int argc,
+ char **argv,
+ void *extobj,
+ int (*callback)(
+ const char option, const char *argument, void *extobj));
+
+int optparse_text(
+ int argc,
+ char **argv,
+ void *extobj,
+ int (*callback)(
+ const char *option, const char *argument, void *extobj));
+
+#endif
+
--- /dev/null
+ntlcap : Makefile captime.h captime_linux.c ntlcap.c serial.h serial_linux.c ../common/optparse.c ../common/optparse.h
+ $(CC) -o $@ ntlcap.c captime_linux.c serial_linux.c ../common/optparse.c -I../common
--- /dev/null
+/**
+ * @file captime.h
+ * @author Shinichiro Nakamura
+ * @brief キャプチャ時間モジュールの定義。
+ */
+
+/*
+ * ===============================================================
+ * Natural Tiny Logger (NT-Logger)
+ * ===============================================================
+ * Copyright (c) 2010-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef CAPTIME_H
+#define CAPTIME_H
+
+typedef struct CAPTIME CAPTIME;
+
+typedef struct {
+ int year;
+ int month;
+ int day;
+ int hour;
+ int min;
+ int sec;
+ int usec;
+} captime_t;
+
+CAPTIME *captime_open(void);
+void captime_read(CAPTIME *cp, captime_t *t);
+void captime_close(CAPTIME *cp);
+
+#endif
+
--- /dev/null
+/**
+ * @file captime_linux.c
+ * @author Shinichiro Nakamura
+ * @brief キャプチャ時間モジュールのLinux実装。
+ */
+
+/*
+ * ===============================================================
+ * Natural Tiny Logger (NT-Logger)
+ * ===============================================================
+ * Copyright (c) 2010-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include "captime.h"
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+struct CAPTIME {
+ int dummy;
+};
+
+CAPTIME *captime_open(void)
+{
+ CAPTIME *cp = (CAPTIME *)malloc(sizeof(CAPTIME));
+ return cp;
+}
+
+void captime_read(CAPTIME *cp, captime_t *t)
+{
+ struct timeval tv;
+ struct timezone tz;
+ gettimeofday(&tv, &tz);
+ struct tm *tm = localtime(&tv.tv_sec);
+ t->year = 1900 + tm->tm_year;
+ t->month = 1 + tm->tm_mon;
+ t->day = tm->tm_mday;
+ t->hour = tm->tm_hour;
+ t->min = tm->tm_min;
+ t->sec = tm->tm_sec;
+ t->usec = tv.tv_usec;
+}
+
+void captime_close(CAPTIME *cp)
+{
+ if (cp != NULL) {
+ free(cp);
+ }
+}
+
--- /dev/null
+/**
+ * @file ntlcap.c
+ * @author Shinichiro Nakamura
+ * @brief Natural Tiny Logger (NT-Logger)のホスト側キャプチャ。
+ */
+
+/*
+ * ===============================================================
+ * Natural Tiny Logger (NT-Logger)
+ * ===============================================================
+ * Copyright (c) 2010-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "captime.h"
+#include "serial.h"
+#include "optparse.h"
+
+/**
+ * @brief オプションを初期化する。
+ *
+ * @param P オプション構造体へのポインタ。
+ */
+#define OPTION_INIT(P) \
+ do { \
+ (P)->optflag = 0; \
+ strcpy((P)->portname, ""); \
+ (P)->baudrate = SerialBaud9600; \
+ strcpy((P)->output, ""); \
+ (P)->count = 0; \
+ } while (0)
+
+#define OPTFLAG_PORTNAME (1 << 0) /**< ポート名。 */
+#define OPTFLAG_BAUDRATE (1 << 1) /**< ボーレート。 */
+#define OPTFLAG_OUTPUT (1 << 2) /**< 出力ファイル名。 */
+#define OPTFLAG_COUNT (1 << 3) /**< 記録イベント数。 */
+
+/**
+ * @brief オプション構造体。
+ */
+typedef struct {
+ unsigned char optflag; /**< オプション指定確認用フラグ。 */
+ char portname[BUFSIZ]; /**< ポート名。 */
+ enum SerialBaud baudrate; /**< ボーレート。 */
+ char output[BUFSIZ]; /**< 出力ファイル名。 */
+ int count; /**< 記録イベント数。 */
+} option_t;
+
+/**
+ * @brief オプション分割装置用のコールバック関数。
+ *
+ * @param option オプション文字。
+ * @param argument オプション文字に対する引数。
+ * @param extobj 外部オブジェクト。
+ *
+ * @retval 0 解析継続。
+ * @retval !0 解析中断。
+ */
+static int option_callback(
+ const char option, const char *argument, void *extobj)
+{
+ option_t *opt = (option_t *)extobj;
+ switch (option) {
+ case 'p':
+ strcpy(opt->portname, argument);
+ opt->optflag |= OPTFLAG_PORTNAME;
+ break;
+ case 'b':
+ switch (atoi(argument)) {
+ case 2400:
+ opt->baudrate = SerialBaud2400;
+ break;
+ case 4800:
+ opt->baudrate = SerialBaud4800;
+ break;
+ case 9600:
+ opt->baudrate = SerialBaud9600;
+ break;
+ case 19200:
+ opt->baudrate = SerialBaud19200;
+ break;
+ case 38400:
+ opt->baudrate = SerialBaud38400;
+ break;
+ }
+ opt->optflag |= OPTFLAG_BAUDRATE;
+ break;
+ case 'o':
+ strcpy(opt->output, argument);
+ opt->optflag |= OPTFLAG_OUTPUT;
+ break;
+ case 'c':
+ opt->count = atoi(argument);
+ opt->optflag |= OPTFLAG_COUNT;
+ break;
+ }
+ return 0;
+}
+
+/**
+ * @brief エントリーポイント。
+ *
+ * @param argc 引数の数。
+ * @param argv 引数のポインタのポインタ。
+ *
+ * @return シェルに返す値。
+ */
+int main(int argc, char **argv)
+{
+ int i;
+ option_t opt;
+ CAPTIME *cap;
+ SERIAL *ser;
+ FILE *fp;
+
+ /*
+ * オプション解析を実行する。
+ */
+ OPTION_INIT(&opt);
+ optparse_char(argc, argv, &opt, option_callback);
+ if (opt.optflag !=
+ (OPTFLAG_PORTNAME |
+ OPTFLAG_BAUDRATE |
+ OPTFLAG_OUTPUT |
+ OPTFLAG_COUNT)) {
+ printf("ntlcap -p <port name> -b <baud rate> -o <output> -c <count>\n");
+ return 1;
+ }
+
+ /*
+ * キャプチャ時間モジュールを開く。
+ */
+ cap = captime_open();
+
+ /*
+ * シリアルを開く。
+ */
+ ser = serial_open(opt.portname, opt.baudrate);
+ if (ser == NULL) {
+ printf("Serial open failed.\n");
+ return 1;
+ }
+
+ /*
+ * 出力ファイルを開く。
+ */
+ fp = fopen(opt.output, "w");
+ if (fp == NULL) {
+ printf("File open failed.\n");
+ return 1;
+ }
+
+ /*
+ * 指定されたイベント数に達するまでファイルに保存する。
+ */
+ for (i = 0; i < opt.count; i++) {
+ unsigned char evt;
+ captime_t t;
+ serial_read(ser, &evt, 1);
+ captime_read(cap, &t);
+ fprintf(fp, "%4d/%02d/%02d %02d:%02d:%02d.%06d %02X\n",
+ t.year, t.month, t.day,
+ t.hour, t.min, t.sec,
+ t.usec, evt);
+ }
+
+ /*
+ * 出力ファイルを閉じる。
+ */
+ fclose(fp);
+
+ /*
+ * シリアルを閉じる。
+ */
+ serial_close(ser);
+
+ /*
+ * キャプチャ時間モジュールを閉じる。
+ */
+ captime_close(cap);
+
+ return 0;
+}
+
--- /dev/null
+/**
+ * @file serial.h
+ * @author Shinichiro Nakamura
+ * @brief シリアルポートドライバのインターフェース定義。
+ */
+
+/*
+ * ===============================================================
+ * Serial interface library
+ * Version 0.0.4
+ * ===============================================================
+ * Copyright (c) 2010-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef SERIAL_H
+#define SERIAL_H
+
+#include <stdio.h>
+
+typedef struct serial SERIAL;
+
+/**
+ * @brief ボーレート.
+ */
+enum SerialBaud {
+ SerialBaud2400,
+ SerialBaud4800,
+ SerialBaud9600,
+ SerialBaud19200,
+ SerialBaud38400,
+ SerialBaud57600
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * シリアルポートをオープンする.
+ *
+ * @param devfile シリアルポートのデバイスファイル名.
+ * @param baud ボーレート.
+ *
+ * @retval !NULL ハンドラ。
+ * @retval NULL 失敗。
+ */
+SERIAL *serial_open(const char *devfile, const enum SerialBaud baud);
+
+/**
+ * シリアルポートをクローズする.
+ *
+ * @param s シリアルデスクリプタへのポインタ.
+ *
+ * @return 成功したら0を返す.
+ */
+int serial_close(SERIAL * s);
+
+/**
+ * シリアルポートから指定バイト数の読み込みを実行する.
+ *
+ * @param s シリアルデスクリプタへのポインタ.
+ * @param buf バッファへのポインタ.
+ * @param size 読み込みバイト数.
+ *
+ * @return 成功したら0を返す.
+ */
+int serial_read(SERIAL * s, unsigned char *buf, const size_t size);
+
+/**
+ * シリアルポートから指定バイト数の読み込みを実行する.
+ *
+ * @param s シリアルデスクリプタへのポインタ.
+ * @param buf バッファへのポインタ.
+ * @param size 読み込みバイト数.
+ * @param ms ミリ秒単位のタイムアウト時間.
+ *
+ * @return 成功したら0を返す.
+ */
+int serial_read_with_timeout(
+ SERIAL * s, unsigned char *buf, const size_t size, const int ms);
+
+/**
+ * シリアルポートへ指定バイト数の書き込みを実行する.
+ *
+ * @param s シリアルデスクリプタへのポインタ.
+ * @param buf バッファへのポインタ.
+ * @param size 書き込みバイト数.
+ *
+ * @return 成功したら0を返す.
+ */
+int serial_write(SERIAL * s, const unsigned char *buf, const size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/**
+ * @file serial_linux.c
+ * @author Shinichiro Nakamura
+ * @brief シリアルポートドライバの実装。(Linuxプラットフォーム用)
+ */
+
+/*
+ * ===============================================================
+ * Serial interface library
+ * Version 0.0.4
+ * ===============================================================
+ * Copyright (c) 2010-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <limits.h>
+#include <pthread.h>
+#include "serial.h"
+
+#define MUTEX_INIT() pthread_mutex_init(&(s->mutex), NULL)
+#define MUTEX_LOCK() pthread_mutex_lock(&(s->mutex))
+#define MUTEX_UNLOCK() pthread_mutex_unlock(&(s->mutex))
+
+struct serial {
+ char devfile[BUFSIZ];
+ int fd;
+ struct termios termios_old;
+ struct termios termios_new;
+ pthread_mutex_t mutex;
+};
+
+/**
+ * シリアルポートをオープンする.
+ *
+ * @param devfile シリアルポートのデバイスファイル名.
+ * @param baud ボーレート.
+ *
+ * @retval !NULL ハンドラ。
+ * @retval NULL 失敗。
+ */
+SERIAL *serial_open(const char *devfile, const enum SerialBaud baud)
+{
+ int baudrate = 0;
+
+ /*
+ * シリアルデスクリプタの管理領域を確保する.
+ */
+ SERIAL *s = (SERIAL *) malloc(sizeof(SERIAL));
+ if (s == NULL) {
+ return NULL;
+ }
+
+ /*
+ * ミューテックスを初期化する.
+ */
+ MUTEX_INIT();
+
+ /*
+ * ポートを開く.
+ */
+ strcpy(s->devfile, devfile);
+ s->fd = open(devfile, O_RDWR | O_NOCTTY | O_NDELAY);
+ if (s->fd < 0) {
+ free(s);
+ return NULL;
+ }
+
+ /*
+ * ポート設定を退避する.
+ */
+ tcgetattr(s->fd, &(s->termios_old));
+
+ /*
+ * ポート設定を初期化する.
+ */
+ memset(&(s->termios_new), 0x00, sizeof(s->termios_new));
+
+ /*
+ * Bxxxxx : ボーレートの設定.cfsetispeed と cfsetospeed も使用できる
+ * CS8 : 8n1 (8 ビット,ノンパリティ,ストップビット 1)
+ * CLOCAL : ローカル接続,モデム制御なし
+ * CREAD : 受信文字(receiving characters)を有効にする
+ */
+ s->termios_new.c_cflag = CS8 | CLOCAL | CREAD;
+ switch (baud) {
+ case SerialBaud2400:
+ s->termios_new.c_cflag |= B2400;
+ baudrate = 2400;
+ break;
+ case SerialBaud4800:
+ s->termios_new.c_cflag |= B4800;
+ baudrate = 4800;
+ break;
+ case SerialBaud9600:
+ s->termios_new.c_cflag |= B9600;
+ baudrate = 9600;
+ break;
+ case SerialBaud19200:
+ s->termios_new.c_cflag |= B19200;
+ baudrate = 19200;
+ break;
+ case SerialBaud38400:
+ s->termios_new.c_cflag |= B38400;
+ baudrate = 38400;
+ break;
+ case SerialBaud57600:
+ s->termios_new.c_cflag |= B57600;
+ baudrate = 57600;
+ break;
+ default:
+ s->termios_new.c_cflag |= B9600;
+ baudrate = 9600;
+ break;
+ }
+ cfsetispeed(&(s->termios_new), baudrate);
+ cfsetospeed(&(s->termios_new), baudrate);
+
+ /*
+ * IGNPAR : パリティエラーのデータは無視する
+ */
+ s->termios_new.c_iflag = IGNPAR;
+
+ /*
+ * Raw モードでの出力
+ */
+ s->termios_new.c_oflag = 0;
+
+ /*
+ * 入力モードをノンカノニカル、ノンエコーに設定する
+ */
+ s->termios_new.c_lflag = 0;
+
+ /*
+ * モデムラインをクリアし,ポートの設定を有効にする
+ */
+ tcflush(s->fd, TCIFLUSH);
+ tcsetpgrp(s->fd, getpgrp());
+ tcsetattr(s->fd, TCSANOW, &(s->termios_new));
+
+ return s;
+}
+
+/**
+ * シリアルポートをクローズする.
+ *
+ * @param s シリアルデスクリプタへのポインタ.
+ *
+ * @return 成功したら0を返す.
+ */
+int serial_close(SERIAL * s)
+{
+ /*
+ * ポート設定を元に戻す.
+ */
+ tcsetattr(s->fd, TCSANOW, &(s->termios_old));
+
+ /*
+ * ポートを閉じる.
+ */
+ close(s->fd);
+
+ /*
+ * シリアルデスクリプタの管理領域を破棄する.
+ */
+ free(s);
+
+ return 0;
+}
+
+/**
+ * シリアルポートから指定バイト数の読み込みを実行する.
+ *
+ * @param s シリアルデスクリプタへのポインタ.
+ * @param buf バッファへのポインタ.
+ * @param size 読み込みバイト数.
+ *
+ * @return 成功したら0を返す.
+ */
+int serial_read(SERIAL * s, unsigned char *buf, const size_t size)
+{
+ int e = 0;
+ int rcvcnt = 0;
+
+ MUTEX_LOCK();
+
+ /*
+ * 読み込みを実行する.
+ */
+ while (rcvcnt < size) {
+ int r = read(s->fd, buf + rcvcnt, size - rcvcnt);
+ if (r < 0) {
+ e = 1;
+ break;
+ }
+ rcvcnt += r;
+ }
+
+ MUTEX_UNLOCK();
+
+ return e;
+}
+
+/**
+ * シリアルポートから指定バイト数の読み込みを実行する.
+ *
+ * @param s シリアルデスクリプタへのポインタ.
+ * @param buf バッファへのポインタ.
+ * @param size 読み込みバイト数.
+ * @param ms ミリ秒単位のタイムアウト時間.
+ *
+ * @return 成功したら0を返す.
+ */
+int serial_read_with_timeout(SERIAL * s,
+ unsigned char *buf, const size_t size, const int ms)
+{
+ int e = 0;
+ int i;
+
+ MUTEX_LOCK();
+
+ /*
+ * タイムアウトを設定して読み込みを実行する.
+ */
+ for (i = 0; i < (int) size; i++) {
+ struct pollfd fds;
+ fds.fd = s->fd;
+ fds.events = POLLIN;
+ poll(&fds, 1, ms);
+ if (fds.revents & POLLIN) {
+ /*
+ * 1バイトの読み込みを実行.
+ */
+ int r = read(s->fd, buf + i, 1);
+ if (r < 0) {
+ e = 1;
+ break;
+ }
+ } else {
+ /*
+ * タイムアウトが発生した.
+ */
+ e = 2;
+ break;
+ }
+ }
+
+ MUTEX_UNLOCK();
+
+ return e;
+}
+
+/**
+ * シリアルポートへ指定バイト数の書き込みを実行する.
+ *
+ * @param s シリアルデスクリプタへのポインタ.
+ * @param buf バッファへのポインタ.
+ * @param size 書き込みバイト数.
+ *
+ * @return 成功したら0を返す.
+ */
+int serial_write(SERIAL * s,
+ const unsigned char *buf, const size_t size)
+{
+ int e = 0;
+ int sndcnt = 0;
+
+ MUTEX_LOCK();
+
+ while (sndcnt < size) {
+ int r = write(s->fd, buf + sndcnt, size - sndcnt);
+ if (r < 0) {
+ e = 1;
+ break;
+ }
+ sndcnt += r;
+ }
+
+ MUTEX_UNLOCK();
+
+ return e;
+}
+
--- /dev/null
+ntlgen : ntlgen.c fifo.c fifo.h
+ $(CC) -o $@ ntlgen.c fifo.c ../common/optparse.c -I../../target/ -I../common
--- /dev/null
+/**
+ * @file fifo.h
+ * @author Shinichiro Nakamura
+ * @brief FIFOモジュールの実装。
+ */
+
+/*
+ * ===============================================================
+ * Natural Tiny Logger (NT-Logger)
+ * ===============================================================
+ * Copyright (c) 2010-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "fifo.h"
+
+/**
+ * @brief FIFOハンドラの実装。
+ */
+struct FIFO {
+ int depth; /**< FIFOの深さ。 */
+ int count; /**< 格納されているオブジェクト数。 */
+ int rp; /**< リードポインタ。 */
+ int wp; /**< ライトポインタ。 */
+ void **objlist; /**< オブジェクトリスト。 */
+};
+
+/**
+ * @brief FIFOモジュールをオープンする。
+ *
+ * @param depth FIFOの深さ。
+ *
+ * @retval !NULL FIFOハンドラ。
+ * @retval NULL 失敗。
+ */
+FIFO *fifo_open(const int depth)
+{
+ FIFO *p = (FIFO *)malloc(sizeof(FIFO));
+ if (p == NULL) {
+ return NULL;
+ }
+ /*
+ * ユーザが示したdepthは、格納できる長さなので、+1した値が本当に格納可能なオブジェクト数。
+ */
+ p->depth = depth + 1;
+ p->count = 0;
+ p->rp = 0;
+ p->wp = 0;
+ p->objlist = (void **)malloc(sizeof(void *) * p->depth);
+ if (p->objlist == NULL) {
+ free(p);
+ return NULL;
+ }
+ return p;
+}
+
+/**
+ * @brief FIFOが一杯かどうかを検査する。
+ *
+ * @param p FIFOハンドラ。
+ *
+ * @retval 1 FIFOが一杯である。
+ * @retval 0 FIFOが一杯でない。
+ */
+int fifo_full(FIFO *p)
+{
+ return (p->rp == ((p->wp + 1) % p->depth)) ? 1 : 0;
+}
+
+/**
+ * @brief FIFOが空かどうかを検査する。
+ *
+ * @param p FIFOハンドラ。
+ *
+ * @retval 1 FIFOが空である。
+ * @retval 0 FIFOが空でない。
+ */
+int fifo_empty(FIFO *p)
+{
+ return (p->rp == p->wp) ? 1 : 0;
+}
+
+/**
+ * @brief FIFOに格納されているオブジェクト数を取得する。
+ *
+ * @param p FIFOハンドラ。
+ *
+ * @return オブジェクト数。
+ */
+int fifo_count(FIFO *p)
+{
+ return p->count;
+}
+
+/**
+ * @brief FIFOにオブジェクトをプッシュする。
+ * @details
+ * このモジュールはオブジェクトへのポインタのみを保持する。
+ * このため、スタック上に置いたオブジェクトなどをプッシュする事はできない。
+ * 必ずヒープ上のオブジェクトへのポインタを渡すこと。
+ *
+ * @param p FIFOハンドラ。
+ * @param obj オブジェクト。
+ *
+ * @retval 1 成功。
+ * @retval 0 失敗。
+ */
+int fifo_push(FIFO *p, void *obj)
+{
+ if (fifo_full(p)) {
+ return 0;
+ }
+ *(p->objlist + p->wp) = obj;
+ p->wp = (p->wp + 1) % p->depth;
+ p->count = p->count + 1;
+ return 1;
+}
+
+/**
+ * @brief FIFOからオブジェクトをプルする。
+ *
+ * @param p FIFOハンドラ。
+ * @param obj オブジェクト。
+ *
+ * @retval 1 成功。
+ * @retval 0 失敗。
+ */
+int fifo_pull(FIFO *p, void **obj)
+{
+ if (fifo_empty(p)) {
+ return 0;
+ }
+ *obj = *(p->objlist + p->rp);
+ p->rp = (p->rp + 1) % p->depth;
+ p->count = p->count - 1;
+ return 1;
+}
+
+/**
+ * @brief FIFOモジュールをクローズする。
+ *
+ * @param p FIFOハンドラ。
+ *
+ * @retval 1 成功。
+ * @retval 0 失敗。
+ */
+int fifo_close(FIFO *p)
+{
+ if (p == NULL) {
+ return 0;
+ }
+ free(p->objlist);
+ free(p);
+ return 0;
+}
+
--- /dev/null
+/**
+ * @file fifo.h
+ * @author Shinichiro Nakamura
+ * @brief FIFOモジュールの定義。
+ */
+
+/*
+ * ===============================================================
+ * Natural Tiny Logger (NT-Logger)
+ * ===============================================================
+ * Copyright (c) 2010-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#ifndef FIFO_H
+#define FIFO_H
+
+/**
+ * @brief FIFOハンドラの定義。
+ */
+typedef struct FIFO FIFO;
+
+/**
+ * @brief FIFOモジュールをオープンする。
+ *
+ * @param depth FIFOの深さ。
+ *
+ * @retval !NULL FIFOハンドラ。
+ * @retval NULL 失敗。
+ */
+FIFO *fifo_open(const int depth);
+
+/**
+ * @brief FIFOが一杯かどうかを検査する。
+ *
+ * @param p FIFOハンドラ。
+ *
+ * @retval 1 FIFOが一杯である。
+ * @retval 0 FIFOが一杯でない。
+ */
+int fifo_full(FIFO *p);
+
+/**
+ * @brief FIFOが空かどうかを検査する。
+ *
+ * @param p FIFOハンドラ。
+ *
+ * @retval 1 FIFOが空である。
+ * @retval 0 FIFOが空でない。
+ */
+int fifo_empty(FIFO *p);
+
+/**
+ * @brief FIFOに格納されているオブジェクト数を取得する。
+ *
+ * @param p FIFOハンドラ。
+ *
+ * @return オブジェクト数。
+ */
+int fifo_count(FIFO *p);
+
+/**
+ * @brief FIFOにオブジェクトをプッシュする。
+ * @details
+ * このモジュールはオブジェクトへのポインタのみを保持する。
+ * このため、スタック上に置いたオブジェクトなどをプッシュする事はできない。
+ * 必ずヒープ上のオブジェクトへのポインタを渡すこと。
+ *
+ * @param p FIFOハンドラ。
+ * @param obj オブジェクト。
+ *
+ * @retval 1 成功。
+ * @retval 0 失敗。
+ */
+int fifo_push(FIFO *p, void *obj);
+
+/**
+ * @brief FIFOからオブジェクトをプルする。
+ *
+ * @param p FIFOハンドラ。
+ * @param obj オブジェクト。
+ *
+ * @retval 1 成功。
+ * @retval 0 失敗。
+ */
+int fifo_pull(FIFO *p, void **obj);
+
+/**
+ * @brief FIFOモジュールをクローズする。
+ *
+ * @param p FIFOハンドラ。
+ *
+ * @retval 1 成功。
+ * @retval 0 失敗。
+ */
+int fifo_close(FIFO *p);
+
+#endif
+
--- /dev/null
+#!/bin/sh
+cat timeline.html | sed -e 's/\"/\\"/g' | sed -e 's/$/\\n\"/g' | sed -e 's/^/ \"/g' > timeline.txt
+
--- /dev/null
+/**
+ * @file ntlgen.c
+ * @author Shinichiro Nakamura
+ * @brief Natural Tiny Logger (NT-Logger)のホスト側ジェネレータ。
+ */
+
+/*
+ * ===============================================================
+ * Natural Tiny Logger (NT-Logger)
+ * ===============================================================
+ * Copyright (c) 2010-2012 Shinichiro Nakamura
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ * ===============================================================
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ntldef.h"
+#include "optparse.h"
+#include "fifo.h"
+
+/**
+ * @brief トラック数。
+ */
+#define TRACK_COUNT (16)
+
+/**
+ * @brief 1トラックあたりのイベント数。
+ */
+#define EVENT_COUNT (8)
+
+/**
+ * @brief 開始イベントを格納するFIFOの深さ。
+ */
+#define FIFO_DEPTH (32)
+
+/**
+ * @brief オプションを初期化する。
+ *
+ * @param P オプション構造体へのポインタ。
+ */
+#define OPTION_INIT(P) \
+ do { \
+ (P)->optflag = 0; \
+ strcpy((P)->input, ""); \
+ strcpy((P)->output, ""); \
+ strcpy((P)->description, ""); \
+ } while (0)
+
+#define OPTFLAG_INPUT (1 << 0) /**< 入力ファイル名。 */
+#define OPTFLAG_OUTPUT (1 << 1) /**< 出力ファイル名。 */
+#define OPTFLAG_DESCRIPTION (1 << 2) /**< 詳細ファイル名。 */
+
+/**
+ * @brief オプション構造体。
+ */
+typedef struct {
+ unsigned char optflag; /**< オプション指定確認用フラグ。 */
+ char input[BUFSIZ]; /**< 入力ファイル名。 */
+ char output[BUFSIZ]; /**< 出力ファイル名。 */
+ char description[BUFSIZ]; /**< 詳細ファイル名。 */
+} option_t;
+
+/**
+ * @brief オプション分割装置用のコールバック関数。
+ *
+ * @param option オプション文字。
+ * @param argument オプション文字に対する引数。
+ * @param extobj 外部オブジェクト。
+ *
+ * @retval 0 解析継続。
+ * @retval !0 解析中断。
+ */
+static int option_callback(
+ const char option, const char *argument, void *extobj)
+{
+ option_t *opt = (option_t *)extobj;
+ switch (option) {
+ case 'i':
+ strcpy(opt->input, argument);
+ opt->optflag |= OPTFLAG_INPUT;
+ break;
+ case 'o':
+ strcpy(opt->output, argument);
+ opt->optflag |= OPTFLAG_OUTPUT;
+ break;
+ case 'd':
+ strcpy(opt->description, argument);
+ opt->optflag |= OPTFLAG_DESCRIPTION;
+ break;
+ }
+ return 0;
+}
+
+static const char *html_pre =
+ "<html>\n"
+ " <head>\n"
+ " <title>Natural Tiny Logger (NT-Logger)</title>\n"
+ "\n"
+ " <script type=\"text/javascript\" src=\"http://www.google.com/jsapi\"></script>\n"
+ " <script type=\"text/javascript\" src=\"./timeline/timeline.js\"></script>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"./timeline/timeline.css\">\n"
+ "\n"
+ " <style>\n"
+ " body {font: 10pt arial;}\n"
+ "\n"
+ " div.timeline-frame {\n"
+ " border-color: gray;\n"
+ " }\n"
+ "\n"
+ " div.timeline-axis {\n"
+ " border-color: gray;\n"
+ "\n"
+ " background-color: gray;\n"
+ " filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F9F9F9', endColorstr='#EEEFF1'); /* for IE */\n"
+ " background: -webkit-gradient(linear, left top, left bottom, from(#F9F9F9), to(#EEEFF1)); /* for webkit browsers */\n"
+ " background: -moz-linear-gradient(top, #F9F9F9, #EEEFF1); /* for firefox 3.6+ */\n"
+ " }\n"
+ "\n"
+ " div.timeline-axis-text {\n"
+ " font: bold 12px arial;\n"
+ " color: black;\n"
+ " }\n"
+ "\n"
+ " div.timeline-event {\n"
+ " border: none;\n"
+ " background-color: cornflowerblue;\n"
+ " }\n"
+ " div.timeline-event-selected {\n"
+ " background-color: mediumslateblue;\n"
+ " }\n"
+ " div.timeline-event-content {\n"
+ " margin: 0px;\n"
+ " }\n"
+ "\n"
+ " div.timeline-groups-axis {\n"
+ " border-color: gray;\n"
+ " }\n"
+ " div.timeline-groups-text {\n"
+ " font: bold 12px arial;\n"
+ " color: black;\n"
+ " }\n"
+ "\n"
+ " div.event {\n"
+ " border: 1px solid white;\n"
+ " border-radius: 2px;\n"
+ " -moz-border-radius: 2px;\n"
+ "\n"
+ " font: bold 10px arial;\n"
+ " color: black;\n"
+ "\n"
+ " padding: 2px;\n"
+ " margin: 1px;\n"
+ " overflow: hidden;\n"
+ " }\n"
+ "\n"
+ " </style>\n"
+ "\n"
+ " <script type=\"text/javascript\">\n"
+ " var timeline = null;\n"
+ "\n"
+ " google.load(\"visualization\", \"1\");\n"
+ "\n"
+ " // Set callback to run when API is loaded\n"
+ " google.setOnLoadCallback(drawVisualization);\n"
+ "\n"
+ " // Called when the Visualization API is loaded.\n"
+ " function drawVisualization() {\n"
+ " // Create and populate a data table.\n"
+ " var data = new google.visualization.DataTable();\n"
+ " data.addColumn('datetime', 'start');\n"
+ " data.addColumn('datetime', 'end');\n"
+ " data.addColumn('string', 'content');\n"
+ " data.addColumn('string', 'group');\n"
+ "\n";
+
+static const char *html_post =
+ "\n"
+ " // specify options\n"
+ " var options = {\n"
+ " width: \"100%\",\n"
+ " height: \"auto\",\n"
+ " layout: \"box\",\n"
+ " editable: false,\n"
+ " eventMargin: 5, // minimal margin between events\n"
+ " eventMarginAxis: 0, // minimal margin beteen events and the axis\n"
+ " showMajorLabels: true,\n"
+ " axisOnTop: true,\n"
+ " groupsChangeable : true,\n"
+ " groupsOnRight: false\n"
+ " };\n"
+ "\n"
+ " // Instantiate our timeline object.\n"
+ " timeline = new links.Timeline(document.getElementById('mytimeline'));\n"
+ "\n"
+ " // Draw our timeline with the created data and options\n"
+ " timeline.draw(data, options);\n"
+ " }\n"
+ " </script>\n"
+ " </head>\n"
+ "\n"
+ " <body>\n"
+ " <h1>Natural Tiny Logger (NT-Logger)</h1>\n"
+ " <div id=\"mytimeline\"></div>\n"
+ " </body>\n"
+ "\n"
+ "</html>\n"
+ "\n";
+
+/**
+ * @brief イベント時間。
+ */
+typedef struct {
+ int year; /**< 年。 */
+ int month; /**< 月。 */
+ int day; /**< 日。 */
+ int hour; /**< 時。 */
+ int min; /**< 分。 */
+ int sec; /**< 秒。 */
+ int usec; /**< マイクロ秒。 */
+} event_time_t;
+
+/**
+ * @brief イベント構造体。
+ */
+typedef struct {
+ char name[BUFSIZ]; /**< イベント名。 */
+ int count; /**< イベント数。 */
+ FIFO *start; /**< 開始イベントを格納するFIFO。 */
+} event_t;
+
+/**
+ * @brief トラック構造体。
+ */
+typedef struct {
+ char name[BUFSIZ]; /**< トラック名。 */
+ event_t event[EVENT_COUNT]; /**< イベント情報。 */
+} track_t;
+
+/**
+ * @brief ターゲット構造体。
+ */
+typedef struct {
+ int linecnt; /**< イベントファイルの行数。 */
+ int eventcnt; /**< イベントファイルに含まれるイベント数。 */
+ track_t track[TRACK_COUNT]; /**< トラック情報。 */
+} target_t;
+
+/**
+ * @brief 詳細情報をファイルから読み込む。
+ *
+ * @param filename ファイル名。
+ * @param t ターゲット構造体。
+ */
+void read_description(const char *filename, target_t *t)
+{
+ char line[BUFSIZ];
+ FILE *fp = fopen(filename, "r");
+ if (fp == NULL) {
+ return;
+ }
+ printf("[Descriptions]\n");
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ int track, event;
+ char track_name[BUFSIZ];
+ char event_name[BUFSIZ];
+ if (sscanf(line, "%i %i %s %s", &track, &event, track_name, event_name) == 4) {
+ strcpy(t->track[track].name, track_name);
+ strcpy(t->track[track].event[event].name, event_name);
+ printf("\t%d:%d:%s:%s\n", track, event, track_name, event_name);
+ }
+ }
+ fclose(fp);
+ return;
+}
+
+/**
+ * @brief ターゲット情報を初期化する。
+ *
+ * @param target ターゲット。
+ */
+void init_target(target_t *target)
+{
+ int i, j;
+ target->linecnt = 0;
+ target->eventcnt = 0;
+ for (i = 0; i < TRACK_COUNT; i++) {
+ strcpy(target->track[i].name, "Undefined");
+ for (j = 0; j < EVENT_COUNT; j++) {
+ target->track[i].event[j].count = 0;
+ target->track[i].event[j].start = fifo_open(FIFO_DEPTH);
+ strcpy(target->track[i].event[j].name, "Undefined");
+ }
+ }
+}
+
+/**
+ * @brief ターゲット情報を初期化する。
+ *
+ * @param target ターゲット。
+ */
+void fini_target(target_t *target)
+{
+ int i, j;
+ target->linecnt = 0;
+ target->eventcnt = 0;
+ for (i = 0; i < TRACK_COUNT; i++) {
+ for (j = 0; j < EVENT_COUNT; j++) {
+ int cnt = 0;
+ event_time_t *start;
+ while (fifo_pull(target->track[i].event[j].start, (void **)&start)) {
+ cnt++;
+ free(start);
+ }
+ if (target->track[i].event[j].count > 0) {
+ printf("---------------------------------------------------\n");
+ printf("| %02d:%-16.16s | %8d events. |\n", i, target->track[i].name, target->track[i].event[j].count);
+ printf("| %02d:%-16.16s | %8d failed. |\n", j, target->track[i].event[j].name, cnt);
+ }
+ fifo_close(target->track[i].event[j].start);
+ }
+ }
+}
+
+/**
+ * @brief エントリポイント。
+ *
+ * @param argc 引数の数。
+ * @param argv 引数。
+ *
+ * @return シェルに返す値。
+ */
+int main(int argc, char **argv)
+{
+ option_t opt;
+ target_t target;
+ FILE *fpin;
+ FILE *fpout;
+ char line[BUFSIZ];
+
+ /*
+ * オプションを取得する。
+ */
+ OPTION_INIT(&opt);
+ optparse_char(argc, argv, &opt, option_callback);
+ if (opt.optflag !=
+ (OPTFLAG_INPUT | OPTFLAG_OUTPUT | OPTFLAG_DESCRIPTION)) {
+ printf("ntlgen -i <input> -o <output> -d <description>\n");
+ return 1;
+ }
+
+ /*
+ * ターゲット情報を初期化する。
+ */
+ init_target(&target);
+
+ /*
+ * 詳細情報を読み込む。
+ */
+ read_description(opt.description, &target);
+
+ /*
+ * 入力ファイルを開く。
+ */
+ fpin = fopen(opt.input, "r");
+ if (fpin == NULL) {
+ printf("File open failed.\n");
+ return 1;
+ }
+
+ /*
+ * 出力ファイルを開く。
+ */
+ fpout = fopen(opt.output, "w");
+ if (fpout == NULL) {
+ printf("File open failed.\n");
+ return 1;
+ }
+
+ /*
+ * HTMLプリ情報出力。
+ */
+ fprintf(fpout, "%s", html_pre);
+
+ /*
+ * イベント情報を読み込みながらHTMLに変換する。
+ */
+ while (fgets(line, sizeof(line), fpin) != NULL) {
+ int year, month, day;
+ int hour, min, sec, usec;
+ int pkt;
+ target.linecnt++;
+ if (sscanf(line, "%04d/%02d/%02d %02d:%02d:%02d.%06d %02X",
+ &year, &month, &day,
+ &hour, &min, &sec, &usec,
+ &pkt) == 8) {
+ int track = NTLDEF_NTL_TRACK(pkt);
+ int event = NTLDEF_NTL_EVENT(pkt);
+ int type = NTLDEF_NTL_TYPE(pkt);
+ target.eventcnt++;
+ switch (type) {
+ case NTLDEF_TYPE_START:
+ {
+ event_time_t *start = (event_time_t *)malloc(sizeof(event_time_t));
+ start->year = year;
+ start->month = month;
+ start->day = day;
+ start->hour = hour;
+ start->min = min;
+ start->sec = sec;
+ start->usec = usec;
+ target.track[track].event[event].count++;
+ if (!fifo_push(target.track[track].event[event].start, start)) {
+ printf("Warning: FIFO is full.\n");
+ }
+ }
+ break;
+ case NTLDEF_TYPE_END:
+ {
+ event_time_t *start = NULL;
+ if (fifo_pull(target.track[track].event[event].start, (void **)&start)) {
+ fprintf(fpout, " var start = new Date(%d, %d, %d, %d, %d, %d);\n",
+ start->year,
+ start->month,
+ start->day,
+ start->hour,
+ start->min,
+ start->sec);
+ fprintf(fpout, " var end = new Date(%d, %d, %d, %d, %d, %d);\n",
+ year, month, day, hour, min, sec);
+ fprintf(fpout, " data.addRow([\n");
+ fprintf(fpout, " new Date(start.getTime() + %.3f),\n", (double)start->usec / 1000.0);
+ fprintf(fpout, " new Date(end.getTime() + %.3f),\n", (double)usec / 1000.0);
+ fprintf(fpout, " \"<div title='No.%d (%02d:%02d:%02d.%06d) - (%02d:%02d:%02d.%06d)' class='event' style='height:40px'>No.%d<br />%02d:%02d:%02d.%06d<br />%02d:%02d:%02d.%06d</div>\",\n",
+ target.track[track].event[event].count,
+ start->hour,
+ start->min,
+ start->sec,
+ start->usec,
+ hour,
+ min,
+ sec,
+ usec,
+ target.track[track].event[event].count,
+ start->hour,
+ start->min,
+ start->sec,
+ start->usec,
+ hour,
+ min,
+ sec,
+ usec);
+ fprintf(fpout, " \"%02d:%s<br />%02d:%s\"\n",
+ track, target.track[track].name,
+ event, target.track[track].event[event].name);
+ fprintf(fpout, " ]);\n");
+ free(start);
+ } else {
+ printf("Warning: No start point found. (Line=%d)\n", target.linecnt);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /*
+ * HTMLポスト情報出力。
+ */
+ fprintf(fpout, "%s", html_post);
+
+ printf("%d lines. %d events.\n", target.linecnt, target.eventcnt);
+
+ /*
+ * 出力ファイルを閉じる。
+ */
+ fclose(fpout);
+
+ /*
+ * 入力ファイルを閉じる。
+ */
+ fclose(fpin);
+
+ /*
+ * ターゲット情報を破棄する。
+ */
+ fini_target(&target);
+
+ return 0;
+}
+
--- /dev/null
+<html>
+ <head>
+ <title>Natural Tiny Logger (NT-Logger)</title>
+
+ <script type="text/javascript" src="http://www.google.com/jsapi"></script>
+ <script type="text/javascript" src="./timeline/timeline.js"></script>
+ <link rel="stylesheet" type="text/css" href="./timeline/timeline.css">
+
+ <style>
+ body {font: 10pt arial;}
+
+ div.timeline-frame {
+ border-color: gray;
+ }
+
+ div.timeline-axis {
+ border-color: gray;
+
+ background-color: gray;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F9F9F9', endColorstr='#EEEFF1'); /* for IE */
+ background: -webkit-gradient(linear, left top, left bottom, from(#F9F9F9), to(#EEEFF1)); /* for webkit browsers */
+ background: -moz-linear-gradient(top, #F9F9F9, #EEEFF1); /* for firefox 3.6+ */
+ }
+
+ div.timeline-axis-text {
+ font: bold 12px arial;
+ color: black;
+ }
+
+ div.timeline-event {
+ border: none;
+ background-color: cornflowerblue;
+ }
+ div.timeline-event-selected {
+ background-color: mediumslateblue;
+ }
+ div.timeline-event-content {
+ margin: 0px;
+ }
+
+ div.timeline-groups-axis {
+ border-color: gray;
+ }
+ div.timeline-groups-text {
+ font: bold 12px arial;
+ color: black;
+ }
+
+ div.event {
+ border: 1px solid white;
+ border-radius: 2px;
+ -moz-border-radius: 2px;
+
+ font: bold 12px arial;
+ color: black;
+
+ padding: 2px;
+ margin: 1px;
+ overflow: hidden;
+ }
+
+ </style>
+
+ <script type="text/javascript">
+ var timeline = null;
+
+ google.load("visualization", "1");
+
+ // Set callback to run when API is loaded
+ google.setOnLoadCallback(drawVisualization);
+
+ // Called when the Visualization API is loaded.
+ function drawVisualization() {
+ // Create and populate a data table.
+ var data = new google.visualization.DataTable();
+ data.addColumn('datetime', 'start');
+ data.addColumn('datetime', 'end');
+ data.addColumn('string', 'content');
+ data.addColumn('string', 'group');
+
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+ // Insert target timeline data here
+
+ // specify options
+ var options = {
+ width: "100%",
+ height: "auto",
+ layout: "box",
+ editable: false,
+ eventMargin: 5, // minimal margin between events
+ eventMarginAxis: 0, // minimal margin beteen events and the axis
+ showMajorLabels: true,
+ axisOnTop: true,
+ groupsChangeable : true,
+ groupsOnRight: false
+ };
+
+ // Instantiate our timeline object.
+ timeline = new links.Timeline(document.getElementById('mytimeline'));
+
+ // Draw our timeline with the created data and options
+ timeline.draw(data, options);
+ }
+ </script>
+ </head>
+
+ <body>
+ <h1>Natural Tiny Logger (NT-Logger)</h1>
+ <div id="mytimeline"></div>
+ </body>
+
+</html>
+
--- /dev/null
+ "<html>\n"
+ " <head>\n"
+ " <title>Natural Tiny Logger (NT-Logger)</title>\n"
+ "\n"
+ " <script type=\"text/javascript\" src=\"http://www.google.com/jsapi\"></script>\n"
+ " <script type=\"text/javascript\" src=\"./timeline/timeline.js\"></script>\n"
+ " <link rel=\"stylesheet\" type=\"text/css\" href=\"./timeline/timeline.css\">\n"
+ "\n"
+ " <style>\n"
+ " body {font: 10pt arial;}\n"
+ "\n"
+ " div.timeline-frame {\n"
+ " border-color: gray;\n"
+ " }\n"
+ "\n"
+ " div.timeline-axis {\n"
+ " border-color: gray;\n"
+ "\n"
+ " background-color: gray;\n"
+ " filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#F9F9F9', endColorstr='#EEEFF1'); /* for IE */\n"
+ " background: -webkit-gradient(linear, left top, left bottom, from(#F9F9F9), to(#EEEFF1)); /* for webkit browsers */\n"
+ " background: -moz-linear-gradient(top, #F9F9F9, #EEEFF1); /* for firefox 3.6+ */\n"
+ " }\n"
+ "\n"
+ " div.timeline-axis-text {\n"
+ " font: bold 12px arial;\n"
+ " color: black;\n"
+ " }\n"
+ "\n"
+ " div.timeline-event {\n"
+ " border: none;\n"
+ " background-color: cornflowerblue;\n"
+ " }\n"
+ " div.timeline-event-selected {\n"
+ " background-color: mediumslateblue;\n"
+ " }\n"
+ " div.timeline-event-content {\n"
+ " margin: 0px;\n"
+ " }\n"
+ "\n"
+ " div.timeline-groups-axis {\n"
+ " border-color: gray;\n"
+ " }\n"
+ " div.timeline-groups-text {\n"
+ " font: bold 12px arial;\n"
+ " color: black;\n"
+ " }\n"
+ "\n"
+ " div.event {\n"
+ " border: 1px solid white;\n"
+ " border-radius: 2px;\n"
+ " -moz-border-radius: 2px;\n"
+ "\n"
+ " font: bold 12px arial;\n"
+ " color: black;\n"
+ "\n"
+ " padding: 2px;\n"
+ " margin: 1px;\n"
+ " overflow: hidden;\n"
+ " }\n"
+ "\n"
+ " </style>\n"
+ "\n"
+ " <script type=\"text/javascript\">\n"
+ " var timeline = null;\n"
+ "\n"
+ " google.load(\"visualization\", \"1\");\n"
+ "\n"
+ " // Set callback to run when API is loaded\n"
+ " google.setOnLoadCallback(drawVisualization);\n"
+ "\n"
+ " // Called when the Visualization API is loaded.\n"
+ " function drawVisualization() {\n"
+ " // Create and populate a data table.\n"
+ " var data = new google.visualization.DataTable();\n"
+ " data.addColumn('datetime', 'start');\n"
+ " data.addColumn('datetime', 'end');\n"
+ " data.addColumn('string', 'content');\n"
+ " data.addColumn('string', 'group');\n"
+ "\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ " // Insert target timeline data here\n"
+ "\n"
+ " // specify options\n"
+ " var options = {\n"
+ " width: \"100%\",\n"
+ " height: \"auto\",\n"
+ " layout: \"box\",\n"
+ " editable: false,\n"
+ " eventMargin: 5, // minimal margin between events\n"
+ " eventMarginAxis: 0, // minimal margin beteen events and the axis\n"
+ " showMajorLabels: true,\n"
+ " axisOnTop: true,\n"
+ " groupsChangeable : true,\n"
+ " groupsOnRight: false\n"
+ " };\n"
+ "\n"
+ " // Instantiate our timeline object.\n"
+ " timeline = new links.Timeline(document.getElementById('mytimeline'));\n"
+ "\n"
+ " // Draw our timeline with the created data and options\n"
+ " timeline.draw(data, options);\n"
+ " }\n"
+ " </script>\n"
+ " </head>\n"
+ "\n"
+ " <body>\n"
+ " <h1>Natural Tiny Logger (NT-Logger)</h1>\n"
+ " <div id=\"mytimeline\"></div>\n"
+ " </body>\n"
+ "\n"
+ "</html>\n"
+ "\n"