Serial hanging up

Hey, I'm having some problems with serial communication. I need to communicate a Windows PC with 2 devices, both requiring reading and writing. These devices are RS422 and use a baud rate of 12800. They require data sent approximately every 100 ms of 84 bytes. They will send data back to be received by the Windows PC whenever it feels like it (the document for the device provides no help on that one). The receive size is variable - a multiple of 6 bytes - and usually approximately 54 bytes long.

Two questions:

First, what threading model would be suggested for this? I seem to be running out of cycles to keep these devices going. So far, it has worked best to have a single thread per device, doing both reading and writing to one device on each thread. It would seem that some form of threading would be necessary because at a 12800 baud rate, the 84 bytes should take ~52.5 ms, and since they both need to send this, that leaves very little room for the receive before the next pass of send (send every 100 ms).

Secondly, and perhaps most importantly, the WriteFile calls in PortMon (tool for debugging and monitoring communication) sporadically take 100 ms. The ReadFile occasionally also has timeouts. This makes the two threads not have enough cycles to both get their tasks done fast enough and one thread randomly will get behind and my serial device loses data because it was not receiving at 100 ms. Why would a WriteFile take this long? The ReadFile timeout is most likely due to the WriteFile taking all the cycles. Code as follows:

Creation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
bool SerialPort::Create(const string &szPort, unsigned long uBaudRate, unsigned char uByteSize, unsigned char uParity, unsigned char uStopBits)
{
	// Already Created
	if(*m_port != INVALID_HANDLE_VALUE)
        	return false;

        // Create Port
        *m_port = CreateFile(szPort.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
        if(*m_port == INVALID_HANDLE_VALUE)
        	return false;

        // Get Comm State
        if(!GetCommState(*m_port, &m_tDCB))
        {
        	// Close
                Close();
                return false;
        }

        // Set Port Properties
        m_tDCB.BaudRate = uBaudRate;
        m_tDCB.ByteSize = uByteSize;
        m_tDCB.Parity = uParity;
        m_tDCB.StopBits = uStopBits;

        // Set Comm State
        if(!SetCommState(*m_port, &m_tDCB))
        {
        	// Close
                Close();
                return false;
        }

        // Success
        return true;
}


Writing Asynchronous - (called every 100 ms on the thread)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int SerialPort::SendBytesA(const char *pBytes, int nByteCount)
{
	// Invalid Port
	if(*m_port == INVALID_HANDLE_VALUE)
        	return 0;

        OVERLAPPED tOverlappedSend = {0};
        unsigned long uBytesWritten = 0;

        // Create Overlapped Event
        tOverlappedSend.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        if (tOverlappedSend.hEvent == NULL)
        	return 0;

        // Write Bytes
        if(!WriteFile(*m_port, pBytes, nByteCount, &uBytesWritten, &tOverlappedSend))
        {
        	// Reset Bytes
        	uBytesWritten = 0;

        	// Check Pending
        	if(GetLastError() == ERROR_IO_PENDING)
                {
                        // Get Signalled - Wait Indefinately
                        if(!GetOverlappedResult(*m_port, &tOverlappedSend, &uBytesWritten, TRUE))
                        	uBytesWritten = 0;
                }
        }

        // Close Handle
        CloseHandle(tOverlappedSend.hEvent);

        // Return
        return (int)uBytesWritten;
}


Reading Asynchronous - (this function called in a loop in the thread)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
int SerialPort::ReceiveBytesA(char *pBytes, int nReadSize, int &nByteCount)
{
	// Reset Bytes
        nByteCount = 0;

	// Invalid Port
	if(*m_port == INVALID_HANDLE_VALUE)
        	return 0;

        // Check Pending
        unsigned long uBytesRead = 0;
	if(!m_bReceivePending)
        {
        	// Create Event
        	memset(&m_tOverlappedReceive, 0, sizeof(m_tOverlappedReceive));
                m_tOverlappedReceive.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
                if (m_tOverlappedReceive.hEvent == NULL)
                	return 0;

        	// Receive
                if(!ReadFile(*m_port, pBytes, nReadSize, &uBytesRead, &m_tOverlappedReceive))
                {
                	// Validate Pending
                	if(GetLastError() == ERROR_IO_PENDING)
         			m_bReceivePending = true;
                }
                else
                {
                	// Set Bytes
                	nByteCount = (int)uBytesRead;
                }

                // Close Event
                if(!m_bReceivePending)
                {
                	CloseHandle(m_tOverlappedReceive.hEvent);
                        m_tOverlappedReceive.hEvent = NULL;
                }
        }
        else if(HasOverlappedIoCompleted(&m_tOverlappedReceive))
        {
        	// Get Signalled Bytes
                if(GetOverlappedResult(*m_port, &m_tOverlappedReceive, &uBytesRead, FALSE))
                {
                	// Set Bytes
                	nByteCount = (int)uBytesRead;
                }

                // No Longer Pending
                m_bReceivePending = false;

                // Close Event
                CloseHandle(m_tOverlappedReceive.hEvent);
                m_tOverlappedReceive.hEvent = NULL;
        }

        // Success
        return nByteCount;
}
Last edited on
Topic archived. No new replies allowed.