/*
 *	r.c
 *
 *	r.exe - 「run.bat」の問題を修正したコマンド
 *	Copyright (C) 2014 Naoyuki Sawa
 *
 *	* Thu Nov 13 20:56:04 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 *	- P/ECE開発環境付属の「isd.exe」及び「run.bat」には、以下の不具合があります。
 *	  ■P/ECEのプログラムが、pceAppProc()の中で長時間の処理を行って、5秒間ぐらい処理を返さない時に、PC上で「run.bat」を実行すると、P/ECEがハングアップする。
 *	  不具合の原因は、「isd.exe」が、P/ECEのプログラムが終了するのをきちんと待たずに、見切り発車でsrfファイルを書き込み、実行開始してしまっていることでした。
 *	  具体的には、「\usr\PIECE\tools\isd\isdsub.c」のismWriteSrfFile()の処理が、適切ではありません。
 *	- 厳密には、「isd.exe」「run.bat」の不具合ではなく、「pieceif.dll」の不具合なのですが、今回は、「run.bat」を代替する修正プログラムを作ることにしました。
 *	  理由は、「pieceif.dll」を差し替えると影響が大きいですし、「pieceif.dll」は32ビット環境と64ビット環境で異なるので、差替えの手間がわずらわしいからです。
 *	- 今回作った「r.exe」の使用方法は、P/ECE開発環境付属の「run.bat」と同じです。
 *	  「r.exe」を、実行パスの通ったフォルダに、置いておいてください。
 *	  srfファイルの在るフォルダで、「r」を実行すると、srfファイルをP/ECEに転送して、実行します。srfファイル名の指定は不要です。
 *	- P/ECEのプログラムを開発中に、頻繁に使用しますので、名前はごく短い「r」にしました。
 *	  P/ECE開発環境に入っているコマンドも、「s.bat」とか「pm.exe」とか、短い名前が多いですね。
 *	  他のツールと名前が衝突したらその時変えよう、という感じの割り切りが良いと思います。
 */
#define STRICT
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include "C:/usr/PIECE/tools/isd/pieceif.h"			//┬P/ECE開発環境が、デフォルトのインストールフォルダにインストールされていると仮定しました。
#pragma comment(lib,"C:/usr/PIECE/tools/isd/pieceif.lib")	//┘P/ECE開発環境を、別のフォルダにインストールした環境でビルドする場合は、変更してください。

/* 当プログラムは、「isd.exe -run」相当の動作を行う。
 * - 簡略化のために、コマンドライン引数を確認しないことにした。
 *   厳密には、コマンドライン引数が指定されていないことを確認せよ。 */
int main() {
	int exitCode = EXIT_FAILURE;//終了コードを「失敗」としておく。
	struct _finddata_t fileinfo;
	long handle;
	/* P/ECEに接続する。
	 * - 簡略化のために、接続するP/ECEは1台固定とし、接続待ち時間もデフォルトとした。
	 *   2台目以降に対応したり、接続待ち時間を変更する場合は、ismInitEx()に変更せよ。
	 * - 簡略化のために、P/ECEのOSバージョンは確認しないことにした。
	 *   最新のOSバージョンであると仮定する。
	 *   OSバージョンを確認する場合は、ismGetVersion()も使用せよ。 */
	if(ismInit()) {
		fputs("### P/ECEに接続できません。\n", stderr);
		goto L_EXIT;
	}
	/* 現在のフォルダに在る、srfファイルを取得する。
	 * - 複数在る場合は、最初に見つけたsrfファイルを使用する。 */
	handle = _findfirst("*.srf", &fileinfo);
	if(handle == -1) {
		fputs("### srfファイルが在りません。\n", stderr);
		goto L_EXIT;
	}
	_findclose(handle);
//{{P/ECE開発環境付属の「isd.exe」は、この範囲の処理が「ismWriteSrfFile(…,1)」の一命令で行われている。当プログラムでは、問題の修正を行うために、「ismAppStop()」「ismWriteSrfFile(…,0)」「ismAppStart()」に分離して処理することにした。
  //{{
  //×	/* P/ECEのプログラムを終了する。 */
  //×	if(ismAppStop()) {
  //×		fputs("### P/ECEのプログラムを終了できません。\n", stderr);	//┬P/ECE開発環境付属の「isd.exe」は、左記の処理が不足しているようだ。P/ECEのプログラムが長時間の処理中で、停止できなかった場合にも、srfファイルの書き込みを行っていた。
  //×		goto L_EXIT;							//┘そのため、P/ECEのプログラムが長時間の処理中に「run」バッチスクリプトを実行すると、P/ECEがハングアップするという問題が生じていた。停止できなかった場合は、処理を中止することにした。
  //×	}
  //↓一度でもismAppStop()を発行したら、P/ECEはプログラム終了フェーズに入るので、処理を中断してはいけない。処理を中断すると、P/ECEが「終了」状態(=画面が消えた状態)で停止してしまう。「\usr\PIECE\sysdev\pcekn\runapp.c」のAppStart()の「while ( 1 ) { 〜」を参照せよ。
  //↓一度でもismAppStop()を発行したら、P/ECEのプログラムが終了するまで、繰り返す必要がある。
  //↓尚、厳密には、2回目以降の「ismAppStop()」は無効なので(「\usr\PIECE\sysdev\pcekn\usbcom.c」のusbcom()の「case 4: // Set App Status.」を参照せよ)、2回目以降はismAppStop()ではなくismSetAppStat()を使うのが正しいのだが、ismAppStop()を使用しても動作上は問題無い。
	/* P/ECEのプログラムを終了する。 */
	while(ismAppStop()) {
		fputs("### P/ECEのプログラムを終了できません。再試行中…\n", stderr);
	}
  //}}
	/* P/ECEに、srfファイルを書き込む。 */
	if(ismWriteSrfFile(fileinfo.name, 0)) {
		fputs("### srfファイルを書き込めません。\n", stderr);		//┬P/ECE開発環境付属の「isd.exe」は、左記の処理が不足しているようだ。srfファイルの書き込み失敗した場合も、P/ECEのプログラムを開始していた。
		goto L_EXIT;							//┘実際には、処理がここまで進んだ後にsrfファイルの書き込み失敗することは無いはずであるが、安全のために、srfファイルの書き込み失敗した場合は、処理を中止することにした。
	}
  //{{
  //△	/* P/ECEのプログラムを開始する。 */
  //△	if(ismAppStart()) {
  //△		fputs("### P/ECEのプログラムを開始できません。\n", stderr);
  //△		goto L_EXIT;
  //△	}
  //↓この変更は必須では無い。一度でもismAppStart()を発行したら、P/ECEはプログラム開始フェーズに入るので、プログラムが開始したことを確認しなくても、動作上は問題ない。
  //↓しかし、「P/ECEのプログラムを開始できません。」というエラーメッセージを表示したまま、「r.exe」が終了してしまうのは紛らわしいし、
  //↓「r.exe」をバッチスクリプトの中で使って、P/ECEのプログラムが開始した後に別の通信コマンドを実行するような場合のために、P/ECEのプログラムが開始するまで待つことにした。
  //↓具体的には、pceAppInit()の処理時間が長い場合に、上記のケースが起こり得るので、そのための対策である。
  //↓尚、厳密には、2回目以降の「ismAppStart()」は無効なので(「\usr\PIECE\sysdev\pcekn\usbcom.c」のusbcom()の「case 4: // Set App Status.」を参照せよ)、2回目以降はismAppStart()ではなくismSetAppStat()を使うのが正しいのだが、ismAppStart()を使用しても動作上は問題無い。
	/* P/ECEのプログラムを開始する。 */
	while(ismAppStart()) {
		fputs("### P/ECEのプログラムを開始できません。再試行中…\n", stderr);
	}
  //}}
//}}P/ECE開発環境付属の「isd.exe」は、この範囲の処理が「ismWriteSrfFile(…,1)」の一命令で行われている。当プログラムでは、問題の修正を行うために、「ismAppStop()」「ismWriteSrfFile(…,0)」「ismAppStart()」に分離して処理することにした。
	exitCode = EXIT_SUCCESS;//終了コードを「成功」に変更する。
L_EXIT:
	ismExit();//この関数の呼出しは常に必要。ismInit()に失敗しても必要。
	return exitCode;
}
