#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#include <vector>
#include <string>
#include <io.h>			//access()

#include "tstring.h"
#include "ftd2xx.h"
#include "ftd2xx_func.h"

typedef struct {
	unsigned int no;
	char SerialNumber[16];
} FT_INFO;

// 文字列定数
const std::tstring strDQ(_T("\""));		//ダブルコーテーション
const TCHAR szDefWrName[] = _T("ft232h_eeprom_no");		// デフォルト 出力ファイル名
const TCHAR szDefReName[] = _T("ft232h_eeprom_to_write_no");	// デフォルト 入力ファイル名

// global 変数
HMODULE hFtModule = NULL;	// FTDL DLL のハンドル

// prototype
BOOL EEPromToIni(unsigned int ftno, TCHAR *fname);
BOOL IniToEEProm(unsigned int ftno, TCHAR *fname);
BOOL ChkEEProm(unsigned int ftno);
BOOL SetEEProm(unsigned int ftno);
BOOL EraseEEProm(unsigned int ftno);
BOOL InitEEProm(unsigned int ftno);
void printHelp(void);

// main
int _tmain(int argc, _TCHAR* argv[])
{

	FT_STATUS ret = FT_OK;

	//
	// FTDI ライブラリのロード、関数ポインタ取得
	//
	
	// FTDI DLL の公開関数へのポインタ
	_FT_CreateDeviceInfoList FT_CreateDeviceInfoList = NULL;
	_FT_GetDeviceInfoList FT_GetDeviceInfoList = NULL;

	hFtModule = LoadLibrary(_T("ftd2xx.dll"));	// DLL ロード
	if (hFtModule) {
		FT_CreateDeviceInfoList = (_FT_CreateDeviceInfoList)GetProcAddress(hFtModule, "FT_CreateDeviceInfoList");
		FT_GetDeviceInfoList = (_FT_GetDeviceInfoList)GetProcAddress(hFtModule, "FT_GetDeviceInfoList");
	}
	else {
		_tprintf(_T("FTDI D2XX のライブラリがロードできません\r\n"));
		exit(0);
	}

	//
	// デバイス情報取得
	//
	DWORD devNum = 0;	// FDTI デバイス総数
	std::vector<FT_INFO> ift232h;
	FT_INFO info;

	ret = FT_CreateDeviceInfoList(&devNum);
	if (ret == FT_OK) {
		FT_DEVICE_LIST_INFO_NODE *pInfo = new FT_DEVICE_LIST_INFO_NODE[devNum];
		ret = FT_GetDeviceInfoList(pInfo, &devNum);
		if (ret == FT_OK) {
			for (unsigned int i = 0; i < devNum; i++) {
				if (pInfo[i].Type == FT_DEVICE_232H) {	// 232H を見つけた

					memset(&info, '\0', sizeof(info));
					info.no = i;
					strncpy_s(info.SerialNumber, _countof(info.SerialNumber), pInfo[i].SerialNumber, _countof(pInfo[i].SerialNumber));
					ift232h.push_back(info);	// device no と シリアル番号をとっておく
				}
			}
		}
		//メモリ解放
		if (pInfo) {
			delete[] pInfo;
			pInfo = NULL;
		}

		if (ift232h.size() > 0) {
			_tprintf(_T("FT232H が %d 個見つかりました\r\n"), ift232h.size());
			_tprintf(_T("--------------------------\r\n"));
			_tprintf(_T("[NO]       [SerialNumber]\r\n"));
			for (unsigned int i = 0; i < ift232h.size(); i++) {
				_tprintf(_T("%2d          %hs\r\n"), ift232h[i].no, ift232h[i].SerialNumber);
			}
			_tprintf(_T("--------------------------\r\n"));
		}
		else {
			_tprintf(_T("FT232H が見つかりません\r\n"));
			FreeLibrary(hFtModule);
			exit(0);
		}
	}
	else {
		_tprintf(_T("FTDI のデバイスリスト取得に失敗しました\r\n"));
		FreeLibrary(hFtModule);
		exit(0);
	}


	// .ini ファイル名の生成の準備
	// フルパス指定しないと、.ini は c:\windows に生成されてしまう
	TCHAR szThisName[_MAX_PATH] = _T("");
	TCHAR szDrive[_MAX_DRIVE] = _T("");
	TCHAR szDir[_MAX_DIR] = _T("");
	TCHAR szFilename[_MAX_FNAME] = _T("");
	TCHAR szIniName[_MAX_PATH] = _T("");
	std::tstring fname;

	GetModuleFileName(NULL, szThisName, _MAX_PATH);		// パス取得
	_tsplitpath_s(szThisName, szDrive, _countof(szDrive), szDir, _countof(szDir), szFilename, _countof(szFilename), NULL, 0);	// パス分解

	//
	// オプション解析、処理分岐
	//
	BOOL found = FALSE;

	if (argc > 2) {	// オプションが指定されている

		// -r : EEPROM 読み込み
		if (_tcsncicmp(argv[1], _T("-r"), _tcslen(argv[1])) == 0) {

			for (unsigned int index = 0; index < ift232h.size(); index++) {

				if (ift232h[index].no == _tstoi(argv[2])) {	// ft232h リストにある NO が指定された

					fname = szDefWrName;							// 書き出しファイル名
					fname += std::to_tstring(ift232h[index].no);		// NO をつける
					_tmakepath_s(szIniName, _countof(szIniName), szDrive, szDir, fname.c_str(), _T(".ini"));	// 書き出しファイルフルパス生成

					if (EEPromToIni(ift232h[index].no, szIniName)) {
						_tprintf(_T("NO.%d の FT232H の eeprom を %s に書き出しました\r\n"), ift232h[index].no, szIniName);
					}
					else {
						_tprintf(_T("NO.%d の FT232H の eeprom 読み出しが失敗しました\r\n"), ift232h[index].no);	
					}
					found = TRUE;
					break;
				}
			}

			if (!found) {
				_tprintf(_T("NO.%s の FT232H は存在しません\r\n"), argv[2]);
			}

		}
		// -w : EEPROM 書き込み
		else if (_tcsncicmp(argv[1], _T("-w"), _tcslen(argv[1])) == 0) {
				
			for (unsigned int index = 0; index < ift232h.size(); index++) {

				if (ift232h[index].no == _tstoi(argv[2])) {	// ft232h リストにある NO が指定された

					fname = szDefReName;							// 読み込みファイル名
					fname += std::to_tstring(ift232h[index].no);		// NO をつける
					_tmakepath_s(szIniName, _countof(szIniName), szDrive, szDir, fname.c_str(), _T(".ini"));	// 読み込みファイルフルパス生成

					if (IniToEEProm(ift232h[index].no, szIniName)) {
						_tprintf(_T("%s の内容を NO.%d の FT232H の eeprom に書き込みました\r\n"), szIniName, ift232h[index].no);

						// コンソールの色を変える
						HANDLE hCon;
						CONSOLE_SCREEN_BUFFER_INFO cInfo;
						hCon = GetStdHandle(STD_OUTPUT_HANDLE);
						if (hCon != INVALID_HANDLE_VALUE) {
							GetConsoleScreenBufferInfo(hCon, &cInfo);
							SetConsoleTextAttribute(hCon, FOREGROUND_RED | FOREGROUND_INTENSITY);
							_tprintf(_T("NO.%d の FT232H を一度抜き差しして下さい\r\n"), ift232h[index].no);
							SetConsoleTextAttribute(hCon, cInfo.wAttributes);
							CloseHandle(hCon);
						}
						else {
							_tprintf(_T("NO.%d の FT232H を一度抜き差しして下さい\r\n"), ift232h[index].no);
						}
					}
					else {
						_tprintf(_T("NO.%d の FT232H の eeprom 書き込みが失敗しました\r\n"), ift232h[index].no);
					}
					found = TRUE;
					break;
				}
			}

			if (!found) {
				_tprintf(_T("NO.%s の FT232H は存在しません\r\n"), argv[2]);
			}
		}
		// -chk : eeprom のチェック
		else if (_tcsncicmp(argv[1], _T("-chk"), _tcslen(argv[1])) == 0) {
			for (unsigned int index = 0; index < ift232h.size(); index++) {
				if (ift232h[index].no == _tstoi(argv[2])) {	// ft232h リストにある NO が指定された
					if (ChkEEProm(ift232h[index].no)) {
						_tprintf(_T("NO.%d の FT232H は YM2610 用にセッティングされています\r\n"), ift232h[index].no);
					}
					else {
						_tprintf(_T("NO.%d の FT232H は YM2610 用には使えません\r\n"), ift232h[index].no);
					}
					found = TRUE;
					break;
				}
			}

			if (!found) {
				_tprintf(_T("NO.%s の FT232H は存在しません\r\n"), argv[2]);
			}
		}
		// -set : eeprom を最低限書き換える
		else if (_tcsncicmp(argv[1], _T("-set"), _tcslen(argv[1])) == 0) {
			for (unsigned int index = 0; index < ift232h.size(); index++) {
				if (ift232h[index].no == _tstoi(argv[2])) {	// ft232h リストにある NO が指定された
					if (SetEEProm(ift232h[index].no)) {
						_tprintf(_T("NO.%d の FT232H を YM2610 用にセットしました\r\n"), ift232h[index].no);

						// コンソールの色を変える
						HANDLE hCon;
						CONSOLE_SCREEN_BUFFER_INFO cInfo;
						hCon = GetStdHandle(STD_OUTPUT_HANDLE);
						if (hCon != INVALID_HANDLE_VALUE) {
							GetConsoleScreenBufferInfo(hCon, &cInfo);
							SetConsoleTextAttribute(hCon, FOREGROUND_RED | FOREGROUND_INTENSITY);
							_tprintf(_T("NO.%d の FT232H を一度抜き差しして下さい\r\n"), ift232h[index].no);
							SetConsoleTextAttribute(hCon, cInfo.wAttributes);
							CloseHandle(hCon);
						}
						else {
							_tprintf(_T("NO.%d の FT232H を一度抜き差しして下さい\r\n"), ift232h[index].no);
						}
					}
					else {
						_tprintf(_T("NO.%d の FT232H の YM2610 用セッティングは失敗しました\r\n"), ift232h[index].no);
					}
					found = TRUE;
					break;
				}
			}
			if (!found) {
				_tprintf(_T("NO.%s の FT232H は存在しません\r\n"), argv[2]);
			}
		}
		// -erase : eeprom を消去する
		else if (_tcsncicmp(argv[1], _T("-erase"), _tcslen(argv[1])) == 0) {
			for (unsigned int index = 0; index < ift232h.size(); index++) {
				if (ift232h[index].no == _tstoi(argv[2])) {	// ft232h リストにある NO が指定された
					if (EraseEEProm(ift232h[index].no)) {
						_tprintf(_T("NO.%d の FT232H の EEProm を消去しました\r\n"), ift232h[index].no);

						// コンソールの色を変える
						HANDLE hCon;
						CONSOLE_SCREEN_BUFFER_INFO cInfo;
						hCon = GetStdHandle(STD_OUTPUT_HANDLE);
						if (hCon != INVALID_HANDLE_VALUE) {
							GetConsoleScreenBufferInfo(hCon, &cInfo);
							SetConsoleTextAttribute(hCon, FOREGROUND_RED | FOREGROUND_INTENSITY);
							_tprintf(_T("NO.%d の FT232H を一度抜き差しして下さい\r\n"), ift232h[index].no);
							SetConsoleTextAttribute(hCon, cInfo.wAttributes);
							CloseHandle(hCon);
						}
						else {
							_tprintf(_T("NO.%d の FT232H を一度抜き差しして下さい\r\n"), ift232h[index].no);
						}
					}
					else {
						_tprintf(_T("NO.%d の FT232H の EEprom 消去は失敗しました\r\n"), ift232h[index].no);
					}
					found = TRUE;
					break;
				}
			}
			if (!found) {
				_tprintf(_T("NO.%s の FT232H は存在しません\r\n"), argv[2]);
			}
		}
		// -init : eeprom を 0 クリアする
		else if (_tcsncicmp(argv[1], _T("-init"), _tcslen(argv[1])) == 0) {
			for (unsigned int index = 0; index < ift232h.size(); index++) {
				if (ift232h[index].no == _tstoi(argv[2])) {	// ft232h リストにある NO が指定された
					if (InitEEProm(ift232h[index].no)) {
						_tprintf(_T("NO.%d の FT232H の EEProm を初期化しました\r\n"), ift232h[index].no);

						// コンソールの色を変える
						HANDLE hCon;
						CONSOLE_SCREEN_BUFFER_INFO cInfo;
						hCon = GetStdHandle(STD_OUTPUT_HANDLE);
						if (hCon != INVALID_HANDLE_VALUE) {
							GetConsoleScreenBufferInfo(hCon, &cInfo);
							SetConsoleTextAttribute(hCon, FOREGROUND_RED | FOREGROUND_INTENSITY);
							_tprintf(_T("NO.%d の FT232H を一度抜き差しして下さい\r\n"), ift232h[index].no);
							SetConsoleTextAttribute(hCon, cInfo.wAttributes);
							CloseHandle(hCon);
						}
						else {
							_tprintf(_T("NO.%d の FT232H を一度抜き差しして下さい\r\n"), ift232h[index].no);
						}
					}
					else {
						_tprintf(_T("NO.%d の FT232H の EEprom 初期化は失敗しました\r\n"), ift232h[index].no);
					}
					found = TRUE;
					break;
				}
			}
			if (!found) {
				_tprintf(_T("NO.%s の FT232H は存在しません\r\n"), argv[2]);
			}
		}
		// オプション指定間違い
		else {
			printHelp();
			_tprintf(_T("\r\n"));
			_tprintf(_T("オプションが間違っています\r\n"));
		}
	}
	else {	// 引数が少ない
		printHelp();
	}

	// 終了
	if (hFtModule) {
		FreeLibrary(hFtModule);
	}

	exit(0);
}

//
// eeprom を読み出して ini に出力する
//
BOOL EEPromToIni(unsigned int ftno, TCHAR *fname) {

	BOOL ret = FALSE;
	FT_HANDLE ftHandle;

	// FTDI DLL の公開関数へのポインタ
	_FT_Open FT_Open = NULL;
	_FT_Close FT_Close = NULL;
	_FT_EEPROM_Read FT_EEPROM_Read = NULL;

	if (hFtModule) {
		FT_Open = (_FT_Open)GetProcAddress(hFtModule, "FT_Open");
		FT_Close = (_FT_Close)GetProcAddress(hFtModule, "FT_Close");
		FT_EEPROM_Read = (_FT_EEPROM_Read)GetProcAddress(hFtModule, "FT_EEPROM_Read");
	}

	char Manufacturer[64] ="";
	char ManufacturerId[64] = "";
	char Description[64] = "";
	char SerialNumber[64] = "";

	TCHAR T_Manufacturer[64] = _T("");
	TCHAR T_ManufacturerId[64] = _T("");
	TCHAR T_Description[64] = _T("");
	TCHAR T_SerialNumber[64] = _T("");

	FT_EEPROM_232H eeprom_232h;
	eeprom_232h.common.deviceType = FT_DEVICE_232H;

	std::tstring line;	// 文字列を " で囲む用

	if (FT_Open(ftno, &ftHandle) == FT_OK) {
		if (FT_EEPROM_Read(ftHandle, &eeprom_232h, sizeof(eeprom_232h), Manufacturer, ManufacturerId, Description, SerialNumber) == FT_OK) {

			ret = TRUE;

			// string
			char2tchar(T_Manufacturer, Manufacturer, _countof(T_Manufacturer));
			line = strDQ + T_Manufacturer + strDQ;
			ret &= WritePrivateProfileString(_T("DESC"), _T("Manufacturer"), line.c_str(), fname);

			char2tchar(T_ManufacturerId, ManufacturerId, _countof(T_ManufacturerId));
			line = strDQ + T_ManufacturerId + strDQ;
			ret &= WritePrivateProfileString(_T("DESC"), _T("ManufacturerId"), line.c_str(), fname);

			char2tchar(T_Description, Description, _countof(T_Description));
			line = strDQ + T_Description + strDQ;
			ret &= WritePrivateProfileString(_T("DESC"), _T("Description"), line.c_str(), fname);

			char2tchar(T_SerialNumber, SerialNumber, _countof(T_SerialNumber));
			line = strDQ + T_SerialNumber + strDQ;
			ret &= WritePrivateProfileString(_T("DESC"), _T("SerialNumber"), line.c_str(), fname);

			// common
			ret &= WritePrivateProfileString(_T("COMMON"), _T("deviceType"),     std::to_tstring(eeprom_232h.common.deviceType).c_str(),     fname);	// ULONG
			ret &= WritePrivateProfileString(_T("COMMON"), _T("VendorId"),       std::to_tstring(eeprom_232h.common.VendorId).c_str(),       fname);	// WORD
			ret &= WritePrivateProfileString(_T("COMMON"), _T("ProductId"),      std::to_tstring(eeprom_232h.common.ProductId).c_str(),      fname);	// WORD
			ret &= WritePrivateProfileString(_T("COMMON"), _T("SerNumEnable"),   std::to_tstring(eeprom_232h.common.SerNumEnable).c_str(),   fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("COMMON"), _T("MaxPower"),       std::to_tstring(eeprom_232h.common.MaxPower).c_str(),       fname);	// WORD
			ret &= WritePrivateProfileString(_T("COMMON"), _T("SelfPowered"),    std::to_tstring(eeprom_232h.common.SelfPowered).c_str(),    fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("COMMON"), _T("RemoteWakeup"),   std::to_tstring(eeprom_232h.common.RemoteWakeup).c_str(),   fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("COMMON"), _T("PullDownEnable"), std::to_tstring(eeprom_232h.common.PullDownEnable).c_str(), fname);	// UCHAR

			// ft232h
			ret &= WritePrivateProfileString(_T("FT232H"), _T("ACSlowSlew"),        std::to_tstring(eeprom_232h.ACSlowSlew).c_str(),        fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("ACSchmittInput"),    std::to_tstring(eeprom_232h.ACSchmittInput).c_str(),    fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("ACDriveCurrent"),    std::to_tstring(eeprom_232h.ACDriveCurrent).c_str(),    fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("ADSlowSlew"),        std::to_tstring(eeprom_232h.ADSlowSlew).c_str(),        fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("ADSchmittInput"),    std::to_tstring(eeprom_232h.ADSchmittInput).c_str(),    fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("ADDriveCurrent"),    std::to_tstring(eeprom_232h.ADDriveCurrent).c_str(),    fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus0"),             std::to_tstring(eeprom_232h.Cbus0).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus1"),             std::to_tstring(eeprom_232h.Cbus1).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus2"),             std::to_tstring(eeprom_232h.Cbus2).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus3"),             std::to_tstring(eeprom_232h.Cbus3).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus4"),             std::to_tstring(eeprom_232h.Cbus4).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus5"),             std::to_tstring(eeprom_232h.Cbus5).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus6"),             std::to_tstring(eeprom_232h.Cbus6).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus7"),             std::to_tstring(eeprom_232h.Cbus7).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus8"),             std::to_tstring(eeprom_232h.Cbus8).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("Cbus9"),             std::to_tstring(eeprom_232h.Cbus9).c_str(),             fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("FT1248Cpol"),        std::to_tstring(eeprom_232h.FT1248Cpol).c_str(),        fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("FT1248Lsb"),         std::to_tstring(eeprom_232h.FT1248Lsb).c_str(),         fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("FT1248FlowControl"), std::to_tstring(eeprom_232h.FT1248FlowControl).c_str(), fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("IsFifo"),            std::to_tstring(eeprom_232h.IsFifo).c_str(),            fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("IsFifoTar"),         std::to_tstring(eeprom_232h.IsFifoTar).c_str(),         fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("IsFastSer"),         std::to_tstring(eeprom_232h.IsFastSer).c_str(),         fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("IsFT1248"),          std::to_tstring(eeprom_232h.IsFT1248).c_str(),          fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("PowerSaveEnable"),   std::to_tstring(eeprom_232h.PowerSaveEnable).c_str(),   fname);	// UCHAR
			ret &= WritePrivateProfileString(_T("FT232H"), _T("DriverType"),        std::to_tstring(eeprom_232h.DriverType).c_str(),        fname);	// UCHAR
			WritePrivateProfileString(NULL, NULL, NULL, fname);	// フラッシュ
		}
		FT_Close(ftHandle);
	}

	return ret;
}


//
// ini を読み出して、eeprom に書き込む
//
BOOL IniToEEProm(unsigned int ftno, TCHAR *fname) {

	BOOL ret = FALSE;
	FT_HANDLE ftHandle;

	// FTDI DLL の公開関数へのポインタ

	_FT_Open FT_Open = NULL;
	_FT_Close FT_Close = NULL;
	_FT_EEPROM_Program FT_EEPROM_Program = NULL;

	if (hFtModule) {
		FT_Open = (_FT_Open)GetProcAddress(hFtModule, "FT_Open");
		FT_Close = (_FT_Close)GetProcAddress(hFtModule, "FT_Close");
		FT_EEPROM_Program = (_FT_EEPROM_Program)GetProcAddress(hFtModule, "FT_EEPROM_Program");
	}

	char Manufacturer[64] = "";
	char ManufacturerId[64] = "";
	char Description[64] = "";
	char SerialNumber[64] = "";

	TCHAR T_Manufacturer[64] = _T("");
	TCHAR T_ManufacturerId[64] = _T("");
	TCHAR T_Description[64] = _T("");
	TCHAR T_SerialNumber[64] = _T("");

	FT_EEPROM_232H eeprom_232h;

	if (_taccess(fname, 0) == -1) {		// ファイルが存在しない
		_tprintf(_T("%s がありません\r\n"), fname);
		return FALSE;
	}

	// 初期化
	memset(&eeprom_232h, '\0', sizeof(eeprom_232h));
	eeprom_232h.common.deviceType = FT_DEVICE_232H;

	// description
	GetPrivateProfileString(_T("DESC"), _T("Manufacturer"), _T(""), T_Manufacturer, _countof(T_Manufacturer), fname);
	GetPrivateProfileString(_T("DESC"), _T("ManufacturerId"), _T(""), T_ManufacturerId, _countof(T_ManufacturerId), fname);
	GetPrivateProfileString(_T("DESC"), _T("Description"), _T(""), T_Description, _countof(T_Description), fname);
	GetPrivateProfileString(_T("DESC"), _T("SerialNumber"), _T(""), T_SerialNumber, _countof(T_SerialNumber), fname);

	tchar2char(Manufacturer, T_Manufacturer, _countof(Manufacturer));
	tchar2char(ManufacturerId, T_ManufacturerId, _countof(ManufacturerId));
	tchar2char(Description, T_Description, _countof(Description));
	tchar2char(SerialNumber, T_SerialNumber, _countof(SerialNumber));

	// common
	eeprom_232h.common.deviceType = GetPrivateProfileInt(_T("COMMON"), _T("deviceType"), 0, fname);	// ULONG
	eeprom_232h.common.VendorId = GetPrivateProfileInt(_T("COMMON"), _T("VendorId"), 0, fname);	// WORD
	eeprom_232h.common.ProductId = GetPrivateProfileInt(_T("COMMON"), _T("ProductId"), 0, fname);	// WORD
	eeprom_232h.common.SerNumEnable = GetPrivateProfileInt(_T("COMMON"), _T("SerNumEnable"), 0, fname);	// UCHAR
	eeprom_232h.common.MaxPower = GetPrivateProfileInt(_T("COMMON"), _T("MaxPower"), 0, fname);	// WORD
	eeprom_232h.common.SelfPowered = GetPrivateProfileInt(_T("COMMON"), _T("SelfPowered"), 0, fname);	// UCHAR
	eeprom_232h.common.RemoteWakeup = GetPrivateProfileInt(_T("COMMON"), _T("RemoteWakeup"), 0, fname);	// UCHAR
	eeprom_232h.common.PullDownEnable = GetPrivateProfileInt(_T("COMMON"), _T("PullDownEnable"), 0, fname);	// UCHAR

																											// ft232h
	eeprom_232h.ACSlowSlew = GetPrivateProfileInt(_T("FT232H"), _T("ACSlowSlew"), 0, fname);	// UCHAR
	eeprom_232h.ACSchmittInput = GetPrivateProfileInt(_T("FT232H"), _T("ACSchmittInput"), 0, fname);	// UCHAR
	eeprom_232h.ACDriveCurrent = GetPrivateProfileInt(_T("FT232H"), _T("ACDriveCurrent"), 0, fname);	// UCHAR
	eeprom_232h.ADSlowSlew = GetPrivateProfileInt(_T("FT232H"), _T("ADSlowSlew"), 0, fname);	// UCHAR
	eeprom_232h.ADSchmittInput = GetPrivateProfileInt(_T("FT232H"), _T("ADSchmittInput"), 0, fname);	// UCHAR
	eeprom_232h.ADDriveCurrent = GetPrivateProfileInt(_T("FT232H"), _T("ADDriveCurrent"), 0, fname);	// UCHAR
	eeprom_232h.Cbus0 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus0"), 0, fname);	// UCHAR
	eeprom_232h.Cbus1 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus1"), 0, fname);	// UCHAR
	eeprom_232h.Cbus2 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus2"), 0, fname);	// UCHAR
	eeprom_232h.Cbus3 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus3"), 0, fname);	// UCHAR
	eeprom_232h.Cbus4 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus4"), 0, fname);	// UCHAR
	eeprom_232h.Cbus5 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus5"), 0, fname);	// UCHAR
	eeprom_232h.Cbus6 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus6"), 0, fname);	// UCHAR
	eeprom_232h.Cbus7 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus7"), 0, fname);	// UCHAR
	eeprom_232h.Cbus8 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus8"), 0, fname);	// UCHAR
	eeprom_232h.Cbus9 = GetPrivateProfileInt(_T("FT232H"), _T("Cbus9"), 0, fname);	// UCHAR
	eeprom_232h.FT1248Cpol = GetPrivateProfileInt(_T("FT232H"), _T("FT1248Cpol"), 0, fname);	// UCHAR
	eeprom_232h.FT1248Lsb = GetPrivateProfileInt(_T("FT232H"), _T("FT1248Lsb"), 0, fname);	// UCHAR
	eeprom_232h.FT1248FlowControl = GetPrivateProfileInt(_T("FT232H"), _T("FT1248FlowControl"), 0, fname);	// UCHAR
	eeprom_232h.IsFifo = GetPrivateProfileInt(_T("FT232H"), _T("IsFifo"), 0, fname);	// UCHAR
	eeprom_232h.IsFifoTar = GetPrivateProfileInt(_T("FT232H"), _T("IsFifoTar"), 0, fname);	// UCHAR
	eeprom_232h.IsFastSer = GetPrivateProfileInt(_T("FT232H"), _T("IsFastSer"), 0, fname);	// UCHAR
	eeprom_232h.IsFT1248 = GetPrivateProfileInt(_T("FT232H"), _T("IsFT1248"), 0, fname);	// UCHAR
	eeprom_232h.PowerSaveEnable = GetPrivateProfileInt(_T("FT232H"), _T("PowerSaveEnable"), 0, fname);	// UCHAR
	eeprom_232h.DriverType = GetPrivateProfileInt(_T("FT232H"), _T("DriverType"), 0, fname);	// UCHAR

	//printf("Manufacturer = %s\r\n", Manufacturer);
	//printf("ManufacturerId = %s\r\n", ManufacturerId);
	//printf("Description = %s\r\n", Description);
	//printf("SerialNumber = %s\r\n", SerialNumber);
	//printf("------------------------\r\n");
	//printf("deviceType = %d\r\n", eeprom_232h.common.deviceType);
	//printf("VendorId = 0x%04x\r\n", eeprom_232h.common.VendorId);
	//printf("ProductId = 0x%04x\r\n", eeprom_232h.common.ProductId);
	//printf("SerNumEnable = %d\r\n", eeprom_232h.common.SerNumEnable);
	//printf("MaxPower = %d\r\n", eeprom_232h.common.MaxPower);
	//printf("SelfPowered = %d\r\n", eeprom_232h.common.SelfPowered);
	//printf("RemoteWakeup = %d\r\n", eeprom_232h.common.RemoteWakeup);
	//printf("PullDownEnable = %d\r\n", eeprom_232h.common.PullDownEnable);
	//printf("------------------------\r\n");
	//printf("ACSlowSlew = %d\r\n", eeprom_232h.ACSlowSlew);
	//printf("ACSchmittInput = %d\r\n", eeprom_232h.ACSchmittInput);
	//printf("ACDriveCurrent = %d\r\n", eeprom_232h.ACDriveCurrent);
	//printf("ADSlowSlew = %d\r\n", eeprom_232h.ADSlowSlew);
	//printf("ADSchmittInput = %d\r\n", eeprom_232h.ADSchmittInput);
	//printf("ADDriveCurrent = %d\r\n", eeprom_232h.ADDriveCurrent);
	//printf("Cbus0 = %d\r\n", eeprom_232h.Cbus0);
	//printf("Cbus1 = %d\r\n", eeprom_232h.Cbus1);
	//printf("Cbus2 = %d\r\n", eeprom_232h.Cbus2);
	//printf("Cbus3 = %d\r\n", eeprom_232h.Cbus3);
	//printf("Cbus4 = %d\r\n", eeprom_232h.Cbus4);
	//printf("Cbus5 = %d\r\n", eeprom_232h.Cbus5);
	//printf("Cbus6 = %d\r\n", eeprom_232h.Cbus6);
	//printf("Cbus7 = %d\r\n", eeprom_232h.Cbus7);
	//printf("Cbus8 = %d\r\n", eeprom_232h.Cbus8);
	//printf("Cbus9 = %d\r\n", eeprom_232h.Cbus9);
	//printf("FT1248Cpol = %d\r\n", eeprom_232h.FT1248Cpol);
	//printf("FT1248Lsb = %d\r\n", eeprom_232h.FT1248Lsb);
	//printf("FT1248FlowControl = %d\r\n", eeprom_232h.FT1248FlowControl);
	//printf("IsFifo = %d\r\n", eeprom_232h.IsFifo);
	//printf("IsFifoTar = %d\r\n", eeprom_232h.IsFifoTar);
	//printf("IsFastSer = %d\r\n", eeprom_232h.IsFastSer);
	//printf("IsFT1248 = %d\r\n", eeprom_232h.IsFT1248);
	//printf("PowerSaveEnable = %d\r\n", eeprom_232h.PowerSaveEnable);
	//printf("DriverType = %d\r\n", eeprom_232h.DriverType);
	
	// 書き込みルーチン
	if (FT_Open(ftno, &ftHandle) == FT_OK) {
		if (FT_EEPROM_Program(ftHandle, &eeprom_232h, sizeof(eeprom_232h), Manufacturer, ManufacturerId, Description, SerialNumber) == FT_OK) {
			ret = TRUE;
		}
		FT_Close(ftHandle);
	}
	
	return ret;
}


//
// eeprom の内容を最低限チェックする
//
BOOL ChkEEProm(unsigned int ftno)
{
	BOOL ret = FALSE;
	FT_HANDLE ftHandle;

	// FTDI DLL の公開関数へのポインタ
	_FT_Open FT_Open = NULL;
	_FT_Close FT_Close = NULL;
	_FT_EEPROM_Read FT_EEPROM_Read = NULL;

	if (hFtModule) {
		FT_Open = (_FT_Open)GetProcAddress(hFtModule, "FT_Open");
		FT_Close = (_FT_Close)GetProcAddress(hFtModule, "FT_Close");
		FT_EEPROM_Read = (_FT_EEPROM_Read)GetProcAddress(hFtModule, "FT_EEPROM_Read");
	}

	char Manufacturer[64] = "";
	char ManufacturerId[64] = "";
	char Description[64] = "";
	char SerialNumber[64] = "";
	FT_EEPROM_232H eeprom_232h;
	eeprom_232h.common.deviceType = FT_DEVICE_232H;

	if (FT_Open(ftno, &ftHandle) == FT_OK) {
		if (FT_EEPROM_Read(ftHandle, &eeprom_232h, sizeof(eeprom_232h), Manufacturer, ManufacturerId, Description, SerialNumber) == FT_OK) {
			ret = TRUE;
			ret &= (eeprom_232h.Cbus5 == FT_232H_CBUS_IOMODE) ? TRUE : FALSE;
			ret &= (eeprom_232h.Cbus6 == FT_232H_CBUS_IOMODE) ? TRUE : FALSE;
			ret &= (eeprom_232h.IsFifo == 1) ? TRUE : FALSE;
			ret &= (eeprom_232h.IsFifoTar == 0) ? TRUE : FALSE;
			ret &= (eeprom_232h.IsFastSer == 0) ? TRUE : FALSE;
			ret &= (eeprom_232h.IsFT1248 == 0) ? TRUE : FALSE;
			ret &= (eeprom_232h.DriverType == FT_DRIVER_TYPE_D2XX) ? TRUE : FALSE;	// D2XX ドライバ

			ret &= (eeprom_232h.ACDriveCurrent == 8) ? TRUE : FALSE;	// とりあえず 8mA を要求する
			ret &= (eeprom_232h.ADDriveCurrent == 8) ? TRUE : FALSE;	// とりあえず 8mA を要求する

			//ret &= (eeprom_232h.Cbus9 == FT_232H_CBUS_PWREN) ? TRUE : FALSE;	// Power LED はどっちでもいい
			//ret &= (eeprom_232h.common.MaxPower == 200) ? TRUE : FALSE;	// MaxPower もとりあえずいいか
		}
		FT_Close(ftHandle);
	}

	return ret;
}


//
// eeprom を読み出して最低限必要な部分だけ書き直す
//
BOOL SetEEProm(unsigned int ftno) {

	BOOL ret = FALSE;
	FT_HANDLE ftHandle;

	// FTDI DLL の公開関数へのポインタ
	_FT_Open FT_Open = NULL;
	_FT_Close FT_Close = NULL;
	_FT_EEPROM_Read FT_EEPROM_Read = NULL;
	_FT_EEPROM_Program FT_EEPROM_Program = NULL;

	if (hFtModule) {
		FT_Open = (_FT_Open)GetProcAddress(hFtModule, "FT_Open");
		FT_Close = (_FT_Close)GetProcAddress(hFtModule, "FT_Close");
		FT_EEPROM_Read = (_FT_EEPROM_Read)GetProcAddress(hFtModule, "FT_EEPROM_Read");
		FT_EEPROM_Program = (_FT_EEPROM_Program)GetProcAddress(hFtModule, "FT_EEPROM_Program");
	}

	char Manufacturer[64] = "";
	char ManufacturerId[64] = "";
	char Description[64] = "";
	char SerialNumber[64] = "";

	FT_EEPROM_232H eeprom_232h;
	eeprom_232h.common.deviceType = FT_DEVICE_232H;

	if (FT_Open(ftno, &ftHandle) == FT_OK) {
		if (FT_EEPROM_Read(ftHandle, &eeprom_232h, sizeof(eeprom_232h), Manufacturer, ManufacturerId, Description, SerialNumber) == FT_OK) {

			eeprom_232h.common.MaxPower = 200;	// とりあえず 200mAを要求する
			eeprom_232h.Cbus5 = FT_232H_CBUS_IOMODE;
			eeprom_232h.Cbus6 = FT_232H_CBUS_IOMODE;
			eeprom_232h.Cbus9 = FT_232H_CBUS_PWREN;		// POWER LED を ON にしておこう
			eeprom_232h.IsFifo = 1;
			eeprom_232h.IsFifoTar = 0;
			eeprom_232h.IsFastSer = 0;
			eeprom_232h.IsFT1248 = 0;
			eeprom_232h.ACDriveCurrent = 8;			// 8mA にしておく
			eeprom_232h.ADDriveCurrent = 8;			// 8mA にしておく
			eeprom_232h.DriverType = FT_DRIVER_TYPE_D2XX;	// driver type は D2XX

			if (FT_EEPROM_Program(ftHandle, &eeprom_232h, sizeof(eeprom_232h), Manufacturer, ManufacturerId, Description, SerialNumber) == FT_OK) {
				ret = TRUE;
			}
		}
		FT_Close(ftHandle);
	}

	return ret;
}

//
// eeprom を FT_PROG のデフォルト値らしき値で埋める
// eeprom が BLANK 用。read しないで書き込む
//
BOOL InitEEProm(unsigned int ftno)
{
	BOOL ret = FALSE;
	FT_HANDLE ftHandle;

	// FTDI DLL の公開関数へのポインタ
	_FT_Open FT_Open = NULL;
	_FT_Close FT_Close = NULL;
	_FT_EEPROM_Program FT_EEPROM_Program = NULL;

	if (hFtModule) {
		FT_Open = (_FT_Open)GetProcAddress(hFtModule, "FT_Open");
		FT_Close = (_FT_Close)GetProcAddress(hFtModule, "FT_Close");
		FT_EEPROM_Program = (_FT_EEPROM_Program)GetProcAddress(hFtModule, "FT_EEPROM_Program");
	}

	char Manufacturer[64] = "FTDI";
	char ManufacturerId[64] = "FT";
	char Description[64] = "USB <-> Serial Converter";
	char SerialNumber[64] = "";

	FT_EEPROM_232H eeprom_232h;
	memset(&eeprom_232h, 0, sizeof(eeprom_232h));

	eeprom_232h.common.deviceType = FT_DEVICE_232H;
	eeprom_232h.common.VendorId = 0x0403;
	eeprom_232h.common.ProductId = 0x6014;
	eeprom_232h.common.SerNumEnable = 1;
	eeprom_232h.common.MaxPower = 100;
	eeprom_232h.ACDriveCurrent = 4;
	eeprom_232h.ADDriveCurrent = 4;
	eeprom_232h.DriverType = FT_DRIVER_TYPE_VCP;

	if (FT_Open(ftno, &ftHandle) == FT_OK) {
		if (FT_EEPROM_Program(ftHandle, &eeprom_232h, sizeof(eeprom_232h), Manufacturer, ManufacturerId, Description, SerialNumber) == FT_OK) {
			ret = TRUE;
		}
		FT_Close(ftHandle);
	}
	return ret;
}

//
// eeprom の内容を消去する
//
BOOL EraseEEProm(unsigned int ftno)
{
	BOOL ret = FALSE;
	FT_HANDLE ftHandle;

	// FTDI DLL の公開関数へのポインタ
	_FT_Open FT_Open = NULL;
	_FT_Close FT_Close = NULL;
	_FT_EraseEE FT_EraseEE = NULL;

	if (hFtModule) {
		FT_Open = (_FT_Open)GetProcAddress(hFtModule, "FT_Open");
		FT_Close = (_FT_Close)GetProcAddress(hFtModule, "FT_Close");
		FT_EraseEE = (_FT_EraseEE)GetProcAddress(hFtModule, "FT_EraseEE");
	}


	if (FT_Open(ftno, &ftHandle) == FT_OK) {
		if (FT_EraseEE(ftHandle) == FT_OK) {
			ret = TRUE;
		}
		FT_Close(ftHandle);
	}
	return ret;
}

//
// ヘルプ表示
//
void printHelp(void)
{
	_tprintf(_T("オプション\r\n"));
	_tprintf(_T("-init [NO]  ...  [NO] の FT232H の EEProm を初期化する\r\n"));
	_tprintf(_T("-chk [NO]   ...  [NO] の FT232H が YM2610 用の設定になっているかチェックする\r\n"));
	_tprintf(_T("-set [NO]   ...  [NO] の FT232H を YM2610 用の設定にセットする\r\n"));
	_tprintf(_T("-erase [NO] ...  [NO] の FT232H の EEProm を消去する\r\n"));
	_tprintf(_T("-r [NO]     ...  [NO] の FT232H の eeprom をファイルに書き出す\r\n"));
	_tprintf(_T("                 書き出すファイル名 = %s[NO].ini\r\n"), szDefWrName);
	_tprintf(_T("-w [NO]     ...  [NO] の FT232H の eeprom をファイルから読んだ値で書き換える\r\n"));
	_tprintf(_T("                 読み出すファイル名 = %s[NO].ini\r\n"), szDefReName);
}
