commit 849cb8865a9fa7f36a1fb6c86e2fed901fd3f539 Author: Ebrahim Byagowi Date: Sat Mar 3 13:20:54 2012 +0330 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..b7005a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ + +#ignore thumbnails created by windows +Thumbs.db +#Ignore files build by Visual Studio +*.obj +*.exe +*.pdb +*.user +*.aps +*.pch +*.vspscc +*_i.c +*_p.c +*.ncb +*.suo +*.tlb +*.tlh +*.bak +*.cache +*.ilk +*.log +[Bb]in +[Dd]ebug*/ +*.lib +*.sbr +obj/ +[Rr]elease*/ +_ReSharper*/ +[Tt]est[Rr]esult* +*.testsettings \ No newline at end of file diff --git a/PInvokeSerialPort.Sample/PInvokeSerialPort.Sample.csproj b/PInvokeSerialPort.Sample/PInvokeSerialPort.Sample.csproj new file mode 100755 index 0000000..60b2cbb --- /dev/null +++ b/PInvokeSerialPort.Sample/PInvokeSerialPort.Sample.csproj @@ -0,0 +1,63 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {76FAB402-7515-4A9B-8605-4FEC0736C78A} + Exe + Properties + PInvokeSerialPort.Sample + PInvokeSerialPort.Sample + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A} + PInvokeSerialPort + + + + + \ No newline at end of file diff --git a/PInvokeSerialPort.Sample/Program.cs b/PInvokeSerialPort.Sample/Program.cs new file mode 100755 index 0000000..926e95c --- /dev/null +++ b/PInvokeSerialPort.Sample/Program.cs @@ -0,0 +1,19 @@ +using System; +using PInvokeSerialPort; + +namespace PInvokeSerialPort.Sample +{ + class Program + { + static void Main(string[] args) + { + var serialPort = new SerialPort("com1", 14400); + serialPort.DataReceived += x => Console.Write((char)x); + serialPort.Open(); + while (true) + { + serialPort.Write(Console.ReadKey().KeyChar); + } + } + } +} diff --git a/PInvokeSerialPort.Sample/Properties/AssemblyInfo.cs b/PInvokeSerialPort.Sample/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..6d4480c --- /dev/null +++ b/PInvokeSerialPort.Sample/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PInvokeSerialPort.Sample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PInvokeSerialPort.Sample")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9628528d-5e4d-4071-aad1-b1f85f3d45d5")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PInvokeSerialPort.Test/PInvokeSerialPort.Test.csproj b/PInvokeSerialPort.Test/PInvokeSerialPort.Test.csproj new file mode 100755 index 0000000..3d51eb7 --- /dev/null +++ b/PInvokeSerialPort.Test/PInvokeSerialPort.Test.csproj @@ -0,0 +1,66 @@ + + + + Debug + AnyCPU + + + 2.0 + {928609B4-70AB-4D93-A43E-4BE75C279066} + Library + Properties + PInvokeSerialPort.Test + PInvokeSerialPort.Test + v4.0 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + 3.5 + + + + + False + + + + + + + + + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A} + PInvokeSerialPort + + + + + \ No newline at end of file diff --git a/PInvokeSerialPort.Test/PInvokeSerialPortTest.cs b/PInvokeSerialPort.Test/PInvokeSerialPortTest.cs new file mode 100755 index 0000000..e1553f5 --- /dev/null +++ b/PInvokeSerialPort.Test/PInvokeSerialPortTest.cs @@ -0,0 +1,84 @@ +using System; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading; + +namespace PInvokeSerialPort.Test +{ + /// + /// Test class. + /// Attention: Run it just in test debug. + /// + [TestClass] + public class PInvokeSerialPortTest + { + dynamic _sender; + dynamic _reciever; + StringBuilder _stringBuilder; + + public void OpenWriteDoWaitClose(Action action) + { + const string testSting = "test"; + _stringBuilder = new StringBuilder(); + _sender.Open(); + _reciever.Open(); + + action(); + + _sender.Write(testSting); + Thread.Sleep(100); + Assert.AreEqual(testSting, _stringBuilder.ToString()); + + _sender.Close(); + _reciever.Close(); + } + + [TestMethod] + public void OverallTest1() + { + _sender = new SerialPort("com1"); + _reciever = new SerialPort("com2"); + OpenWriteDoWaitClose(() => + { + ((SerialPort)_reciever).DataReceived += x => _stringBuilder.Append((char)x); + }); + } + + [TestMethod] + public void OverallTest2() + { + _sender = new System.IO.Ports.SerialPort("com1"); + + _reciever = new SerialPort("com2"); + + OpenWriteDoWaitClose(() => + { + ((SerialPort)(object)_reciever).DataReceived += x => _stringBuilder.Append((char)x); + }); + } + + [TestMethod] + public void OverallTest3() + { + _sender = new SerialPort("com1"); + _reciever = new System.IO.Ports.SerialPort("com2"); + + OpenWriteDoWaitClose(() => + { + ((System.IO.Ports.SerialPort)_reciever).DataReceived += (x, y) => _stringBuilder.Append(_reciever.ReadExisting()); + }); + } + + [TestMethod] + public void OverallTest4() // this is not really a PInvokeSerialTest :D + { + _sender = new System.IO.Ports.SerialPort("com1"); + _reciever = new System.IO.Ports.SerialPort("com2"); + + OpenWriteDoWaitClose(() => + { + ((System.IO.Ports.SerialPort)_reciever).DataReceived += (x, y) => _stringBuilder.Append(_reciever.ReadExisting()); + }); + } + } +} diff --git a/PInvokeSerialPort.Test/Properties/AssemblyInfo.cs b/PInvokeSerialPort.Test/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..d678fa3 --- /dev/null +++ b/PInvokeSerialPort.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PInvokeSerialPort.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PInvokeSerialPort.Test")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7e55b1ff-e888-4433-ab65-c9b32bb8125f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PInvokeSerialPort.sln b/PInvokeSerialPort.sln new file mode 100755 index 0000000..91ecd9a --- /dev/null +++ b/PInvokeSerialPort.sln @@ -0,0 +1,64 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PInvokeSerialPort", "PInvokeSerialPort\PInvokeSerialPort.csproj", "{AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{99052083-B245-462F-8778-4C94662ABABE}" + ProjectSection(SolutionItems) = preProject + Local.testsettings = Local.testsettings + PInvokeSerialPort.vsmdi = PInvokeSerialPort.vsmdi + TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PInvokeSerialPort.Test", "PInvokeSerialPort.Test\PInvokeSerialPort.Test.csproj", "{928609B4-70AB-4D93-A43E-4BE75C279066}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PInvokeSerialPort.Sample", "PInvokeSerialPort.Sample\PInvokeSerialPort.Sample.csproj", "{76FAB402-7515-4A9B-8605-4FEC0736C78A}" +EndProject +Global + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = PInvokeSerialPort.vsmdi + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Debug|Any CPU.ActiveCfg = Debug|x86 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Debug|x86.ActiveCfg = Debug|x86 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Debug|x86.Build.0 = Debug|x86 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Release|Any CPU.ActiveCfg = Release|x86 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Release|Mixed Platforms.Build.0 = Release|x86 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Release|x86.ActiveCfg = Release|x86 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A}.Release|x86.Build.0 = Release|x86 + {928609B4-70AB-4D93-A43E-4BE75C279066}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {928609B4-70AB-4D93-A43E-4BE75C279066}.Debug|Any CPU.Build.0 = Debug|Any CPU + {928609B4-70AB-4D93-A43E-4BE75C279066}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {928609B4-70AB-4D93-A43E-4BE75C279066}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {928609B4-70AB-4D93-A43E-4BE75C279066}.Debug|x86.ActiveCfg = Debug|Any CPU + {928609B4-70AB-4D93-A43E-4BE75C279066}.Release|Any CPU.ActiveCfg = Release|Any CPU + {928609B4-70AB-4D93-A43E-4BE75C279066}.Release|Any CPU.Build.0 = Release|Any CPU + {928609B4-70AB-4D93-A43E-4BE75C279066}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {928609B4-70AB-4D93-A43E-4BE75C279066}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {928609B4-70AB-4D93-A43E-4BE75C279066}.Release|x86.ActiveCfg = Release|Any CPU + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Debug|Any CPU.ActiveCfg = Debug|x86 + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Debug|Mixed Platforms.Build.0 = Debug|x86 + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Debug|x86.ActiveCfg = Debug|x86 + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Debug|x86.Build.0 = Debug|x86 + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Release|Any CPU.ActiveCfg = Release|x86 + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Release|Mixed Platforms.ActiveCfg = Release|x86 + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Release|Mixed Platforms.Build.0 = Release|x86 + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Release|x86.ActiveCfg = Release|x86 + {76FAB402-7515-4A9B-8605-4FEC0736C78A}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/PInvokeSerialPort.vsmdi b/PInvokeSerialPort.vsmdi new file mode 100755 index 0000000..64e42ad --- /dev/null +++ b/PInvokeSerialPort.vsmdi @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/PInvokeSerialPort/ASCII.cs b/PInvokeSerialPort/ASCII.cs new file mode 100755 index 0000000..102eb98 --- /dev/null +++ b/PInvokeSerialPort/ASCII.cs @@ -0,0 +1,13 @@ +namespace PInvokeSerialPort +{ + /// + /// Byte type with enumeration constants for ASCII control codes. + /// + public enum ASCII : byte + { + NULL = 0x00, SOH = 0x01, STH = 0x02, ETX = 0x03, EOT = 0x04, ENQ = 0x05, ACK = 0x06, BELL = 0x07, + BS = 0x08, HT = 0x09, LF = 0x0A, VT = 0x0B, FF = 0x0C, CR = 0x0D, SO = 0x0E, SI = 0x0F, DC1 = 0x11, + DC2 = 0x12, DC3 = 0x13, DC4 = 0x14, NAK = 0x15, SYN = 0x16, ETB = 0x17, CAN = 0x18, EM = 0x19, + SUB = 0x1A, ESC = 0x1B, FS = 0x1C, GS = 0x1D, RS = 0x1E, US = 0x1F, SP = 0x20, DEL = 0x7F + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/CommPortException.cs b/PInvokeSerialPort/CommPortException.cs new file mode 100755 index 0000000..b916f0c --- /dev/null +++ b/PInvokeSerialPort/CommPortException.cs @@ -0,0 +1,22 @@ +using System; + +namespace PInvokeSerialPort +{ + /// + /// Exception used for all errors. + /// + public class CommPortException : ApplicationException + { + /// + /// Constructor for raising direct exceptions + /// + /// Description of error + public CommPortException(string desc) : base(desc) { } + + /// + /// Constructor for re-raising exceptions from receive thread + /// + /// Inner exception raised on receive thread + public CommPortException(Exception e) : base("Receive Thread Exception", e) { } + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/Handshake.cs b/PInvokeSerialPort/Handshake.cs new file mode 100755 index 0000000..6d76eac --- /dev/null +++ b/PInvokeSerialPort/Handshake.cs @@ -0,0 +1,25 @@ +namespace PInvokeSerialPort +{ + /// + /// Standard handshake methods + /// + public enum Handshake + { + /// + /// No handshaking + /// + None, + /// + /// Software handshaking using Xon / Xoff + /// + XonXoff, + /// + /// Hardware handshaking using CTS / RTS + /// + CtsRts, + /// + /// Hardware handshaking using DSR / DTR + /// + DsrDtr + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/HsOutput.cs b/PInvokeSerialPort/HsOutput.cs new file mode 100755 index 0000000..3d2e742 --- /dev/null +++ b/PInvokeSerialPort/HsOutput.cs @@ -0,0 +1,25 @@ +namespace PInvokeSerialPort +{ + /// + /// Uses for RTS or DTR pins + /// + public enum HsOutput + { + /// + /// Pin is asserted when this station is able to receive data. + /// + Handshake = 2, + /// + /// Pin is asserted when this station is transmitting data (RTS on NT, 2000 or XP only). + /// + Gate = 3, + /// + /// Pin is asserted when this station is online (port is open). + /// + Online = 1, + /// + /// Pin is never asserted. + /// + None = 0 + }; +} \ No newline at end of file diff --git a/PInvokeSerialPort/ModemStatus.cs b/PInvokeSerialPort/ModemStatus.cs new file mode 100755 index 0000000..0daf900 --- /dev/null +++ b/PInvokeSerialPort/ModemStatus.cs @@ -0,0 +1,29 @@ +using PInvokeSerialPort.Win32PInvoke; + +namespace PInvokeSerialPort +{ + /// + /// Represents the status of the modem control input signals. + /// + public struct ModemStatus + { + private readonly uint _status; + internal ModemStatus(uint val) { _status = val; } + /// + /// Condition of the Clear To Send signal. + /// + public bool Cts { get { return ((_status & Win32Com.MS_CTS_ON) != 0); } } + /// + /// Condition of the Data Set Ready signal. + /// + public bool Dsr { get { return ((_status & Win32Com.MS_DSR_ON) != 0); } } + /// + /// Condition of the Receive Line Status Detection signal. + /// + public bool Rlsd { get { return ((_status & Win32Com.MS_RLSD_ON) != 0); } } + /// + /// Condition of the Ring Detection signal. + /// + public bool Ring { get { return ((_status & Win32Com.MS_RING_ON) != 0); } } + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/PInvokeSerialPort.csproj b/PInvokeSerialPort/PInvokeSerialPort.csproj new file mode 100755 index 0000000..5b5b76d --- /dev/null +++ b/PInvokeSerialPort/PInvokeSerialPort.csproj @@ -0,0 +1,74 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {AEC711A5-AA9B-4127-A82C-C4D8FDA9741A} + Library + Properties + PInvokeSerialPort + PInvokeSerialPort + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/PInvokeSerialPort/Parity.cs b/PInvokeSerialPort/Parity.cs new file mode 100755 index 0000000..9889b7c --- /dev/null +++ b/PInvokeSerialPort/Parity.cs @@ -0,0 +1,29 @@ +namespace PInvokeSerialPort +{ + /// + /// Parity settings + /// + public enum Parity + { + /// + /// Characters do not have a parity bit. + /// + None = 0, + /// + /// If there are an odd number of 1s in the data bits, the parity bit is 1. + /// + Odd = 1, + /// + /// If there are an even number of 1s in the data bits, the parity bit is 1. + /// + Even = 2, + /// + /// The parity bit is always 1. + /// + Mark = 3, + /// + /// The parity bit is always 0. + /// + Space = 4 + }; +} \ No newline at end of file diff --git a/PInvokeSerialPort/Properties/AssemblyInfo.cs b/PInvokeSerialPort/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..e73f91b --- /dev/null +++ b/PInvokeSerialPort/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PInvokeSerialPort")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PInvokeSerialPort")] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a9b6ec41-2cde-4cdb-bd80-3dc730bcd820")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/PInvokeSerialPort/QueueStatus.cs b/PInvokeSerialPort/QueueStatus.cs new file mode 100755 index 0000000..c9c8aa3 --- /dev/null +++ b/PInvokeSerialPort/QueueStatus.cs @@ -0,0 +1,134 @@ +using System.Text; +using PInvokeSerialPort.Win32PInvoke; + +namespace PInvokeSerialPort +{ + /// + /// Represents the current condition of the port queues. + /// + public struct QueueStatus + { + private uint status; + private uint inQueue; + private uint outQueue; + private uint inQueueSize; + private uint outQueueSize; + + internal QueueStatus(uint stat, uint inQ, uint outQ, uint inQs, uint outQs) + { status = stat; inQueue = inQ; outQueue = outQ; inQueueSize = inQs; outQueueSize = outQs; } + /// + /// Output is blocked by CTS handshaking. + /// + public bool ctsHold { get { return ((status & COMSTAT.fCtsHold) != 0); } } + /// + /// Output is blocked by DRS handshaking. + /// + public bool dsrHold { get { return ((status & COMSTAT.fDsrHold) != 0); } } + /// + /// Output is blocked by RLSD handshaking. + /// + public bool rlsdHold { get { return ((status & COMSTAT.fRlsdHold) != 0); } } + /// + /// Output is blocked because software handshaking is enabled and XOFF was received. + /// + public bool xoffHold { get { return ((status & COMSTAT.fXoffHold) != 0); } } + /// + /// Output was blocked because XOFF was sent and this station is not yet ready to receive. + /// + public bool xoffSent { get { return ((status & COMSTAT.fXoffSent) != 0); } } + + /// + /// There is a character waiting for transmission in the immediate buffer. + /// + public bool immediateWaiting { get { return ((status & COMSTAT.fTxim) != 0); } } + + /// + /// Number of bytes waiting in the input queue. + /// + public long InQueue { get { return inQueue; } } + /// + /// Number of bytes waiting for transmission. + /// + public long OutQueue { get { return outQueue; } } + /// + /// Total size of input queue (0 means information unavailable) + /// + public long InQueueSize { get { return inQueueSize; } } + /// + /// Total size of output queue (0 means information unavailable) + /// + public long OutQueueSize { get { return outQueueSize; } } + + public override string ToString() + { + var m = new StringBuilder("The reception queue is ", 60); + if (inQueueSize == 0) + { + m.Append("of unknown size and "); + } + else + { + m.Append(inQueueSize.ToString() + " bytes long and "); + } + if (inQueue == 0) + { + m.Append("is empty."); + } + else if (inQueue == 1) + { + m.Append("contains 1 byte."); + } + else + { + m.Append("contains "); + m.Append(inQueue.ToString()); + m.Append(" bytes."); + } + m.Append(" The transmission queue is "); + if (outQueueSize == 0) + { + m.Append("of unknown size and "); + } + else + { + m.Append(outQueueSize.ToString() + " bytes long and "); + } + if (outQueue == 0) + { + m.Append("is empty"); + } + else if (outQueue == 1) + { + m.Append("contains 1 byte. It is "); + } + else + { + m.Append("contains "); + m.Append(outQueue.ToString()); + m.Append(" bytes. It is "); + } + if (outQueue > 0) + { + if (ctsHold || dsrHold || rlsdHold || xoffHold || xoffSent) + { + m.Append("holding on"); + if (ctsHold) m.Append(" CTS"); + if (dsrHold) m.Append(" DSR"); + if (rlsdHold) m.Append(" RLSD"); + if (xoffHold) m.Append(" Rx XOff"); + if (xoffSent) m.Append(" Tx XOff"); + } + else + { + m.Append("pumping data"); + } + } + m.Append(". The immediate buffer is "); + if (immediateWaiting) + m.Append("full."); + else + m.Append("empty."); + return m.ToString(); + } + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/SerialPort.cs b/PInvokeSerialPort/SerialPort.cs new file mode 100755 index 0000000..c9d1021 --- /dev/null +++ b/PInvokeSerialPort/SerialPort.cs @@ -0,0 +1,740 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using PInvokeSerialPort.Win32PInvoke; + +namespace PInvokeSerialPort +{ + /// + /// PInvokeSerialPort main class. + /// Borrowed from http://msdn.microsoft.com/en-us/magazine/cc301786.aspx ;) + /// + public class SerialPort : IDisposable + { + private IntPtr _hPort; + private IntPtr _ptrUwo = IntPtr.Zero; + private Thread _rxThread; + private bool _online; + private bool _auto; + private bool _checkSends = true; + private Exception _rxException; + private bool _rxExceptionReported; + private int _writeCount; + private readonly ManualResetEvent _writeEvent = new ManualResetEvent(false); + private int _stateRts = 2; + private int _stateDtr = 2; + private int _stateBrk = 2; + + /// + /// Class contructor + /// + public SerialPort(string portName) + { + PortName = portName; + } + + /// + /// Class contructor + /// + public SerialPort(string portName, int baudRate) + { + PortName = portName; + BaudRate = baudRate; + } + + /// + /// Opens the com port and configures it with the required settings + /// + /// false if the port could not be opened + public bool Open() + { + var portDcb = new DCB(); + var commTimeouts = new COMMTIMEOUTS(); + var wo = new OVERLAPPED(); + + if (_online) return false; + + _hPort = Win32Com.CreateFile(PortName, Win32Com.GENERIC_READ | Win32Com.GENERIC_WRITE, 0, IntPtr.Zero, + Win32Com.OPEN_EXISTING, Win32Com.FILE_FLAG_OVERLAPPED, IntPtr.Zero); + if (_hPort == (IntPtr)Win32Com.INVALID_HANDLE_VALUE) + { + if (Marshal.GetLastWin32Error() == Win32Com.ERROR_ACCESS_DENIED) + { + return false; + } + throw new CommPortException("Port Open Failure"); + } + + _online = true; + + commTimeouts.ReadIntervalTimeout = 0; + commTimeouts.ReadTotalTimeoutConstant = 0; + commTimeouts.ReadTotalTimeoutMultiplier = 0; + commTimeouts.WriteTotalTimeoutConstant = SendTimeoutConstant; + commTimeouts.WriteTotalTimeoutMultiplier = SendTimeoutMultiplier; + portDcb.Init(((Parity == Parity.Odd) || (Parity == Parity.Even)), TxFlowCts, TxFlowDsr, + (int)UseDtr, RxGateDsr, !TxWhenRxXoff, TxFlowX, RxFlowX, (int)UseRts); + portDcb.BaudRate = BaudRate; + portDcb.ByteSize = (byte)DataBits; + portDcb.Parity = (byte)Parity; + portDcb.StopBits = (byte)StopBits; + portDcb.XoffChar = (byte)XoffChar; + portDcb.XonChar = (byte)XonChar; + portDcb.XoffLim = (short)RxHighWater; + portDcb.XonLim = (short)RxLowWater; + if ((RxQueue != 0) || (TxQueue != 0)) + if (!Win32Com.SetupComm(_hPort, (uint)RxQueue, (uint)TxQueue)) ThrowException("Bad queue settings"); + if (!Win32Com.SetCommState(_hPort, ref portDcb)) ThrowException("Bad com settings"); + if (!Win32Com.SetCommTimeouts(_hPort, ref commTimeouts)) ThrowException("Bad timeout settings"); + + _stateBrk = 0; + if (UseDtr == HsOutput.None) _stateDtr = 0; + if (UseDtr == HsOutput.Online) _stateDtr = 1; + if (UseRts == HsOutput.None) _stateRts = 0; + if (UseRts == HsOutput.Online) _stateRts = 1; + + _checkSends = CheckAllSends; + wo.Offset = 0; + wo.OffsetHigh = 0; + wo.hEvent = _checkSends ? _writeEvent.Handle : IntPtr.Zero; + _ptrUwo = Marshal.AllocHGlobal(Marshal.SizeOf(wo)); + Marshal.StructureToPtr(wo, _ptrUwo, true); + _writeCount = 0; + + _rxException = null; + _rxExceptionReported = false; + _rxThread = new Thread(ReceiveThread) + { + Name = "CommBaseRx", + Priority = ThreadPriority.AboveNormal + }; + _rxThread.Start(); + Thread.Sleep(1); //Give rx thread time to start. By documentation, 0 should work, but it does not! + + _auto = false; + if (AfterOpen()) + { + _auto = AutoReopen; + return true; + } + Close(); + return false; + } + + /// + /// Closes the com port. + /// + public void Close() + { + if (_online) + { + _auto = false; + BeforeClose(false); + InternalClose(); + _rxException = null; + } + } + + private void InternalClose() + { + Win32Com.CancelIo(_hPort); + if (_rxThread != null) + { + _rxThread.Abort(); + _rxThread = null; + } + Win32Com.CloseHandle(_hPort); + if (_ptrUwo != IntPtr.Zero) Marshal.FreeHGlobal(_ptrUwo); + _stateRts = 2; + _stateDtr = 2; + _stateBrk = 2; + _online = false; + } + + /// + /// For IDisposable + /// + public void Dispose() { Close(); } + + /// + /// Destructor (just in case) + /// + ~SerialPort() { Close(); } + + /// + /// True if online. + /// + public bool Online { get { return _online && CheckOnline(); } } + + /// + /// Block until all bytes in the queue have been transmitted. + /// + public void Flush() + { + CheckOnline(); + CheckResult(); + } + + /// + /// Use this to throw exceptions in derived classes. Correctly handles threading issues + /// and closes the port if necessary. + /// + /// Description of fault + protected void ThrowException(string reason) + { + if (Thread.CurrentThread == _rxThread) + { + throw new CommPortException(reason); + } + if (_online) + { + BeforeClose(true); + InternalClose(); + } + if (_rxException == null) + { + throw new CommPortException(reason); + } + throw new CommPortException(_rxException); + } + + /// + /// Queues bytes for transmission. + /// + /// Array of bytes to be sent + public void Write(byte[] toSend) + { + uint sent; + CheckOnline(); + CheckResult(); + _writeCount = toSend.GetLength(0); + if (Win32Com.WriteFile(_hPort, toSend, (uint)_writeCount, out sent, _ptrUwo)) + { + _writeCount -= (int)sent; + } + else + { + if (Marshal.GetLastWin32Error() != Win32Com.ERROR_IO_PENDING) ThrowException("Unexpected failure"); + } + } + + /// + /// Queues string for transmission. + /// + /// Array of bytes to be sent + public void Write(string toSend) + { + Write(new ASCIIEncoding().GetBytes(toSend)); + } + + /// + /// Queues a single byte for transmission. + /// + /// Byte to be sent + public void Write(byte toSend) + { + var b = new byte[1]; + b[0] = toSend; + Write(b); + } + + /// + /// Queues a single char for transmission. + /// + /// Byte to be sent + public void Write(char toSend) + { + Write(toSend.ToString()); + } + + /// + /// Queues string with a new line ("\r\n") for transmission. + /// + /// Array of bytes to be sent + public void WriteLine(string toSend) + { + Write(new ASCIIEncoding().GetBytes(toSend + Environment.NewLine)); + } + + private void CheckResult() + { + if (_writeCount <= 0) return; + uint sent; + if (Win32Com.GetOverlappedResult(_hPort, _ptrUwo, out sent, _checkSends)) + { + _writeCount -= (int)sent; + if (_writeCount != 0) ThrowException("Send Timeout"); + } + else + { + if (Marshal.GetLastWin32Error() != Win32Com.ERROR_IO_PENDING) ThrowException("Unexpected failure"); + } + } + + /// + /// Sends a protocol byte immediately ahead of any queued bytes. + /// + /// Byte to send + /// False if an immediate byte is already scheduled and not yet sent + public void SendImmediate(byte tosend) + { + CheckOnline(); + if (!Win32Com.TransmitCommChar(_hPort, tosend)) ThrowException("Transmission failure"); + } + + /// + /// Delay processing. + /// + /// Milliseconds to delay by + protected void Sleep(int milliseconds) + { + Thread.Sleep(milliseconds); + } + + /// + /// Gets the status of the modem control input signals. + /// + /// Modem status object + protected ModemStatus GetModemStatus() + { + uint f; + + CheckOnline(); + if (!Win32Com.GetCommModemStatus(_hPort, out f)) ThrowException("Unexpected failure"); + return new ModemStatus(f); + } + + + /// + /// Get the status of the queues + /// + /// Queue status object + protected QueueStatus GetQueueStatus() + { + COMSTAT cs; + COMMPROP cp; + uint er; + + CheckOnline(); + if (!Win32Com.ClearCommError(_hPort, out er, out cs)) ThrowException("Unexpected failure"); + if (!Win32Com.GetCommProperties(_hPort, out cp)) ThrowException("Unexpected failure"); + return new QueueStatus(cs.Flags, cs.cbInQue, cs.cbOutQue, cp.dwCurrentRxQueue, cp.dwCurrentTxQueue); + } + + /// + /// True if the RTS pin is controllable via the RTS property + /// + protected bool RtSavailable { get { return (_stateRts < 2); } } + + /// + /// Set the state of the RTS modem control output + /// + protected bool Rts + { + set + { + if (_stateRts > 1) return; + CheckOnline(); + if (value) + { + if (Win32Com.EscapeCommFunction(_hPort, Win32Com.SETRTS)) + _stateRts = 1; + else + ThrowException("Unexpected Failure"); + } + else + { + if (Win32Com.EscapeCommFunction(_hPort, Win32Com.CLRRTS)) + _stateRts = 1; + else + ThrowException("Unexpected Failure"); + } + } + get + { + return (_stateRts == 1); + } + } + + /// + /// True if the DTR pin is controllable via the DTR property + /// + protected bool DtrAvailable { get { return (_stateDtr < 2); } } + + /// + /// The state of the DTR modem control output + /// + protected bool Dtr + { + set + { + if (_stateDtr > 1) return; + CheckOnline(); + if (value) + { + if (Win32Com.EscapeCommFunction(_hPort, Win32Com.SETDTR)) + _stateDtr = 1; + else + ThrowException("Unexpected Failure"); + } + else + { + if (Win32Com.EscapeCommFunction(_hPort, Win32Com.CLRDTR)) + _stateDtr = 0; + else + ThrowException("Unexpected Failure"); + } + } + get + { + return (_stateDtr == 1); + } + } + + /// + /// Assert or remove a break condition from the transmission line + /// + protected bool Break + { + set + { + if (_stateBrk > 1) return; + CheckOnline(); + if (value) + { + if (Win32Com.EscapeCommFunction(_hPort, Win32Com.SETBREAK)) + _stateBrk = 0; + else + ThrowException("Unexpected Failure"); + } + else + { + if (Win32Com.EscapeCommFunction(_hPort, Win32Com.CLRBREAK)) + _stateBrk = 0; + else + ThrowException("Unexpected Failure"); + } + } + get + { + return (_stateBrk == 1); + } + } + + /// + /// Override this to provide processing after the port is openned (i.e. to configure remote + /// device or just check presence). + /// + /// false to close the port again + protected virtual bool AfterOpen() { return true; } + + /// + /// Override this to provide processing prior to port closure. + /// + /// True if closing due to an error + protected virtual void BeforeClose(bool error) { } + + public event Action DataReceived; + /// + /// Override this to process received bytes. + /// + /// The byte that was received + protected void OnRxChar(byte ch) + { + if (DataReceived != null) + DataReceived(ch); + } + + /// + /// Override this to take action when transmission is complete (i.e. all bytes have actually + /// been sent, not just queued). + /// + protected virtual void OnTxDone() { } + + /// + /// Override this to take action when a break condition is detected on the input line. + /// + protected virtual void OnBreak() { } + + /// + /// Override this to take action when a ring condition is signalled by an attached modem. + /// + protected virtual void OnRing() { } + + /// + /// Override this to take action when one or more modem status inputs change state + /// + /// The status inputs that have changed state + /// The state of the status inputs + protected virtual void OnStatusChange(ModemStatus mask, ModemStatus state) { } + + /// + /// Override this to take action when the reception thread closes due to an exception being thrown. + /// + /// The exception which was thrown + protected virtual void OnRxException(Exception e) { } + + private void ReceiveThread() + { + var buf = new Byte[1]; + + var sg = new AutoResetEvent(false); + var ov = new OVERLAPPED(); + var unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov)); + ov.Offset = 0; ov.OffsetHigh = 0; + ov.hEvent = sg.Handle; + Marshal.StructureToPtr(ov, unmanagedOv, true); + + uint eventMask = 0; + var uMask = Marshal.AllocHGlobal(Marshal.SizeOf(eventMask)); + + try + { + while (true) + { + if (!Win32Com.SetCommMask(_hPort, Win32Com.EV_RXCHAR | Win32Com.EV_TXEMPTY | Win32Com.EV_CTS | Win32Com.EV_DSR + | Win32Com.EV_BREAK | Win32Com.EV_RLSD | Win32Com.EV_RING | Win32Com.EV_ERR)) + { + throw new CommPortException("IO Error [001]"); + } + Marshal.WriteInt32(uMask, 0); + if (!Win32Com.WaitCommEvent(_hPort, uMask, unmanagedOv)) + { + if (Marshal.GetLastWin32Error() == Win32Com.ERROR_IO_PENDING) + { + sg.WaitOne(); + } + else + { + throw new CommPortException("IO Error [002]"); + } + } + eventMask = (uint)Marshal.ReadInt32(uMask); + if ((eventMask & Win32Com.EV_ERR) != 0) + { + UInt32 errs; + if (Win32Com.ClearCommError(_hPort, out errs, IntPtr.Zero)) + { + var s = new StringBuilder("UART Error: ", 40); + if ((errs & Win32Com.CE_FRAME) != 0) s = s.Append("Framing,"); + if ((errs & Win32Com.CE_IOE) != 0) s = s.Append("IO,"); + if ((errs & Win32Com.CE_OVERRUN) != 0) s = s.Append("Overrun,"); + if ((errs & Win32Com.CE_RXOVER) != 0) s = s.Append("Receive Cverflow,"); + if ((errs & Win32Com.CE_RXPARITY) != 0) s = s.Append("Parity,"); + if ((errs & Win32Com.CE_TXFULL) != 0) s = s.Append("Transmit Overflow,"); + s.Length = s.Length - 1; + throw new CommPortException(s.ToString()); + } + throw new CommPortException("IO Error [003]"); + } + if ((eventMask & Win32Com.EV_RXCHAR) != 0) + { + uint gotbytes; + do + { + if (!Win32Com.ReadFile(_hPort, buf, 1, out gotbytes, unmanagedOv)) + { + if (Marshal.GetLastWin32Error() == Win32Com.ERROR_IO_PENDING) + { + Win32Com.CancelIo(_hPort); + gotbytes = 0; + } + else + { + throw new CommPortException("IO Error [004]"); + } + } + if (gotbytes == 1) OnRxChar(buf[0]); + + } while (gotbytes > 0); + } + if ((eventMask & Win32Com.EV_TXEMPTY) != 0) + { + OnTxDone(); + } + if ((eventMask & Win32Com.EV_BREAK) != 0) OnBreak(); + + uint i = 0; + if ((eventMask & Win32Com.EV_CTS) != 0) i |= Win32Com.MS_CTS_ON; + if ((eventMask & Win32Com.EV_DSR) != 0) i |= Win32Com.MS_DSR_ON; + if ((eventMask & Win32Com.EV_RLSD) != 0) i |= Win32Com.MS_RLSD_ON; + if ((eventMask & Win32Com.EV_RING) != 0) i |= Win32Com.MS_RING_ON; + if (i != 0) + { + uint f; + if (!Win32Com.GetCommModemStatus(_hPort, out f)) throw new CommPortException("IO Error [005]"); + OnStatusChange(new ModemStatus(i), new ModemStatus(f)); + } + } + } + catch (Exception e) + { + if (uMask != IntPtr.Zero) Marshal.FreeHGlobal(uMask); + if (unmanagedOv != IntPtr.Zero) Marshal.FreeHGlobal(unmanagedOv); + if (!(e is ThreadAbortException)) + { + _rxException = e; + OnRxException(e); + } + } + } + + private bool CheckOnline() + { + if ((_rxException != null) && (!_rxExceptionReported)) + { + _rxExceptionReported = true; + ThrowException("rx"); + } + if (_online) + { + uint f; + if (Win32Com.GetHandleInformation(_hPort, out f)) return true; + ThrowException("Offline"); + return false; + } + if (_auto) + { + if (Open()) return true; + } + ThrowException("Offline"); + return false; + } + + + + /// + /// Port Name + /// + public string PortName { get; set; } + /// + /// Baud Rate (default: 2400) unsupported rates will throw "Bad settings" + /// + public int BaudRate = 115200; + /// + /// The parity checking scheme (default: none) + /// + public Parity Parity = Parity.None; + /// + /// Number of databits 1..8 (default: 8) unsupported values will throw "Bad settings" + /// + public int DataBits = 8; + /// + /// Number of stop bits (default: one) + /// + public StopBits StopBits = StopBits.one; + /// + /// If true, transmission is halted unless CTS is asserted by the remote station (default: false) + /// + public bool TxFlowCts; + /// + /// If true, transmission is halted unless DSR is asserted by the remote station (default: false) + /// + public bool TxFlowDsr; + /// + /// If true, transmission is halted when Xoff is received and restarted when Xon is received (default: false) + /// + public bool TxFlowX; + /// + /// If false, transmission is suspended when this station has sent Xoff to the remote station (default: true) + /// Set false if the remote station treats any character as an Xon. + /// + public bool TxWhenRxXoff = true; + /// + /// If true, received characters are ignored unless DSR is asserted by the remote station (default: false) + /// + public bool RxGateDsr; + /// + /// If true, Xon and Xoff characters are sent to control the data flow from the remote station (default: false) + /// + public bool RxFlowX; + /// + /// Specifies the use to which the RTS output is put (default: none) + /// + public HsOutput UseRts = HsOutput.None; + /// + /// Specidies the use to which the DTR output is put (default: none) + /// + public HsOutput UseDtr = HsOutput.None; + /// + /// The character used to signal Xon for X flow control (default: DC1) + /// + public ASCII XonChar = ASCII.DC1; + /// + /// The character used to signal Xoff for X flow control (default: DC3) + /// + public ASCII XoffChar = ASCII.DC3; + /// + /// The number of free bytes in the reception queue at which flow is disabled (default: 2048) + /// + public int RxHighWater = 2048; + /// + /// The number of bytes in the reception queue at which flow is re-enabled (default: 512) + /// + public int RxLowWater = 512; + /// + /// Multiplier. Max time for Send in ms = (Multiplier * Characters) + Constant + /// (default: 0 = No timeout) + /// + public int SendTimeoutMultiplier; + /// + /// Constant. Max time for Send in ms = (Multiplier * Characters) + Constant (default: 0) + /// + public int SendTimeoutConstant; + /// + /// Requested size for receive queue (default: 0 = use operating system default) + /// + public int RxQueue; + /// + /// Requested size for transmit queue (default: 0 = use operating system default) + /// + public int TxQueue; + /// + /// If true, the port will automatically re-open on next send if it was previously closed due + /// to an error (default: false) + /// + public bool AutoReopen; + + /// + /// If true, subsequent Send commands wait for completion of earlier ones enabling the results + /// to be checked. If false, errors, including timeouts, may not be detected, but performance + /// may be better. + /// + public bool CheckAllSends = true; + + private Handshake _handShake; + public Handshake Handshake + { + get { return _handShake; } + set + { + Handshake = value; + switch (Handshake) + { + case Handshake.None: + TxFlowCts = false; TxFlowDsr = false; TxFlowX = false; + RxFlowX = false; UseRts = HsOutput.Online; UseDtr = HsOutput.Online; + TxWhenRxXoff = true; RxGateDsr = false; + break; + case Handshake.XonXoff: + TxFlowCts = false; TxFlowDsr = false; TxFlowX = true; + RxFlowX = true; UseRts = HsOutput.Online; UseDtr = HsOutput.Online; + TxWhenRxXoff = true; RxGateDsr = false; + XonChar = ASCII.DC1; XoffChar = ASCII.DC3; + break; + case Handshake.CtsRts: + TxFlowCts = true; TxFlowDsr = false; TxFlowX = false; + RxFlowX = false; UseRts = HsOutput.Handshake; UseDtr = HsOutput.Online; + TxWhenRxXoff = true; RxGateDsr = false; + break; + case Handshake.DsrDtr: + TxFlowCts = false; TxFlowDsr = true; TxFlowX = false; + RxFlowX = false; UseRts = HsOutput.Online; UseDtr = HsOutput.Handshake; + TxWhenRxXoff = true; RxGateDsr = false; + break; + } + } + } + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/StopBits.cs b/PInvokeSerialPort/StopBits.cs new file mode 100755 index 0000000..c727f72 --- /dev/null +++ b/PInvokeSerialPort/StopBits.cs @@ -0,0 +1,21 @@ +namespace PInvokeSerialPort +{ + /// + /// Stop bit settings + /// + public enum StopBits + { + /// + /// Line is asserted for 1 bit duration at end of each character + /// + one = 0, + /// + /// Line is asserted for 1.5 bit duration at end of each character + /// + onePointFive = 1, + /// + /// Line is asserted for 2 bit duration at end of each character + /// + two = 2 + }; +} \ No newline at end of file diff --git a/PInvokeSerialPort/Win32PInvoke/COMMPROP.cs b/PInvokeSerialPort/Win32PInvoke/COMMPROP.cs new file mode 100755 index 0000000..2fa0a66 --- /dev/null +++ b/PInvokeSerialPort/Win32PInvoke/COMMPROP.cs @@ -0,0 +1,28 @@ +using System; +using System.Runtime.InteropServices; + +namespace PInvokeSerialPort.Win32PInvoke +{ + [StructLayout(LayoutKind.Sequential)] + internal struct COMMPROP + { + internal UInt16 wPacketLength; + internal UInt16 wPacketVersion; + internal UInt32 dwServiceMask; + internal UInt32 dwReserved1; + internal UInt32 dwMaxTxQueue; + internal UInt32 dwMaxRxQueue; + internal UInt32 dwMaxBaud; + internal UInt32 dwProvSubType; + internal UInt32 dwProvCapabilities; + internal UInt32 dwSettableParams; + internal UInt32 dwSettableBaud; + internal UInt16 wSettableData; + internal UInt16 wSettableStopParity; + internal UInt32 dwCurrentTxQueue; + internal UInt32 dwCurrentRxQueue; + internal UInt32 dwProvSpec1; + internal UInt32 dwProvSpec2; + internal Byte wcProvChar; + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/Win32PInvoke/COMMTIMEOUTS.cs b/PInvokeSerialPort/Win32PInvoke/COMMTIMEOUTS.cs new file mode 100755 index 0000000..506c49a --- /dev/null +++ b/PInvokeSerialPort/Win32PInvoke/COMMTIMEOUTS.cs @@ -0,0 +1,15 @@ +using System; +using System.Runtime.InteropServices; + +namespace PInvokeSerialPort.Win32PInvoke +{ + [StructLayout(LayoutKind.Sequential)] + internal struct COMMTIMEOUTS + { + internal Int32 ReadIntervalTimeout; + internal Int32 ReadTotalTimeoutMultiplier; + internal Int32 ReadTotalTimeoutConstant; + internal Int32 WriteTotalTimeoutMultiplier; + internal Int32 WriteTotalTimeoutConstant; + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/Win32PInvoke/COMSTAT.cs b/PInvokeSerialPort/Win32PInvoke/COMSTAT.cs new file mode 100755 index 0000000..c4d5be0 --- /dev/null +++ b/PInvokeSerialPort/Win32PInvoke/COMSTAT.cs @@ -0,0 +1,20 @@ +using System; +using System.Runtime.InteropServices; + +namespace PInvokeSerialPort.Win32PInvoke +{ + [StructLayout(LayoutKind.Sequential)] + internal struct COMSTAT + { + internal const uint fCtsHold = 0x1; + internal const uint fDsrHold = 0x2; + internal const uint fRlsdHold = 0x4; + internal const uint fXoffHold = 0x8; + internal const uint fXoffSent = 0x10; + internal const uint fEof = 0x20; + internal const uint fTxim = 0x40; + internal UInt32 Flags; + internal UInt32 cbInQue; + internal UInt32 cbOutQue; + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/Win32PInvoke/DCB.cs b/PInvokeSerialPort/Win32PInvoke/DCB.cs new file mode 100755 index 0000000..4ef5aba --- /dev/null +++ b/PInvokeSerialPort/Win32PInvoke/DCB.cs @@ -0,0 +1,41 @@ +using System; +using System.Runtime.InteropServices; + +namespace PInvokeSerialPort.Win32PInvoke +{ + [StructLayout(LayoutKind.Sequential)] + internal struct DCB + { + internal Int32 DCBlength; + internal Int32 BaudRate; + internal Int32 PackedValues; + internal Int16 wReserved; + internal Int16 XonLim; + internal Int16 XoffLim; + internal Byte ByteSize; + internal Byte Parity; + internal Byte StopBits; + internal Byte XonChar; + internal Byte XoffChar; + internal Byte ErrorChar; + internal Byte EofChar; + internal Byte EvtChar; + internal Int16 wReserved1; + + internal void Init(bool parity, bool outCts, bool outDsr, int dtr, bool inDsr, bool txc, bool xOut, + bool xIn, int rts) + { + DCBlength = 28; PackedValues = 0x8001; + if (parity) PackedValues |= 0x0002; + if (outCts) PackedValues |= 0x0004; + if (outDsr) PackedValues |= 0x0008; + PackedValues |= ((dtr & 0x0003) << 4); + if (inDsr) PackedValues |= 0x0040; + if (txc) PackedValues |= 0x0080; + if (xOut) PackedValues |= 0x0100; + if (xIn) PackedValues |= 0x0200; + PackedValues |= ((rts & 0x0003) << 12); + + } + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/Win32PInvoke/OVERLAPPED.cs b/PInvokeSerialPort/Win32PInvoke/OVERLAPPED.cs new file mode 100755 index 0000000..c26ff13 --- /dev/null +++ b/PInvokeSerialPort/Win32PInvoke/OVERLAPPED.cs @@ -0,0 +1,15 @@ +using System; +using System.Runtime.InteropServices; + +namespace PInvokeSerialPort.Win32PInvoke +{ + [StructLayout(LayoutKind.Sequential)] + internal struct OVERLAPPED + { + internal UIntPtr Internal; + internal UIntPtr InternalHigh; + internal UInt32 Offset; + internal UInt32 OffsetHigh; + internal IntPtr hEvent; + } +} \ No newline at end of file diff --git a/PInvokeSerialPort/Win32PInvoke/Win32Com.cs b/PInvokeSerialPort/Win32PInvoke/Win32Com.cs new file mode 100755 index 0000000..029af99 --- /dev/null +++ b/PInvokeSerialPort/Win32PInvoke/Win32Com.cs @@ -0,0 +1,155 @@ +using System; +using System.Runtime.InteropServices; + +namespace PInvokeSerialPort.Win32PInvoke +{ + internal class Win32Com + { + /// + /// Opening Testing and Closing the Port Handle. + /// + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, + IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, + IntPtr hTemplateFile); + + //Constants for errors: + internal const UInt32 ERROR_FILE_NOT_FOUND = 2; + internal const UInt32 ERROR_INVALID_NAME = 123; + internal const UInt32 ERROR_ACCESS_DENIED = 5; + internal const UInt32 ERROR_IO_PENDING = 997; + + //Constants for return value: + internal const Int32 INVALID_HANDLE_VALUE = -1; + + //Constants for dwFlagsAndAttributes: + internal const UInt32 FILE_FLAG_OVERLAPPED = 0x40000000; + + //Constants for dwCreationDisposition: + internal const UInt32 OPEN_EXISTING = 3; + + //Constants for dwDesiredAccess: + internal const UInt32 GENERIC_READ = 0x80000000; + internal const UInt32 GENERIC_WRITE = 0x40000000; + + [DllImport("kernel32.dll")] + internal static extern Boolean CloseHandle(IntPtr hObject); + + [DllImport("kernel32.dll")] + internal static extern Boolean GetHandleInformation(IntPtr hObject, out UInt32 lpdwFlags); + + + /// + /// Manipulating the communications settings. + /// + + [DllImport("kernel32.dll")] + internal static extern Boolean GetCommState(IntPtr hFile, ref DCB lpDCB); + + [DllImport("kernel32.dll")] + internal static extern Boolean GetCommTimeouts(IntPtr hFile, out COMMTIMEOUTS lpCommTimeouts); + + [DllImport("kernel32.dll")] + internal static extern Boolean BuildCommDCBAndTimeouts(String lpDef, ref DCB lpDCB, ref COMMTIMEOUTS lpCommTimeouts); + + [DllImport("kernel32.dll")] + internal static extern Boolean SetCommState(IntPtr hFile, [In] ref DCB lpDCB); + + [DllImport("kernel32.dll")] + internal static extern Boolean SetCommTimeouts(IntPtr hFile, [In] ref COMMTIMEOUTS lpCommTimeouts); + + [DllImport("kernel32.dll")] + internal static extern Boolean SetupComm(IntPtr hFile, UInt32 dwInQueue, UInt32 dwOutQueue); + + /// + /// Reading and writing. + /// + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern Boolean WriteFile(IntPtr fFile, Byte[] lpBuffer, UInt32 nNumberOfBytesToWrite, + out UInt32 lpNumberOfBytesWritten, IntPtr lpOverlapped); + + [DllImport("kernel32.dll")] + internal static extern Boolean SetCommMask(IntPtr hFile, UInt32 dwEvtMask); + + // Constants for dwEvtMask: + internal const UInt32 EV_RXCHAR = 0x0001; + internal const UInt32 EV_RXFLAG = 0x0002; + internal const UInt32 EV_TXEMPTY = 0x0004; + internal const UInt32 EV_CTS = 0x0008; + internal const UInt32 EV_DSR = 0x0010; + internal const UInt32 EV_RLSD = 0x0020; + internal const UInt32 EV_BREAK = 0x0040; + internal const UInt32 EV_ERR = 0x0080; + internal const UInt32 EV_RING = 0x0100; + internal const UInt32 EV_PERR = 0x0200; + internal const UInt32 EV_RX80FULL = 0x0400; + internal const UInt32 EV_EVENT1 = 0x0800; + internal const UInt32 EV_EVENT2 = 0x1000; + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern Boolean WaitCommEvent(IntPtr hFile, IntPtr lpEvtMask, IntPtr lpOverlapped); + + [DllImport("kernel32.dll")] + internal static extern Boolean CancelIo(IntPtr hFile); + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern Boolean ReadFile(IntPtr hFile, [Out] Byte[] lpBuffer, UInt32 nNumberOfBytesToRead, + out UInt32 nNumberOfBytesRead, IntPtr lpOverlapped); + + [DllImport("kernel32.dll")] + internal static extern Boolean TransmitCommChar(IntPtr hFile, Byte cChar); + + /// + /// Control port functions. + /// + [DllImport("kernel32.dll")] + internal static extern Boolean EscapeCommFunction(IntPtr hFile, UInt32 dwFunc); + + // Constants for dwFunc: + internal const UInt32 SETXOFF = 1; + internal const UInt32 SETXON = 2; + internal const UInt32 SETRTS = 3; + internal const UInt32 CLRRTS = 4; + internal const UInt32 SETDTR = 5; + internal const UInt32 CLRDTR = 6; + internal const UInt32 RESETDEV = 7; + internal const UInt32 SETBREAK = 8; + internal const UInt32 CLRBREAK = 9; + + [DllImport("kernel32.dll")] + internal static extern Boolean GetCommModemStatus(IntPtr hFile, out UInt32 lpModemStat); + + // Constants for lpModemStat: + internal const UInt32 MS_CTS_ON = 0x0010; + internal const UInt32 MS_DSR_ON = 0x0020; + internal const UInt32 MS_RING_ON = 0x0040; + internal const UInt32 MS_RLSD_ON = 0x0080; + + /// + /// Status Functions. + /// + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern Boolean GetOverlappedResult(IntPtr hFile, IntPtr lpOverlapped, + out UInt32 nNumberOfBytesTransferred, Boolean bWait); + + [DllImport("kernel32.dll")] + internal static extern Boolean ClearCommError(IntPtr hFile, out UInt32 lpErrors, IntPtr lpStat); + [DllImport("kernel32.dll")] + internal static extern Boolean ClearCommError(IntPtr hFile, out UInt32 lpErrors, out COMSTAT cs); + + //Constants for lpErrors: + internal const UInt32 CE_RXOVER = 0x0001; + internal const UInt32 CE_OVERRUN = 0x0002; + internal const UInt32 CE_RXPARITY = 0x0004; + internal const UInt32 CE_FRAME = 0x0008; + internal const UInt32 CE_BREAK = 0x0010; + internal const UInt32 CE_TXFULL = 0x0100; + internal const UInt32 CE_PTO = 0x0200; + internal const UInt32 CE_IOE = 0x0400; + internal const UInt32 CE_DNS = 0x0800; + internal const UInt32 CE_OOP = 0x1000; + internal const UInt32 CE_MODE = 0x8000; + [DllImport("kernel32.dll")] + internal static extern Boolean GetCommProperties(IntPtr hFile, out COMMPROP cp); + } +} \ No newline at end of file