LoginSignup
4
2

TOPPERS活用アイデア・アプリケーション開発コンテスト受賞作品紹介(3)第二回(2012)アプリケーション開発部門銀賞Natural Tiny Logger(NT-Logger) 中村晋一郎(個人)

Last updated at Posted at 2018-06-20

TOPPERS「活用アイデア」・「アプリケーション開発」コンテスト
は、2011年から毎年実施されています。
https://www.toppers.jp/contest.html

「アプケーション開発」は、ソースコードの公開を前提としています。
「活用アイデア」でも、その後実現したソースコードなどもある。探しながら紹介。

なお、この記事は、TOPPERSプロジェクトの公式見解ではなく、
小川清 の 技術者個人の考えに基づいています。

目的(purpose)

TOPPERS開発アイデア・アプリケーション開発コンテスト受賞作品には、良質な算譜、技術的に崇高な志向、目的を達成するための意思などが感じられる。広く、source codeを表示して紹介し、次の応募作品を促す。
#成果(outcome)

応募作品の算譜を眺めると、その技術者の得意分野や技法を感じることができる。応募作品のソースコードを使ってみようという気になる。自分も良い作品を作ろうという気になる。

TOPPERS活用アイデア・アプリケーション開発コンテスト受賞作品紹介(3) 第二回アプリケーション開発部門(2012)銅賞

Natural Tiny Logger(NT-Logger) 中村晋一郎(個人)

応募資料(application material)等

ET2012発表資料
https://www.toppers.jp/docs/contest/2012/nakamura_presen_2012.pdf

組み込みシステムの全体挙動を簡単に確認できるロギングツール - Natural Tiny Logger (NT-Logger)
http://shinta-main-jp.blogspot.com/2012/07/natural-tiny-logger-nt-logger.html

Download

ntlogger-v0.1.0.tar.gz
https://www.cubeatsystems.com/firmware/ntlogger/ntlogger-v0.1.0.tar.gz

関連資料(related URL)

KOZOSのタスク間通信を可視化するツールを作ってみた (ipcrvt.sh : KOZOS IPC Relationship Visualization Tool)
http://shinta-main-jp.blogspot.com/2012/07/kozos-ipcrvtsh-kozos-ipc-relationship.html

NT-Loggerでお気楽デバッグ
https://www.cubeatsystems.com/firmware/ntlogger/ntlogger_ja.html

NT-Logger の使い方メモ
http://nsaito-nmiri.hateblo.jp/entry/2015/06/04/105945

SWEST14参加報告
http://shinta-main-jp.blogspot.com/2012/09/swest14.html

「ピュア・カーネルで本当に満足ですか?「Natural Tiny Shellでもっと
便利に開発ライフ!」 +「Natural Tiny Loggerでアプリケーション・
デバッグをもっと便利に!」」
中村 晋一郎
https://swest.toppers.jp/SWEST14/minutes/poster.txt (SWEST poster)

TOPPERS活用アイデア・アプリケーション開発コンテスト受賞作品紹介(1) 第一回(2011)アプリケーション開発部門銀賞『Natural Tiny Shell Task』中村晋一郎
https://qiita.com/kaizen_nagoya/items/763209c213e3c0daee10

TOPPERS活用アイデア・アプリケーション開発コンテスト受賞作品紹介(6)第三回アプリケーション開発部門銀賞 T TOPPERS Realtime System Sample(RSS)- LPCXpresso GPS Clock 中村 晋一郎(個人)
https://qiita.com/kaizen_nagoya/items/06744374c509bf46ebfb

算譜(source code)

ntlgen.c
/**
 * @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;
}

ntlgen.c以外のソースコードは順次追記予定。
https://www.cubeatsystems.com/firmware/ntlogger/ntlogger-v0.1.0.tar.gz

参考資料(reference)

「TOPPERS活用アイデア・アプリケーション開発コンテスト受賞作品紹介」まとめ
https://qiita.com/kaizen_nagoya/items/72b882d96b2841f25faf

TOPPERS活用アイデア・アプリケーション開発コンテストを振り返る
https://researchmap.jp/joxkbxlck-1778110/
「応募すると何が嬉しい」TOPPERS活用アイデア・ アプリケーション開発コンテスト
https://www.slideshare.net/kaizenjapan/ss-78528931
「TOPPERS活用アイデア・アプリケーション開発コンテスト」への道
https://researchmap.jp/jovr40j3b-1778110/?block_id=1778110&active_action=journal_view_main_detail&post_id=38687&comment_flag=1

文書履歴(document history)

ver. 0.10 初稿 20180621
ver. 0.11 成果追記 20180622
ver. 0.12 関連・参考文献追記 20180623

最後までおよみいただきありがとうございました。

いいね 💚、フォローをお願いします。

Thank you very much for reading to the last sentence.

Please press the like icon 💚 and follow me for your happy life.

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2