[ttssh2-commit] [10557] データ送信の実装を修正

Back to archive index
scmno****@osdn***** scmno****@osdn*****
2023年 1月 31日 (火) 23:57:12 JST


Revision: 10557
          https://osdn.net/projects/ttssh2/scm/svn/commits/10557
Author:   zmatsuo
Date:     2023-01-31 23:57:12 +0900 (Tue, 31 Jan 2023)
Log Message:
-----------
データ送信の実装を修正

- 送信関連の実装が適当だったので修正
  - overlapedな書き込みをできるようにした
- エラー後close()できなかったので修正

Modified Paths:
--------------
    branches/ttcomtester/tools/ttcomtester/CMakeLists.txt
    branches/ttcomtester/tools/ttcomtester/README.md
    branches/ttcomtester/tools/ttcomtester/device_com.cpp
    branches/ttcomtester/tools/ttcomtester/main.cpp

-------------- next part --------------
Modified: branches/ttcomtester/tools/ttcomtester/CMakeLists.txt
===================================================================
--- branches/ttcomtester/tools/ttcomtester/CMakeLists.txt	2023-01-31 12:43:07 UTC (rev 10556)
+++ branches/ttcomtester/tools/ttcomtester/CMakeLists.txt	2023-01-31 14:57:12 UTC (rev 10557)
@@ -14,8 +14,14 @@
   #
   ${CMAKE_CURRENT_SOURCE_DIR}/../../teraterm/common/asprintf.h
   ${CMAKE_CURRENT_SOURCE_DIR}/../../teraterm/common/codeconv.h
-  )
+)
 
+target_compile_options(
+  ${PACKAGE_NAME}
+  PRIVATE
+  /W4
+)
+
 target_include_directories(
   ${PACKAGE_NAME}
   PRIVATE

Modified: branches/ttcomtester/tools/ttcomtester/README.md
===================================================================
--- branches/ttcomtester/tools/ttcomtester/README.md	2023-01-31 12:43:07 UTC (rev 10556)
+++ branches/ttcomtester/tools/ttcomtester/README.md	2023-01-31 14:57:12 UTC (rev 10557)
@@ -4,6 +4,37 @@
 - コマンドラインプログラム
   - cmd などから実行する
 
+## 使い方
+
+### コマンドライン
+
+```
+ttcomtester [options]
+  -h, --help               show this
+  -v, --verbose            verbose, 'v' command
+  -i, --inifile [inifile]  read inifile, default=ttcomtester.ini
+  -r, rts [rts]            RTS/CTS(HARD) flow {off|on|hs|toggle}
+  -d, --device [name]      open device name, ex com2
+```
+
+### コマンド
+
+ttcomtester はキー入力を受け付け、つぎの2つの状態がある。
+
+- command mode
+  - ttcomtester へキーで指示するためのモード
+  - ':' キーで send mode へ切り替わる
+  - 'o' device open
+  - 'c' device open
+  - 'q' 終了
+  - :
+  - ' ' (スペース) で使えるキーを表示
+- send mode
+  - 押下したきーコードをそのまま送信するモード
+  - ':' キーで command mode へ切り替わる
+
+デバイスをオープンした状態のとき、データを受信すると表示する。
+
 ## 動作確認
 
 - シリアルをクロス接続する
@@ -58,3 +89,7 @@
   - https://www.hilgraeve.com/hyperterminal-trial/
   - A free 30 day trial
 
+## Microsoft
+
+- Serial Communications in Win32
+  - https://learn.microsoft.com/en-us/previous-versions/ms810467(v=msdn.10)?redirectedfrom=MSDN

Modified: branches/ttcomtester/tools/ttcomtester/device_com.cpp
===================================================================
--- branches/ttcomtester/tools/ttcomtester/device_com.cpp	2023-01-31 12:43:07 UTC (rev 10556)
+++ branches/ttcomtester/tools/ttcomtester/device_com.cpp	2023-01-31 14:57:12 UTC (rev 10557)
@@ -20,6 +20,8 @@
 	bool commtimeouts_setted;
 	COMMTIMEOUTS commtimeouts;
 	bool read_requested;
+	bool write_requested;
+	DWORD write_left;
 	enum {
 		STATE_CLOSE,
 		STATE_OPEN,
@@ -66,7 +68,7 @@
 		return ERROR_HANDLES_CLOSED;
 	}
 
-	if (p->state != comdata_t::STATE_OPEN) {
+	if (p->state == comdata_t::STATE_CLOSE) {
 		return ERROR_SUCCESS;
 	}
 
@@ -139,13 +141,12 @@
 	p->h = h;
 
 	p->state = comdata_t::STATE_OPEN;
+	p->read_requested = false;
+	p->write_requested = false;
 
 	return ERROR_SUCCESS;
 }
 
-// https://donnk.com/Nmura/soft/help015.html
-// http://nonsoft.la.coocan.jp/SoftSample/VC/SampleRs232c.html
-
 /**
  *	\x83y\x83\x93\x83f\x83B\x83\x93\x83O\x8F\xF3\x91Ԃ\xF0\x83`\x83F\x83b\x83N\x82\xB7\x82\xE9
  *
@@ -152,7 +153,7 @@
  *	@param	readed				\x93ǂݍ\x9E\x82񂾃o\x83C\x83g\x90\x94
  *								0	\x93ǂݍ\x9E\x82܂\xEA\x82Ă\xA2\x82Ȃ\xA2
  *	@return	ERROR_SUCCESS		\x93ǂݍ\x9E\x82\xF1\x82\xBE (\x83y\x83\x93\x83f\x83B\x83\x93\x83O\x8F\xF3\x91ԏI\x97\xB9)
- *	@return	ERROR_IO_PENDING	\x93ǂݍ\x9E\x82ݑ҂\xBF(\x90\xB3\x8F\xED,
+ *	@return	ERROR_IO_PENDING	\x93ǂݍ\x9E\x82ݑ҂\xBF(\x90\xB3\x8F\xED)
  *	@return	etc					\x83G\x83\x89\x81[
  */
 static DWORD wait_read(device_t *device, size_t *readed)
@@ -243,7 +244,7 @@
 	}
 	if (p->read_requested) {
 		// \x83G\x83\x89\x81[\x81A\x83\x8A\x83N\x83G\x83X\x83g\x92\x86
-		return ERROR_IO_PENDING;
+		return ERROR_INVALID_OPERATION;
 	}
 
 	DWORD readed_;
@@ -268,6 +269,15 @@
 	return ERROR_SUCCESS;
 }
 
+/**
+ *	\x83y\x83\x93\x83f\x83B\x83\x93\x83O\x8F\xF3\x91Ԃ\xF0\x83`\x83F\x83b\x83N\x82\xB7\x82\xE9
+ *
+ *	@param	writed				\x8F\x91\x82\xAB\x8D\x9E\x82܂ꂽ\x83o\x83C\x83g\x90\x94
+ *								0	\x93ǂݍ\x9E\x82܂\xEA\x82Ă\xA2\x82Ȃ\xA2
+ *	@return	ERROR_SUCCESS		\x93ǂݍ\x9E\x82\xF1\x82\xBE (\x83y\x83\x93\x83f\x83B\x83\x93\x83O\x8F\xF3\x91ԏI\x97\xB9)
+ *	@return	ERROR_IO_PENDING	\x93ǂݍ\x9E\x82ݑ҂\xBF(\x90\xB3\x8F\xED)
+ *	@return	etc					\x83G\x83\x89\x81[
+ */
 static DWORD wait_write(device_t *device, size_t *writed)
 {
 	comdata_t *p = (comdata_t *)device->private_data;
@@ -276,26 +286,49 @@
 	if (p->state != comdata_t::STATE_OPEN) {
 		return ERROR_NOT_READY;
 	}
-#if 0
-	if (p->read_requested == false) {
+
+	if (p->write_requested == false) {
 		// \x83\x8A\x83N\x83G\x83X\x83g\x82\xB5\x82Ă\xA2\x82Ȃ\xA2\x82̂ɑ҂\xBF\x8F\xF3\x91ԂɂȂ\xC1\x82\xBD
 		return ERROR_INVALID_OPERATION;
 	}
-#endif
 
-	// \x83C\x83x\x83\x93\x83g\x94\xAD\x90\xB6(\x8F\x91\x82\xAB\x8D\x9E\x82݊\xAE\x97\xB9/\x83G\x83\x89\x81[\x81c)
-	DWORD writed_;
-	DWORD r = GetOverlappedResult(h, &p->wol, &writed_, FALSE);
-	if (r) {
-		printf("GetOverlappedResult %d\n", r);
-		*writed = writed_;
+	//const DWORD timeout_ms = INFINITE;
+	const DWORD timeout_ms = 0;
+	DWORD wait = WaitForSingleObject(p->wol.hEvent, timeout_ms);
+	if (wait == WAIT_TIMEOUT) {
+		// \x82܂\xBE\x91\x97\x90M\x82\xB5\x82Ă\xA2\x82Ȃ\xA2
+		*writed = 0;
 		return ERROR_IO_PENDING;
-		//return ERROR_SUCCESS;
 	}
+	else if (wait == WAIT_OBJECT_0) {
+		// \x83C\x83x\x83\x93\x83g\x94\xAD\x90\xB6(\x8F\x91\x82\xAB\x8D\x9E\x82\xF1\x82\xBE/\x83G\x83\x89\x81[\x81c)
+		DWORD writed_;
+		DWORD r = GetOverlappedResult(h, &p->wol, &writed_, FALSE);
+		if (r) {
+			*writed = writed_;
+			p->write_left -= writed_;
+			if (p->write_left == 0) {
+				// \x91\x97\x90M\x8A\xAE\x97\xB9
+				p->write_requested = false;
+				return ERROR_SUCCESS;
+			}
+			else {
+				// \x82܂\xBE\x83y\x83\x93\x83f\x83B\x83\x93\x83O\x92\x86
+				return ERROR_IO_PENDING;
+			}
+		}
+		else {
+			DWORD e = GetLastError();
+			p->state = comdata_t::STATE_ERROR;
+			*writed = 0;
+			return e;
+		}
+	}
 	else {
-		DWORD e = GetLastError();
+		// WAIT_FAILED
 		p->state = comdata_t::STATE_ERROR;
 		*writed = 0;
+		DWORD e = GetLastError();
 		return e;
 	}
 }
@@ -302,15 +335,12 @@
 
 /**
  *	\x8F\x91\x82\xAB\x8D\x9E\x82\xDD
- *		TODO
- *			- overlap\x82ł\xBF\x82\xE1\x82\xF1\x82Ɠ\xAE\x82\xA2\x82Ă\xA2\x82\xE9?\x83`\x83F\x83b\x83N
- *			- \x8F\x91\x82\xAB\x8D\x9E\x82݊\xAE\x97\xB9\x83`\x83F\x83b\x83N\x82\xF0\x8D\xEC\x82\xE9
+ *
  *	@return	ERROR_SUCCESS		\x8F\x91\x82\xAB\x8D\x9E\x82݊\xAE\x97\xB9
- *	@return	ERROR_IO_PENDING	\x8F\x91\x82\xAB\x8D\x9E\x82ݒ\x86 (\x83V\x83\x8A\x83A\x83\x8B\x82̎\x9E\x82͔\xAD\x90\xB6\x82\xB5\x82Ȃ\xA2)
- *								wait_write() \x82Ŋ\xAE\x97\xB9\x82\xF0\x91҂\xC2 (\x96\xA2\x83e\x83X\x83g)
+ *	@return	ERROR_IO_PENDING	\x8F\x91\x82\xAB\x8D\x9E\x82ݒ\x86
+ *								wait_write() \x82Ŋ\xAE\x97\xB9\x82\xF0\x91҂\xC2
+ *	@return	etc					\x83G\x83\x89\x81[
  */
-// http://www.ys-labo.com/BCB/2007/070512%20RS232C%20zenpan.html
-// https://learn.microsoft.com/en-us/previous-versions/ms810467(v=msdn.10)?redirectedfrom=MSDN
 static DWORD write(device_t *device, const void *buf, size_t buf_len, size_t *writed)
 {
 	comdata_t *p = (comdata_t *)device->private_data;
@@ -325,6 +355,11 @@
 		return ERROR_SUCCESS;
 	}
 
+	if (p->write_requested == true) {
+		// \x83G\x83\x89\x81[\x81A\x83\x8A\x83N\x83G\x83X\x83g\x92\x86
+		return ERROR_INVALID_OPERATION;
+	}
+
 #if 0
 	DWORD Errors;
 	COMSTAT Comstat;
@@ -350,17 +385,20 @@
 	}
 #endif
 
+	p->write_left = (DWORD)buf_len;
 	DWORD writed_;
 	BOOL r = WriteFile(h, buf, (DWORD)buf_len, &writed_, &p->wol);
 	if (!r) {
 		err = GetLastError();
 		if (err == ERROR_IO_PENDING) {
-#if 1
-			const DWORD timeout_ms = INFINITE;
+			p->write_requested = true;
+			//const DWORD timeout_ms = INFINITE;
+			const DWORD timeout_ms = 0;
 			DWORD wait = WaitForSingleObject(p->wol.hEvent, timeout_ms);
 			if (wait == WAIT_TIMEOUT) {
-				// \x83u\x83\x8D\x83b\x83N\x82\xB7\x82\xE9\x82̂Ŕ\xAD\x90\xB6\x82\xB5\x82Ȃ\xA2
-				;
+				// \x82܂\xBE\x91\x97\x90M\x82\xB5\x82Ă\xA2\x82Ȃ\xA2
+				*writed = 0;
+				return ERROR_IO_PENDING;
 			}
 			else if (wait == WAIT_OBJECT_0) {
 				// \x83C\x83x\x83\x93\x83g\x94\xAD\x90\xB6(\x8F\x91\x82\xAB\x8D\x9E\x82݊\xAE\x97\xB9/\x83G\x83\x89\x81[\x81c)
@@ -390,10 +428,6 @@
 				DWORD e = GetLastError();
 				return e;
 			}
-#else
-			*writed = buf_len;
-			return ERROR_SUCCESS;
-#endif
 		}
 		else {
 			p->state = comdata_t::STATE_ERROR;
@@ -402,10 +436,16 @@
 			return e;
 		}
 	}
-	if (writed != NULL) {
-		*writed = writed_;
+	else {
+		if (writed != NULL) {
+			*writed = writed_;
+		}
+		p->write_left -= writed_;
+		if (p->write_left != 0) {
+			p->write_requested = true;
+		}
+		return ERROR_SUCCESS;
 	}
-	return err;
 }
 
 static DWORD ctrl(device_t *device, device_ctrl_request request, ...)

Modified: branches/ttcomtester/tools/ttcomtester/main.cpp
===================================================================
--- branches/ttcomtester/tools/ttcomtester/main.cpp	2023-01-31 12:43:07 UTC (rev 10556)
+++ branches/ttcomtester/tools/ttcomtester/main.cpp	2023-01-31 14:57:12 UTC (rev 10557)
@@ -17,10 +17,12 @@
 static void usage()
 {
 	printf(
-		"ttcomtester [option]\n"
-		"  -h\n"
-		"  -v\n"
-		"  -i ttcomtester.ini\n"
+        "ttcomtester [options]\n"
+        "  -h, --help               show this\n"
+        "  -v, --verbose            verbose, 'v' command\n"
+        "  -i, --inifile [inifile]  read inifile, default=ttcomtester.ini\n"
+        "  -r, rts [rts]            RTS/CTS(HARD) flow {off|on|hs|toggle}\n"
+        "  -d, --device [name]      open device name, ex com2\n"
 		);
 }
 
@@ -30,8 +32,8 @@
 		"key:\n"
 		"   command mode\n"
 		"':'	go send mode\n"
-		"'o'	open\n"
-		"'c'	close\n"
+		"'o'	device open\n"
+		"'c'	device close\n"
 		"'q'	quit\n"
 		"'r'	RTS 0/1\n"
 		"'d'	DTR 0/1\n"
@@ -137,7 +139,7 @@
 
 	opterr = 0;
     while(1) {
-		int c = getopt_long_w(argc, argv, L"vhi:r:", long_options, NULL);
+		int c = getopt_long_w(argc, argv, L"vhi:r:d:", long_options, NULL);
         if(c == -1) break;
 
         switch (c)
@@ -263,12 +265,15 @@
 		timeouts.WriteTotalTimeoutMultiplier = 0;
 		timeouts.WriteTotalTimeoutConstant = 0;
 #endif
+#if 1
 		// \x8D\xA1\x89\xF1\x92\xF1\x88Ă\xB7\x82\xE9\x92l
 		timeouts.ReadIntervalTimeout = 1;
 		timeouts.ReadTotalTimeoutMultiplier = 0;
 		timeouts.ReadTotalTimeoutConstant = 0;
-		timeouts.WriteTotalTimeoutMultiplier = 0;
+		timeouts.WriteTotalTimeoutMultiplier = 20;
+		//timeouts.WriteTotalTimeoutMultiplier = 0;
 		timeouts.WriteTotalTimeoutConstant = 1;
+#endif
 		ope->ctrl(dev, SET_COM_TIMEOUTS, &timeouts);
 	}
 
@@ -284,11 +289,13 @@
 	bool dtr = true;
 	bool echo_mode = false;
 	bool check_line_state = true;
+	bool write_pending = false;
 	enum {
 		STATE_CLOSE,
 		STATE_OPEN,
 		STATE_ERROR,
 	} state = STATE_CLOSE;
+	printf("command mode\n");
 	while (!quit_flag) {
 		if (_kbhit() == 0) {
 			// \x83L\x81[\x82\xAA\x89\x9F\x82\xB3\x82\xEA\x82Ă\xA2\x82Ȃ\xA2
@@ -303,18 +310,20 @@
 					DWORD e = ope->open(dev);
 					if (e == ERROR_SUCCESS) {
 						state = STATE_OPEN;
+						if (verbose) {
+							DCB dcb;
+							ope->ctrl(dev, GET_COM_DCB, &dcb);
+							dumpDCB(&dcb);
+							COMMTIMEOUTS timeouts;
+							ope->ctrl(dev, GET_COM_TIMEOUTS, &timeouts);
+							dumpCOMMTIMEOUTS(&timeouts);
+						}
 					}
 					else {
 						DispErrorStr(L"open()", e);
 					}
-					if (verbose) {
-						DCB dcb;
-						ope->ctrl(dev, GET_COM_DCB, &dcb);
-						dumpDCB(&dcb);
-						COMMTIMEOUTS timeouts;
-						ope->ctrl(dev, GET_COM_TIMEOUTS, &timeouts);
-						dumpCOMMTIMEOUTS(&timeouts);
-					}
+					receive_pending = false;
+					write_pending = false;
 					break;
 				}
 				case 'c': {
@@ -336,16 +345,8 @@
 						printf("sent %zu bytes\n", sent_len);
 					}
 					else if (e == ERROR_IO_PENDING) {
-						size_t sent_len_total = sent_len;
-						while(1) {
-							DWORD r = ope->wait_write(dev, &sent_len);
-							if (r != ERROR_SUCCESS) {
-								printf("send error\n");
-							}
-							sent_len_total += sent_len;
-							printf("send size %zu(%zu)/%zu\n", sent_len_total, sent_len, send_len);
-							Sleep(100);
-						}
+						printf("send pending..\n");
+						write_pending = true;
 					}
 					else {
 						DispErrorStr(L"write()", e);
@@ -484,16 +485,24 @@
 				}
 				else {
 					if (state == STATE_OPEN) {
-						char send_text[2];
-						size_t sent_len;
-						send_text[0] = (char)c;
-						DWORD e = ope->write(dev, send_text, 1, &sent_len);
-						if (e == ERROR_SUCCESS) {
-							printf("send %02x, %zu byte\n", c, sent_len);
+						if (write_pending) {
+							printf("writing..\n");
 						}
 						else {
-							DispErrorStr(L"write() error", e);
-							state = STATE_ERROR;
+							char send_text[2];
+							size_t sent_len;
+							send_text[0] = (char)c;
+							DWORD e = ope->write(dev, send_text, 1, &sent_len);
+							if (e == ERROR_SUCCESS) {
+								printf("send %02x, %zu byte\n", c, sent_len);
+							}
+							else if (e == ERROR_IO_PENDING) {
+								write_pending = true;
+							}
+							else {
+								DispErrorStr(L"write() error", e);
+								state = STATE_ERROR;
+							}
 						}
 					}
 				}
@@ -500,46 +509,66 @@
 			}
 		}
 
-		uint8_t buf[1024];
+		static uint8_t buf[1024];
 		size_t len = 0;
 		DWORD e;
 		if (state != STATE_OPEN) {
 			Sleep(1);
 		}
-		else if (receive_pending == false) {
-			e = ope->read(dev, buf, sizeof(buf), &len);
-			if (e == ERROR_SUCCESS) {
-				if(len > 0) {
-					printf("read:\n");
-					dump(buf, len);
+		else {
+			if (write_pending == true) {
+				size_t sent_len;
+				e = ope->wait_write(dev, &sent_len);
+				if (e == ERROR_IO_PENDING) {
+					// \x82܂\xBE\x91҂\xBF\x8F\xF3\x91\xD4
+					if (sent_len != 0) {
+						printf("send size %zu (pending)\n", sent_len);
+					}
 				}
+				else if (e == ERROR_SUCCESS) {
+					printf("send size %zu (finish)\n", sent_len);
+					write_pending = false;
+				} else if (e != ERROR_SUCCESS) {
+					DispErrorStr(L"write() error", e);
+					state = STATE_ERROR;
+					printf("send error\n");
+				}
 			}
-			else if (e == ERROR_IO_PENDING) {
-				printf("read pending\n");
-				receive_pending = true;
+			if (receive_pending == false) {
+				e = ope->read(dev, buf, sizeof(buf), &len);
+				if (e == ERROR_SUCCESS) {
+					if(len > 0) {
+						printf("read:\n");
+						dump(buf, len);
+					}
+				}
+				else if (e == ERROR_IO_PENDING) {
+					printf("read pending\n");
+					receive_pending = true;
+				}
+				else {
+					DispErrorStr(L"read() error", e);
+					state = STATE_ERROR;
+				}
 			}
 			else {
-				DispErrorStr(L"read() error", e);
-				state = STATE_ERROR;
+				e = ope->wait_read(dev, &len);
+				if (e == ERROR_IO_PENDING) {
+					// \x82܂\xBE\x91҂\xBF\x8F\xF3\x91\xD4
+					;
+				}
+				else if (e == ERROR_SUCCESS) {
+					printf("wait_read:\n");
+					dump(buf, len);
+					receive_pending = false;
+				}
+				else {
+					DispErrorStr(L"wait_read", e);
+					state = STATE_ERROR;
+					receive_pending = false;
+				}
 			}
 		}
-		else {
-			e = ope->wait_read(dev, &len);
-			if (e == ERROR_IO_PENDING) {
-				// \x82܂\xBE\x91҂\xBF\x8F\xF3\x91\xD4
-				;
-			}
-			else if (e == ERROR_SUCCESS) {
-				printf("wait_read:\n");
-				dump(buf, len);
-				receive_pending = false;
-			}
-			else {
-				DispErrorStr(L"wait_read", e);
-				state = STATE_ERROR;
-				receive_pending = false;
-			}
-		}
 
 		if (echo_mode) {
 			if (len > 0){


ttssh2-commit メーリングリストの案内
Back to archive index