1
0
mirror of https://github.com/DarthAffe/OBD.NET.git synced 2025-12-13 01:08:30 +00:00
Roman Lumetsberger f9b25b4965 changed common to NetStandard-1.4
added desktop implementation of serial port (needs full Framework)
2017-05-07 09:30:05 +02:00

164 lines
4.9 KiB
C#

// Copyright 2013 Antanas Veiverys www.veiverys.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.ComponentModel;
using System.IO;
using System.IO.Ports;
using System.Reflection;
using System.Runtime.InteropServices;
// Source: http://antanas.veiverys.com/mono-serialport-datareceived-event-workaround-using-a-derived-class/
namespace OBD.NET.Communication
{
[DesignerCategory("Code")]
public class EnhancedSerialPort : SerialPort
{
#region Properties & Fields
// private member access via reflection
private int _fd;
private FieldInfo _disposedFieldInfo;
private object _dataReceived;
#endregion
#region DLLImports
[DllImport("MonoPosixHelper", SetLastError = true)]
private static extern bool poll_serial(int fd, out int error, int timeout);
[DllImport("libc")]
private static extern IntPtr strerror(int errnum);
#endregion
#region Constructors
public EnhancedSerialPort()
: base()
{ }
public EnhancedSerialPort(IContainer container)
: base(container)
{ }
public EnhancedSerialPort(string portName)
: base(portName)
{ }
public EnhancedSerialPort(string portName, int baudRate)
: base(portName, baudRate)
{ }
public EnhancedSerialPort(string portName, int baudRate, Parity parity)
: base(portName, baudRate, parity)
{ }
public EnhancedSerialPort(string portName, int baudRate, Parity parity, int dataBits)
: base(portName, baudRate, parity, dataBits)
{ }
public EnhancedSerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
: base(portName, baudRate, parity, dataBits, stopBits)
{ }
#endregion
#region Methods
public new void Open()
{
base.Open();
if (!IsWindows)
{
FieldInfo fieldInfo = BaseStream.GetType().GetField("fd", BindingFlags.Instance | BindingFlags.NonPublic);
_fd = (int)fieldInfo.GetValue(BaseStream);
_disposedFieldInfo = BaseStream.GetType().GetField("disposed", BindingFlags.Instance | BindingFlags.NonPublic);
fieldInfo = typeof(SerialPort).GetField("data_received", BindingFlags.Instance | BindingFlags.NonPublic);
_dataReceived = fieldInfo.GetValue(this);
new System.Threading.Thread(EventThreadFunction).Start();
}
}
private static bool IsWindows
{
get
{
PlatformID id = Environment.OSVersion.Platform;
return (id == PlatformID.Win32Windows) || (id == PlatformID.Win32NT); // WinCE not supported
}
}
private void EventThreadFunction()
{
do
{
try
{
Stream stream = BaseStream;
if (stream == null)
return;
if (Poll(stream, ReadTimeout))
OnDataReceived(null);
}
catch
{
return;
}
} while (IsOpen);
}
private void OnDataReceived(SerialDataReceivedEventArgs args)
{
SerialDataReceivedEventHandler handler = Events[_dataReceived] as SerialDataReceivedEventHandler;
handler?.Invoke(this, args);
}
private bool Poll(Stream stream, int timeout)
{
CheckDisposed(stream);
if (IsOpen == false)
throw new Exception("port is closed");
int error;
bool pollResult = poll_serial(_fd, out error, ReadTimeout);
if (error == -1)
ThrowIOException();
return pollResult;
}
private static void ThrowIOException()
{
int errnum = Marshal.GetLastWin32Error();
string errorMessage = Marshal.PtrToStringAnsi(strerror(errnum));
throw new IOException(errorMessage);
}
private void CheckDisposed(Stream stream)
{
bool disposed = (bool)_disposedFieldInfo.GetValue(stream);
if (disposed)
throw new ObjectDisposedException(stream.GetType().FullName);
}
#endregion
}
}