Sinatr
Sinatr

Reputation: 21999

SerialPort check CTS

How to check CTS line value of opened SerialPort? Idea is to set this value from device on other side while using 3-wire serial interface without handshaking.

Here is some code to start discussion (adapted msdn example):

[DllImport("kernel32.dll")]
static extern bool SetCommMask(IntPtr hFile, uint dwEvtMask);
[DllImport("kernel32.dll")]
static extern bool WaitCommEvent(IntPtr hFile, out uint lpEvtMask, IntPtr lpOverlapped);

SerialPort _port = null;
bool _exit;

public Form1()
{
    InitializeComponent();

    _port = new SerialPort("COM2");
    _port.Open();

    // getting handle is tricky
    var handle = ((SafeFileHandle)_port.BaseStream.GetType().GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(_port.BaseStream)).DangerousGetHandle();

    // set mask to listen to change of CTS signal
    if (!SetCommMask(handle, 0x0008)) // EV_CTS
        throw ...

    // start listener
    Task.Run(() =>
    {
        while (!_exit)
        {
            uint mask = 0;
            if (WaitCommEvent(handle, out mask, IntPtr.Zero))
                if ((mask & 0x0008) != 0)
                    Task.Run(() => MessageBox.Show("smth happenz"));
        });
        _port.Close();
    }
}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    _exit = true;
}

This code can tell me if there is a change of signal on CTS line, but can't figure out how to get actual value (is it high or low?).

Apart from that there are strange issues. WaitCommEvent returns false immediately (with Marshal.GetLastError() = 0) unless CTS is set to opposite to what it was when com-port was opened. Moreover, I see MessageBox for values which are equal to what it was when com-port was opened. This is really weird, because I can't figure out a value by using this approach.

Another thing is what WaitCommEvent blocks. I can close form and application terminates without visible (yet?) issues, but I'd really enjoy having non-blocking polling here.

Upvotes: 0

Views: 1934

Answers (2)

Mike Nakis
Mike Nakis

Reputation: 61993

A 3-wire serial interface does not include the CTS signal, so you cannot use it.

As for reading the value of CTS, the documentation is here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363194%28v=vs.85%29.aspx you want to look at GetCommMask() and GetCommModemStatus().

Upvotes: 3

ElderBug
ElderBug

Reputation: 6145

You need to use GetCommModemStatus to retrieve status of CTS.

You can use WaitCommEvent in non-blocking mode with overlapped IO. That is, opening the port as overlapped and providing the 3rd parameter of WaitCommEvent.

Upvotes: 2

Related Questions