【FatFs】車載外部ストレージ その120【SDカード直接制御③】

【FatFs】車載外部ストレージ その120【SDカード直接制御③】 車載外部ストレージ

バックナンバーはこちら。
https://www.simulationroom999.com/blog/In-vehicle-external-storage-backnumber/

はじめに

FatFs WinシミュレーションでSDカードに直接制御する話。
今回は「FatFs改造」の話。

登場人物

博識フクロウのフクさん

指差しフクロウ

イラストACにて公開の「kino_k」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=iKciwKA9&area=1

エンジニア歴8年の太郎くん

技術者太郎

イラストACにて公開の「しのみ」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=uCKphAW2&area=1

実験手順

フクさん
フクさん

想定実験手順は以下。
今回は「FatFs改造」の話。

  • FatFs改造方針を考える
  • FatFs改造 ← これの1回目/全3回
  • FatFsでSDカードのFAT認識
  • FatFsでファイル書き込みとWindowsでの認識
  • FatFsでFAT32フォーマットしてWindowsで認識
フクさん
フクさん

そして、全体構成

FatFS、FileSystem、DiskIO、DeviceIoControl、読み書き実施、SDHC、WindowsAPIを駆使してSDを直接制御
太郎くん
太郎くん

たしか、大体改造したソースコードを見るんだよね?

フクさん
フクさん

そうそう。
とりあえず、差分は以下だ。

FatFs改造差分コード

diff U3B win32/diskio.c win32/diskio.c
--- win32/diskio.c	Thu Dec  3 23:18:14 2020
+++ win32/diskio.c	Mon Jan  4 02:16:08 2021
@@ -14,8 +14,8 @@
 #define SZ_RAMDISK	135		/* Size of drive 0 (RAM disk) [MiB] */
 #define SS_RAMDISK	512		/* Initial sector size of drive 0 (RAM disk) [byte] */
 
-#define MIN_READ_ONLY	1	/* Read-only drive from */
-#define	MAX_READ_ONLY	1	/* Read-only drive to */
+#define MIN_READ_ONLY	5	/* Read-only drive from */
+#define	MAX_READ_ONLY	5	/* Read-only drive to */
 
 
 
@@ -55,7 +55,7 @@
 	DWORD dw;
 	int drv;
 
-
+#if 0
 	for (;;) {
 		Sleep(100);
 		for (drv = 1; drv < Drives; drv++) {
@@ -69,6 +69,7 @@
 			}
 		}
 	}
+#endif
 }
 
 
@@ -92,6 +93,12 @@
 		return 1;
 	}
 
+	if (pdrv > 3) {
+		stat->n_sectors = 1024 * 1024;
+		stat->sz_sector = 512;
+		stat->status = 0;
+	}
+
 	/* Get drive size */
 	if (!DeviceIoControl(h, IOCTL_STORAGE_CHECK_VERIFY, 0, 0, 0, 0, &rb, 0)) return 0;
 	if (DeviceIoControl(h, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 0, 0, &parms_ex, sizeof parms_ex, &rb, 0)) {
@@ -119,6 +125,29 @@
    Public Functions
 
 ---------------------------------------------------------------------------*/
+static HANDLE hSD[10];
+
+void dismount_volume(const TCHAR drvlet[])
+{
+	int i;
+	DWORD dummy;
+	for (i = 0; i < 10; i++) {
+		HANDLE *pSD = &hSD[i];
+		WCHAR szlogicalDrvName[10] = L"\\\\.\\d:";
+		if (drvlet[i] == '\0') {
+			break;
+		}
+		szlogicalDrvName[4] = drvlet[i];
+		if ((*pSD != 0)) {
+			DeviceIoControl(*pSD, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0, &dummy, 0);
+			CloseHandle(*pSD);
+			*pSD = 0;
+		}
+		*pSD = CreateFileW(szlogicalDrvName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
+		DeviceIoControl(*pSD, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &dummy, 0);
+		DeviceIoControl(*pSD, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0, &dummy, 0);
+	}
+}
 
 
 /*-----------------------------------------------------------------------*/
@@ -143,17 +172,29 @@
 	if (!RamDisk) return 0;
 	Stat[0].sz_sector = SS_RAMDISK;
 
-	if (GetVersionEx(&vinfo) == FALSE) return 0;
-	ndrv = vinfo.dwMajorVersion > 5 ? 1 : MAX_DRIVES;
+	//if (GetVersionEx(&vinfo) == FALSE) return 0;
+	//ndrv = vinfo.dwMajorVersion > 5 ? 1 : MAX_DRIVES;
+	ndrv = MAX_DRIVES;
 
 	for (pdrv = 0; pdrv < ndrv; pdrv++) {
 		if (pdrv == 0) {	/* \\.\PhysicalDrive0 is never mapped to disk function, but RAM disk is mapped to pd#0 instead. */
 			swprintf(str, 50, L"RAM Disk");
-		} else {			/* \\.\PhysicalDrive<n> (n=1..) are mapped to disk funtion pd#<n>. */
+		} else if(pdrv <= 3){			/* \\.\PhysicalDrive<n> (n=1..) are mapped to disk funtion pd#<n>. */
 			swprintf(str, 50, L"\\\\.\\PhysicalDrive%u", pdrv);
-			h = CreateFileW(str, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
-			if (h == INVALID_HANDLE_VALUE) break;
-			Stat[pdrv].h_drive = h;
+			if (Stat[pdrv].h_drive != 0) {
+				CloseHandle(Stat[pdrv].h_drive);
+			}
+			h = CreateFileW(str, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
+			if (h != INVALID_HANDLE_VALUE)
+				Stat[pdrv].h_drive = h;
+		}else {
+			swprintf(str, 50, L"PhysicalDrive%u", pdrv);
+			if (Stat[pdrv].h_drive != 0) {
+				CloseHandle(Stat[pdrv].h_drive);
+			}
+			h = CreateFileW(str, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, 0);
+			if (h != INVALID_HANDLE_VALUE)
+				Stat[pdrv].h_drive = h;
 		}
 		wprintf(L"PD#%u <== %s", pdrv, str);
 		if (get_status(pdrv)) {
@@ -321,9 +362,35 @@
 				res = RES_ERROR;
 			} else {
 				memcpy(Buffer, buff, nc);
-				if (!WriteFile(Stat[pdrv].h_drive, Buffer, nc, &rnc, 0) || nc != rnc) {
-					res = RES_ERROR;
+				{
+					int i;
+					//DWORD dummy;
+					//DeviceIoControl( Stat[pdrv].h_drive, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &dummy, 0 );
+					//DeviceIoControl( Stat[pdrv].h_drive, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0, &dummy, 0 );
+					for (i = 0; i < 10; i++) {
+						if (!WriteFile(Stat[pdrv].h_drive, Buffer, nc, &rnc, 0) || nc != rnc) {
+							LPVOID lpMsgBuf;
+							res = RES_ERROR;
+
+							FormatMessage(
+								FORMAT_MESSAGE_ALLOCATE_BUFFER  //      テキストのメモリ割り当てを要求する
+								| FORMAT_MESSAGE_FROM_SYSTEM    //      エラーメッセージはWindowsが用意しているものを使用
+								| FORMAT_MESSAGE_IGNORE_INSERTS,//      次の引数を無視してエラーコードに対するエラーメッセージを作成する
+								NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),//   言語を指定
+								(LPTSTR)&lpMsgBuf,                          //      メッセージテキストが保存されるバッファへのポインタ
+								0,
+								NULL);
+							printf((char*)lpMsgBuf);
+
+						}
+						else {
+							res = RES_OK;
+							break;
+						}
+					}
+					//DeviceIoControl( Stat[pdrv].h_drive, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0, &dummy, 0 );
 				}
+				FlushFileBuffers(Stat[pdrv].h_drive);
 			}
 		}
 	} else {	/* RAM disk */
diff U3B win32/main.c win32/main.c
--- win32/main.c	Thu Dec  3 23:18:14 2020
+++ win32/main.c	Sun May  2 02:48:11 2021
@@ -26,8 +26,8 @@
 /* This is an example of volume - partition mapping table */
 PARTITION VolToPart[FF_VOLUMES] = {
 	{0, 1},	/* "0:" ==> 1st partition on PD#0 */
-	{0, 2},	/* "1:" ==> 2nd partition on PD#0 */
-	{0, 3},	/* "2:" ==> 3rd partition on PD#0 */
+//	{0, 2},	/* "1:" ==> 2nd partition on PD#0 */
+//	{0, 3},	/* "2:" ==> 3rd partition on PD#0 */
 	{1, 0},	/* "1:" ==> PD#1 */
 	{2, 0},	/* "2:" ==> PD#2 */
 	{3, 0},	/* "3:" ==> PD#3 */
@@ -559,6 +559,12 @@
 	zprintf(L"FatFs module test monitor (%s, CP%u, %s)\n\n", FF_USE_LFN ? L"LFN" : L"SFN", FF_CODE_PAGE, uni[FF_LFN_UNICODE]);
 
 	assign_drives();	/* Find physical drives on the PC */
+	{
+		extern void dismount_volume(const TCHAR drvlet[]);
+		const TCHAR drvlet[10] = { 'd','e','f','g','\0' };
+		dismount_volume(drvlet);
+	}
+
 #if FF_MULTI_PARTITION
 	zprintf(L"\nMultiple partition is enabled. Logical drives are associated with the patitions as follows:\n");
 	for (cnt = 0; cnt < sizeof VolToPart / sizeof (PARTITION); cnt++) {

差分コードの解説

フクさん
フクさん

コードの解説は次回かなー。

太郎くん
太郎くん

とりあえず、気になるポイントは以下かな。

  • dismount_volume関数
  • main.cのVolToPart配列
フクさん
フクさん

じゃ、そこに注力して解説しよう。

まとめ

フクさん
フクさん

まとめだよ。

  • FatFs改造のソースコード差分提示。
  • 次回から以下に注力する形で開設予定。
    • dismount_volume関数。
      • DeviceIoControlがポイントとなる。
    • main.cのVolToPart配列。
      • 論理ドライブと物理ドライブ関連。

バックナンバーはこちら。

コメント

タイトルとURLをコピーしました