Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device Error #25

Closed
AndreiGorlov opened this issue May 4, 2017 · 13 comments
Closed

Device Error #25

AndreiGorlov opened this issue May 4, 2017 · 13 comments

Comments

@AndreiGorlov
Copy link

Trying to read output from Arduino Uno clone (with CH340 on board):

var arduino = new SerialPortStream("COM6", 9600, 8, Parity.None, StopBits.One);
arduino.DtrEnable = true;

arduino.Open();

while (true)
{
    Console.Write(arduino.ReadExisting());
    System.Threading.Thread.Sleep(1000);
}

ReadExisting() throws:

Unhandled Exception: System.IO.IOException: Device Error
   at RJCP.IO.Ports.SerialPortStream.ReadCheckDeviceError(Boolean immediate) in c:\Users\jcurl\Documents\Programming\HELIOS\serialportstream\code\SerialPortStream.cs:line 629
   at RJCP.IO.Ports.SerialPortStream.ReadExisting() in c:\Users\jcurl\Documents\Programming\HELIOS\serialportstream\code\SerialPortStream.cs:line 931
   at ArduinoReader.Program.Main(String[] args) in C:\Users\Andrei\documents\visual studio 2017\Projects\ArduinoReader\ArduinoReader\Program.cs:line 17

Same code with System.IO.Ports.SerialPort works fine.

Windows 10 x64 1703, .NET 4.6.1

@splitice
Copy link

splitice commented May 5, 2017

I've had a few Device Errors on our hardware too, usually on the first read if at all. Although I found they could be ignored. Have you tried catching it and repeating?

@AndreiGorlov
Copy link
Author

Catching and repeating doesn't work.
ReadExisting() constantly throws exception after third call. First call returns empty string, second call returns null.

@jcurl
Copy link
Owner

jcurl commented May 5, 2017

Sounds like the reading thread died. Can you please provide .net logs?

@AndreiGorlov
Copy link
Author

Debug output with enabled trace:

IO.Ports.SerialPortStream Error: 0 : COM6: SerialThread: DoWaitCommEvent: Result: 87
IO.Ports.SerialPortStream Error: 0 : COM6: SerialThread: Died from Value does not fall within the expected range.
The thread 0x2628 has exited with code 0 (0x0).
Exception thrown: 'System.IO.IOException' in RJCP.SerialPortStream.dll

@jcurl
Copy link
Owner

jcurl commented May 6, 2017

The driver doesn't support the OS Call WaitCommEvent, which is pretty fundamental to the SerialPortStream implementation on Windows (it tells me when flush has occurred, when bytes are available, etc.)

As a fix can only be made with the hardware to test (I have no idea what this driver is doing), would you be willing to make some changes and debug? It will probably take some time before we get to a final solution.

The first would be to comment out the exception in the method DoWaitCommEvent from CommOverlappedIo.cs and see what happens:

        private bool DoWaitCommEvent(out NativeMethods.SerialEventMask mask, ref NativeOverlapped overlap)
        {
            bool result = UnsafeNativeMethods.WaitCommEvent(m_ComPortHandle, out mask, ref overlap);
            if (!result) {
                int w32err = Marshal.GetLastWin32Error();
                int hr = Marshal.GetHRForLastWin32Error();
                if (w32err != WinError.ERROR_IO_PENDING) {
                    SerialTrace.TraceSer.TraceEvent(System.Diagnostics.TraceEventType.Error, 0,
                        "{0}: SerialThread: DoWaitCommEvent: Result: {1}", m_Name, w32err);
                    // Marshal.ThrowExceptionForHR(hr);
                }
            } else {
                ProcessWaitCommEvent(mask);
            }
            return !result;
        }

That will make the main thread think that the result is pending (it will never arrive) effectively disabling it. Getting the EOF, flushing and errors from the driver won't work as expected. But I'm hoping at least the OS call ClearCommError will work. I'll need full logs for your test program to see what the effects are.

@AndreiGorlov
Copy link
Author

After commenting out Marshal.ThrowExceptionForHR(hr) my program began to receive data from the device.
Trace:

IO.Ports.SerialPortStream Error: 0 : COM6: SerialThread: DoWaitCommEvent: Result: 87
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(628, 3007597484464, 1048576) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 7 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: End=0; Bytes=7
IO.Ports.SerialPortStream Verbose: 0 : COM6: CommEvent: EV_RXCHAR
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(628, 3007597484471, 1048569) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: HandleEvent: Chars; NoError; NoChange;
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 0 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(628, 3007597484471, 1048569) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 7 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: End=7; Bytes=7
IO.Ports.SerialPortStream Verbose: 0 : COM6: CommEvent: EV_RXCHAR
IO.Ports.SerialPortStream Verbose: 0 : COM6: HandleEvent: Chars; NoError; NoChange;
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(628, 3007597484478, 1048562) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 0 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(628, 3007597484478, 1048562) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 7 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: End=14; Bytes=7
...

@jcurl
Copy link
Owner

jcurl commented May 7, 2017

This is going to take a little time to get a full solution (I can only work on this in my free time). I would want to build in a detection mechanism for this. Then I need to deactivate or change some behaviour, such as flushing.

I need to analyse the logs. I might have some more tests that add extra logging. I want to check how the GetReceiveStat function works on your hardware.

@AndreiGorlov
Copy link
Author

Ready to help.

@jcurl
Copy link
Owner

jcurl commented May 15, 2017

@splitice you indicated that you sometimes had the Device Error also but it only happened a few times. Do you have any logs for that situation? I've spent a few hours trying to reproduce and analysing code, but I can't see how this can occur. If you can, could you open a new issue?

@safrazik
Copy link

I have the same hardware - Arduino Uno clone (with CH340 on board) and I face the same problem with DataReceived event (the Read thread exited with code 0). When commenting the line Marshal.ThrowExceptionForHR(hr) the code worked

jcurl added a commit that referenced this issue May 21, 2017
Some devices, notably a Arduino Uno clone (with CH340 on board), would return error 87 (ERROR_INVALID_PARAMETER) on a call to WaitCommEvent, but it does work with the GetReceiveStats (Windows API ClearCommError function) to know when data is available to read.

The flush functionality should still work on write, even without the TX_EMPTY event that we'd miss with WaitCommEvent, because we set this every time our internal buffer is empty.

All unit test cases on Windows with the COM-0-COM driver work. Haven't tested with an Arduino board though.

Issue: DOTNET-98, #25
@jcurl
Copy link
Owner

jcurl commented May 21, 2017

I've made a commit to the branch "feature/dotnet-98" if you could please test. It's slightly different. If it's OK, I'll merge and put in the next release.

@AndreiGorlov
Copy link
Author

feature/dotnet-98 works fine with CH340.
Trace, just in case:

IO.Ports.SerialPortStream Error: 0 : COM6: SerialThread: DoWaitCommEvent: Result: 87
IO.Ports.SerialPortStream Warning: 0 : COM6: SerialThread: Not processing WaitCommEvent events
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(648, 2154877655472, 1048576) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 7 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: End=0; Bytes=7
IO.Ports.SerialPortStream Verbose: 0 : COM6: CommEvent: EV_RXCHAR
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(648, 2154877655479, 1048569) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: HandleEvent: Chars; NoError; NoChange;
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 0 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(648, 2154877655479, 1048569) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 7 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: End=7; Bytes=7
IO.Ports.SerialPortStream Verbose: 0 : COM6: CommEvent: EV_RXCHAR
IO.Ports.SerialPortStream Verbose: 0 : COM6: HandleEvent: Chars; NoError; NoChange;
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(648, 2154877655486, 1048562) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 0 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: DoReadEvent: ReadFile(648, 2154877655486, 1048562) == False
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: 7 bytes
IO.Ports.SerialPortStream Verbose: 0 : COM6: SerialThread: ProcessReadEvent: End=14; Bytes=7

jcurl added a commit that referenced this issue May 22, 2017
Some devices, notably a Arduino Uno clone (with CH340 on board), would return error 87 (ERROR_INVALID_PARAMETER) on a call to WaitCommEvent, but it does work with the GetReceiveStats (Windows API ClearCommError function) to know when data is available to read.

The flush functionality should still work on write, even without the TX_EMPTY event that we'd miss with WaitCommEvent, because we set this every time our internal buffer is empty.

All unit test cases on Windows with the COM-0-COM driver work. Testing on the Arduino CH340 borad done by GitHub user AndreiGorlov.

Issue: DOTNET-98, #25
@jcurl
Copy link
Owner

jcurl commented May 22, 2017

Merged on master

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants