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\x82o\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){