#include <stdlib.h>
#include <stdint.h>
#include "serial.h"
-#include "kz_h8write.h"
#include "mot.h"
+#include "optparse.h"
+#include "kz_h8write.h"
/**
- * @brief デバッグモードフラグ。
- * @details 0:デバッグモードオフ、1:デバッグモードオン。
+ * @brief プログラム終了用マクロ。
+ * @details このマクロはシリアルポートのオープン成功後の処理に用いる。
+ * @param CODE シェルに返すコード番号。
*/
-#define DEBUG 0
+#define PROGEXIT(CODE) serial_close(serial); exit(CODE)
/**
* @brief シリアルタイムアウト時間。
*/
#define SERIAL_TIMEOUT_MS 500
-SERIAL *serial;
-unsigned char memory_image[0x100000 + 0x100];
-unsigned int memory_lastaddr = 0;
+/**
+ * @brief ユーザオプション構造体。
+ */
+typedef struct {
+ char cpu_name[BUFSIZ]; /**< CPU名。 */
+ int cpu_freq; /**< CPU周波数。 */
+ char mot_file[BUFSIZ]; /**< MOTファイル名。NULLなら標準入力。 */
+ char serial_port[BUFSIZ]; /**< シリアルポート名。 */
+ int version; /**< バージョンフラグ。 */
+ int help; /**< ヘルプフラグ。 */
+ int debug; /**< デバッグフラグ。 */
+ int error; /**< オプション指定エラー検出フラグ。 */
+} user_option_t;
+
+#define USER_OPTION_INITIALIZER \
+{ \
+ .cpu_name = "\0", \
+ .cpu_freq = 20, \
+ .mot_file = "\0", \
+ .serial_port = "\0", \
+ .version = 0, \
+ .help = 0, \
+ .debug = 0, \
+ .error = 0, \
+}
+
+#define USER_OPTION_CPU_NAME(P) ((P)->cpu_name)
+#define USER_OPTION_CPU_FREQ(P) ((P)->cpu_freq)
+#define USER_OPTION_MOT_FILE(P) ((P)->mot_file)
+#define USER_OPTION_SERIAL_PORT(P) ((P)->serial_port)
+#define USER_OPTION_VERSION(P) ((P)->version)
+#define USER_OPTION_HELP(P) ((P)->help)
+#define USER_OPTION_DEBUG(P) ((P)->debug)
+#define USER_OPTION_ERROR(P) ((P)->error)
+
+static SERIAL *serial;
+static unsigned char memory_image[0x100000 + 0x100];
+static unsigned int memory_lastaddr = 0;
int com_getc(void);
int com_putc(unsigned char c);
return NoError;
}
-/**
- * @brief プログラム終了用マクロ。
- * @details このマクロはシリアルポートのオープン成功後の処理に用いる。
- * @param CODE シェルに返すコード番号。
- */
-#define PROGEXIT(CODE) serial_close(serial); exit(CODE)
+int optparse_callback(const char option, const char *argument, void *extobj)
+{
+ user_option_t *user_option = (user_option_t *)extobj;
+
+ printf("option=%c, argument=%s\n", option, argument);
+
+ /*
+ * USER_OPTION_MOT_FILE()とUSER_OPTION_SERIAL_PORT()は別に取得する。
+ */
+ switch (option) {
+ case '3':
+ strcpy(USER_OPTION_CPU_NAME(user_option), "3");
+ strcat(USER_OPTION_CPU_NAME(user_option), argument);
+ break;
+ case 'F':
+ case 'f':
+ if (sscanf(argument, "%i", &USER_OPTION_CPU_FREQ(user_option)) != 1) {
+ USER_OPTION_ERROR(user_option) = 1;
+ }
+ break;
+ case 'V':
+ case 'v':
+ USER_OPTION_VERSION(user_option) = 1;
+ break;
+ case 'H':
+ case 'h':
+ USER_OPTION_HELP(user_option) = 1;
+ break;
+ case 'D':
+ case 'd':
+ USER_OPTION_DEBUG(user_option) = 1;
+ break;
+ }
+ return 0;
+}
/**
* @brief エントリーポイント。
{
enum ErrorCode ec;
uint32_t devcode;
- char *motfile;
- int clock;
- char *interface;
+ user_option_t user_option = USER_OPTION_INITIALIZER;
+ /*
+ * バナーを表示する。
+ */
fprintf(stderr, "=================================================\n");
fprintf(stderr, " H8/3069F Flash Writer for KOZOS (Version %d.%d.%d)\n",
VERSION_MAJOR,
VERSION_MINOR,
VERSION_RELEASE);
- fprintf(stderr, " Copyright(C) 2011 Shinichiro Nakamura \n");
+ fprintf(stderr, " Copyright(C) 2011-2012 Shinichiro Nakamura\n");
fprintf(stderr, "=================================================\n");
- if (argc != 4) {
- fprintf(stderr, "%s [mot file] [clock] [interface]\n", argv[0]);
+ /*
+ * オプションのデフォルト値を設定する。
+ */
+ strcpy(USER_OPTION_CPU_NAME(&user_option), "3069");
+ USER_OPTION_CPU_FREQ(&user_option) = 20;
+ strcpy(USER_OPTION_MOT_FILE(&user_option), "");
+ strcpy(USER_OPTION_SERIAL_PORT(&user_option), "");
+ USER_OPTION_VERSION(&user_option) = 0;
+ USER_OPTION_HELP(&user_option) = 0;
+ USER_OPTION_DEBUG(&user_option) = 0;
+ USER_OPTION_ERROR(&user_option) = 0;
+
+ /*
+ * 文字ベースでオプションを解析する。
+ */
+ optparse_char(argc, argv, &user_option, optparse_callback);
+
+ /*
+ * オプションの指定に誤りがある場合には、使い方を表示して終了する。
+ */
+ if ((argc < 3) || USER_OPTION_ERROR(&user_option)
+ || USER_OPTION_VERSION(&user_option) || USER_OPTION_HELP(&user_option)) {
+ fprintf(stderr, "%s [options...] [mot file] [interface]\n", argv[0]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, " Target CPU : -3069 (Default:3069)\n");
+ fprintf(stderr, " Target Frequency : -f[20 | 25] (Default:20)\n");
+ fprintf(stderr, " Version : -v\n");
+ fprintf(stderr, " Help : -h\n");
+ fprintf(stderr, " Debug : -d\n");
exit(1);
}
/*
- * パラメータを受け取る。
+ * 与えられた引数の最後の二つは、それぞれMOTファイルとシリアルポート名であるという仮定。
+ */
+ strcpy(USER_OPTION_MOT_FILE(&user_option), argv[argc - 2]);
+ strcpy(USER_OPTION_SERIAL_PORT(&user_option), argv[argc - 1]);
+
+ /*
+ * デバッグ用の出力。
+ */
+ if (USER_OPTION_DEBUG(&user_option)) {
+ fprintf(stderr, "Target CPU : %s\n", USER_OPTION_CPU_NAME(&user_option));
+ fprintf(stderr, "Target Frequency : %d\n", USER_OPTION_CPU_FREQ(&user_option));
+ fprintf(stderr, "MOT File : %s\n", USER_OPTION_MOT_FILE(&user_option));
+ fprintf(stderr, "Seiral Port : %s\n", USER_OPTION_SERIAL_PORT(&user_option));
+ }
+
+ /*
+ * 与えられたオプションを検証する。
*/
- motfile = argv[1];
- if (sscanf(argv[2], "%d", &clock) != 1) {
- fprintf(stderr, "Invalid clock number found.\n");
+ if (strcmp(USER_OPTION_CPU_NAME(&user_option), "3069") != 0) {
+ /*
+ * 3069F以外はエラーとする。
+ * 3069F以外で検証するつもりは今のところないから対象外とする。
+ * プロトコルが同じなら書き込めるだろう。
+ */
+ fprintf(stderr, "Unsupported CPU name found.\n");
+ exit(1);
+ }
+ if ((USER_OPTION_CPU_FREQ(&user_option) != 20) && (USER_OPTION_CPU_FREQ(&user_option) != 25)) {
+ /*
+ * 20MHzでもなく、25MHzでもなければエラー。
+ */
+ fprintf(stderr, "Unsupported CPU frequency value found.\n");
exit(1);
}
- interface = argv[3];
/*
* motファイルを読み込む。
*/
mot_t mot;
mot.cb_data = mot_callback;
- if (mot_read(motfile, &mot) != 0) {
+ if (mot_read(USER_OPTION_MOT_FILE(&user_option), &mot) != 0) {
fprintf(stderr, "file read error\n");
exit(1);
}
-#if (DEBUG==1)
- /*
- * ダンプしてチェック。
- */
- for (unsigned int i = 0; i < memory_lastaddr; i++) {
- if ((i % 16) == 0) {
- fprintf(stderr, "\n0x%04X :", i);
- }
- fprintf(stderr, " %02X", memory_image[i]);
- }
- fprintf(stderr, "\n");
-#endif
-
/*
* シリアルポートをオープンする。
*/
- serial = serial_open(interface, SerialBaud19200);
+ serial = serial_open(USER_OPTION_SERIAL_PORT(&user_option), SerialBaud19200);
if (serial == NULL) {
fprintf(stderr, "com port open error\n");
exit(1);
* リトライした結果として成功した事を知りたい時にのみ
* 表示を有効にすると良い。
*/
-#if (DEBUG==1)
- fprintf(stderr, "Bitrate sequence failed.\n");
-#endif
+ if (USER_OPTION_DEBUG(&user_option)) {
+ fprintf(stderr, "Bitrate sequence failed.\n");
+ }
}
}
if (ec != NoError) {
/*
* 新ビットレート選択を実行する。
*/
- ec = select_bitrate(19200, clock);
+ ec = select_bitrate(19200, USER_OPTION_CPU_FREQ(&user_option));
if (ec != NoError) {
fprintf(stderr, "Select bitrate failed. (code=0x%02x)\n", (int)ec);
PROGEXIT(1);
--- /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))
+{
+ for (int 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))
+{
+ for (int 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
+