On Tue, 1 Oct 2013, Francois Gouget wrote:
[...]
> The timeout was too short and would only work for UARTs that have a 
> FIFO and where the trigger level was set just right. With this patch 
> we calculate how much time sending the test data will actually take 
> and tack on a small margin to take into account scheduling delays.

I should note that this does not fix the test failuers on the QEmu VMs, 
specifically the WineTestBot ones.
If QEmu 1.1.2 is anything like QEmu 1.6.0, then the serial port seems to 
operate at a fixed speed of about 1800000bps. This is so out of line 
with the 150bps that we request that it causes the test to fail.


[...]
>  * Windows reports that all bytes have been sent not when the UART's 
>    buffer is empty but when they all made it to the UART's buffer. Note 
>    that this can be tested (see next mail).

And here is this test. IT IS NOT MEANT TO BE COMMITTED.
(but seeing the WineTestBot results would still be interesting)

On my one Windows PC with a real UART (Intel(R) 82801DBM LPC Interface 
Controller - 24CC, i.e. ICH4 which emulates a 16550A UART) I get the 
following results which clearly illustrate the impact of the 
FIFO/trigger level.

comm.c:1100: WaitCommEvent(1 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(2 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(3 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(4 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(5 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(6 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(7 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(8 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(9 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(10 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(11 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(12 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(13 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(14 bytes) for EV_TXEMPTY took 0 ms
comm.c:1100: WaitCommEvent(15 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(16 bytes) for EV_TXEMPTY took 872 ms
comm.c:1100: WaitCommEvent(17 bytes) for EV_TXEMPTY took 872 ms
comm.c:1100: WaitCommEvent(18 bytes) for EV_TXEMPTY took 872 ms
comm.c:1100: WaitCommEvent(19 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(20 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(21 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(22 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(23 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(24 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(25 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(26 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(27 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(28 bytes) for EV_TXEMPTY took 871 ms
comm.c:1100: WaitCommEvent(29 bytes) for EV_TXEMPTY took 1802 ms
comm.c:1100: WaitCommEvent(30 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(31 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(32 bytes) for EV_TXEMPTY took 1802 ms
comm.c:1100: WaitCommEvent(33 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(34 bytes) for EV_TXEMPTY took 1802 ms
comm.c:1100: WaitCommEvent(35 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(36 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(37 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(38 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(39 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(40 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(41 bytes) for EV_TXEMPTY took 1802 ms
comm.c:1100: WaitCommEvent(42 bytes) for EV_TXEMPTY took 1803 ms
comm.c:1100: WaitCommEvent(43 bytes) for EV_TXEMPTY took 2734 ms
comm.c:1100: WaitCommEvent(44 bytes) for EV_TXEMPTY took 2734 ms
comm.c:1100: WaitCommEvent(45 bytes) for EV_TXEMPTY took 2734 ms
comm.c:1100: WaitCommEvent(46 bytes) for EV_TXEMPTY took 2734 ms
comm.c:1100: WaitCommEvent(47 bytes) for EV_TXEMPTY took 2734 ms
comm.c:1100: WaitCommEvent(48 bytes) for EV_TXEMPTY took 2734 ms
comm.c:1100: WaitCommEvent(49 bytes) for EV_TXEMPTY took 2734 ms
comm.c:1100: WaitCommEvent(50 bytes) for EV_TXEMPTY took 2734 ms


-- 
Francois Gouget <fgou...@free.fr>              http://fgouget.free.fr/
                          "Utilisateur" (nom commun) :
        Mot utilisé par les informaticiens en lieu et place d'"idiot".
commit d6f4c73ceb4640332c79561b4e8e7c23619aa669
Author: Francois Gouget <fgou...@free.fr>
Date:   Mon Sep 30 19:26:50 2013 +0200

    kernel32/tests: Serial port trigger-level test patch.
    
    This is just an exploration patch and is not meant to be committed.
    See the following for reference:
    http://www.tldp.org/HOWTO/Serial-HOWTO-18.html
    http://www.winehq.org/pipermail/wine-devel/2013-September/101160.html
    http://www.winehq.org/pipermail/wine-devel/2013-September/101490.html

diff --git a/dlls/kernel32/tests/comm.c b/dlls/kernel32/tests/comm.c
index 7ec5fc5..60c8f0a 100644
--- a/dlls/kernel32/tests/comm.c
+++ b/dlls/kernel32/tests/comm.c
@@ -706,8 +706,6 @@ static HANDLE test_OpenComm(BOOL doOverlap)
     {
 	if (hcom == INVALID_HANDLE_VALUE)
 	    trace("Could not find a valid COM port.\n");
-	else
-	    trace("Found Com port %s. Connected devices may disturb results\n", port_name);
 	/*shown = TRUE; */
     }
     if (hcom != INVALID_HANDLE_VALUE)
@@ -989,6 +987,120 @@ todo_wine
     }
 }
 
+
+static void test_triggerlevel(void)
+{
+    HANDLE hcom;
+    DCB dcb;
+    COMMTIMEOUTS timeouts;
+    char tbuf[65536];
+    DWORD before, after, bytes, timediff, evtmask, i;
+    BOOL res;
+    DWORD baud = SLOWBAUD;
+    OVERLAPPED ovl_write, ovl_wait;
+
+    for (i = 1; i < sizeof(tbuf); i+= (i < 50 ? 1 : i == 50 ? 950 : i))
+    {
+        hcom = test_OpenComm(TRUE);
+        if (hcom == INVALID_HANDLE_VALUE) return;
+
+        /* set a low baud rate to have ample time */
+        res = GetCommState(hcom, &dcb);
+        ok(res, "GetCommState error %d\n", GetLastError());
+        dcb.BaudRate = baud;
+        dcb.ByteSize = 8;
+        dcb.Parity = NOPARITY;
+        dcb.fRtsControl=RTS_CONTROL_ENABLE;
+        dcb.fDtrControl=DTR_CONTROL_ENABLE;
+        dcb.StopBits = ONESTOPBIT;
+        res = SetCommState(hcom, &dcb);
+        ok(res, "SetCommState error %d\n", GetLastError());
+        ZeroMemory(&dcb, sizeof(dcb));
+        res = GetCommState(hcom, &dcb);
+        ok(dcb.BaudRate == 150, "BaudRate=%d\n", dcb.BaudRate);
+        ok(dcb.ByteSize == 8, "ByteSize=%d\n", dcb.ByteSize);
+        ok(dcb.Parity == NOPARITY, "Parity=%d\n", dcb.Parity);
+        ok(dcb.StopBits == ONESTOPBIT, "StopBits=%d\n", dcb.StopBits);
+
+        ZeroMemory( &timeouts, sizeof(timeouts));
+        timeouts.ReadTotalTimeoutConstant = TIMEOUT;
+        res = SetCommTimeouts(hcom, &timeouts);
+        ok(res,"SetCommTimeouts error %d\n", GetLastError());
+
+        res = SetupComm(hcom, 1024, 1024);
+        ok(res, "SetUpComm error %d\n", GetLastError());
+
+        /* calling SetCommMask after WriteFile leads to WaitCommEvent failures
+         * due to timeout (no events) under testbot VMs and VirtualBox
+         */
+        res = SetCommMask(hcom, EV_TXEMPTY);
+        ok(res, "SetCommMask error %d\n", GetLastError());
+
+        S(U(ovl_write)).Offset = 0;
+        S(U(ovl_write)).OffsetHigh = 0;
+        ovl_write.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+        before = GetTickCount();
+        SetLastError(0xdeadbeef);
+        res = WriteFile(hcom, tbuf, i, &bytes, &ovl_write);
+        after = GetTickCount();
+        todo_wine
+            ok(!res && GetLastError() == ERROR_IO_PENDING, "WriteFile returned %d, error %d\n", res, GetLastError());
+        todo_wine
+            ok(!bytes, "expected 0, got %u\n", bytes);
+        ok(after - before < 30, "WriteFile took %d ms to write %d Bytes at %d Baud\n",
+           after - before, bytes, baud);
+        /* don't wait for WriteFile completion */
+
+        S(U(ovl_wait)).Offset = 0;
+        S(U(ovl_wait)).OffsetHigh = 0;
+        ovl_wait.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+        evtmask = 0;
+        before = GetTickCount();
+        SetLastError(0xdeadbeef);
+        res = WaitCommEvent(hcom, &evtmask, &ovl_wait);
+        ok(!res && GetLastError() == ERROR_IO_PENDING, "WaitCommEvent error %d\n", GetLastError());
+
+        res = WaitForSingleObject(ovl_wait.hEvent, 4000);
+        ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
+        if (res == WAIT_OBJECT_0)
+        {
+            res = GetOverlappedResult(hcom, &ovl_wait, &bytes, FALSE);
+            ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
+            ok(bytes == sizeof(evtmask), "expected %u, written %u\n", (UINT)sizeof(evtmask), bytes);
+            res = TRUE;
+        }
+        else
+        {
+            /* unblock pending wait */
+            trace("recovering after WAIT_TIMEOUT...\n");
+            res = SetCommMask(hcom, EV_TXEMPTY);
+            ok(res, "SetCommMask error %d\n", GetLastError());
+
+            res = WaitForSingleObject(ovl_wait.hEvent, 4000);
+            ok(res == WAIT_OBJECT_0, "WaitCommEvent failed with a timeout\n");
+
+            res = FALSE;
+            Sleep(3000);
+        }
+        after = GetTickCount();
+        ok(res, "WaitCommEvent error %d\n", GetLastError());
+        ok(evtmask & EV_TXEMPTY, "WaitCommEvent: expected EV_TXEMPTY, got %#x\n", evtmask);
+        CloseHandle(ovl_wait.hEvent);
+
+        timediff = after - before;
+        trace("%d bytes allegedly sent in %d ms, %.0fbps\n", i, timediff, ((double)i) * 10.0 * 1000.0 / (timediff ? timediff : 1));
+
+        res = WaitForSingleObject(ovl_write.hEvent, 0);
+        ok(res == WAIT_OBJECT_0, "WriteFile failed with a timeout\n");
+        res = GetOverlappedResult(hcom, &ovl_write, &bytes, FALSE);
+        ok(res, "GetOverlappedResult reported error %d\n", GetLastError());
+        ok(bytes == i, "expected %u, written %u\n", (UINT)i, bytes);
+        CloseHandle(ovl_write.hEvent);
+        CloseHandle(hcom);
+        Sleep(1000);
+    }
+}
+
 /* A new open handle should not return error or have bytes in the Queues */
 static void test_ClearCommError(void)
 {
@@ -2225,6 +2337,7 @@ START_TEST(comm)
     test_WaitBreak();
     test_stdio();
     test_read_write();
+    test_triggerlevel();
 
     if (!winetest_interactive)
     {


Reply via email to