Advertisement
firdacz

ComPort.cs

Aug 29th, 2014
358
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.77 KB | None | 0 0
  1. using System; using System.Text; using System.Collections.Generic;
  2. using System.IO; using System.IO.Ports; using System.Runtime.InteropServices;
  3. using Microsoft.Win32.SafeHandles; using System.Threading;
  4. namespace Fire { public class ComStream: Stream {
  5. //##################################################################################################
  6. public enum IMPL {
  7. [Display("P/Invoke", XX="native")] NATIVE,
  8. [Display("FileStream", XX="stream")] STREAM,
  9. [Display("SerialPort", XX="serial")] SERIAL }
  10. #if MONO
  11. public static IMPL Implementation = IMPL.SERIAL;
  12. #else
  13. public static IMPL Implementation = IMPL.STREAM;
  14. #endif
  15. public static bool UseAsync = Environment.OSVersion.Platform != PlatformID.Win32Windows;
  16. //[Obsolete]
  17. public static bool UseFileStream { get { return Implementation == IMPL.STREAM; }
  18.     set { Implementation = value ? IMPL.STREAM : IMPL.NATIVE; } }
  19. public static bool UseSerialPort { get { return Implementation == IMPL.SERIAL; }
  20.     set { Implementation = value ? IMPL.SERIAL : IMPL.STREAM; } }
  21. //==================================================================================================
  22. protected byte port;
  23. protected SerialPort serport;
  24. #if !MONO
  25. protected FileStream fstream;
  26. protected SafeFileHandle handle;
  27. protected WinApi.DCB dcb;
  28. protected WinApi.COMMTIMEOUTS tmos;
  29. #endif
  30. protected void SafeClearHandle() {
  31. #if MONO
  32.     try { serport.Close(); } catch { }
  33.     serport = null;
  34. #else
  35.     if(serport != null) {
  36.         try { serport.Close(); } catch { }
  37.         serport = null; return; }
  38.     SafeFileHandle toClose = handle;
  39.     this.handle = null;
  40.     if(toClose == null) return;
  41.     if(fstream != null) {
  42.         try { fstream.Close(); } catch { }
  43.         fstream = null; }
  44.     try { toClose.Close(); } catch { }
  45. #endif
  46. }
  47. protected override void Dispose(bool disposing) {
  48.     if(disposing) try { Flush(); } catch { }
  49.     SafeClearHandle();
  50.     base.Dispose(disposing); }
  51. protected ComStream(byte port) {
  52.     this.port = port;
  53. #if !MONO
  54.     if(Implementation != IMPL.SERIAL) {
  55.     handle = WinApi.OpenFile(@"\\.\COM" + port.ToString(), WinApi.OPEN_EXISTING,
  56.         UseAsync ? WinApi.FILE_FLAG_OVERLAPPED : WinApi.FILE_ATTRIBUTE_NORMAL);
  57.     if(handle.IsInvalid) {
  58.         handle = null; Throw.WinIO("COM{0} open", port); }
  59.     try {
  60.         tmos.ReadIntervalTimeout = 1;               // 1ms max between bytes
  61.         tmos.ReadTotalTimeoutMultiplier = 0;        // don't use - big buffers ;)
  62.         tmos.ReadTotalTimeoutConstant = 333;        // 1/3s max for read
  63.         tmos.WriteTotalTimeoutConstant = 1000;      // 1s max for write
  64.         tmos.WriteTotalTimeoutMultiplier = 2;       // add max 2ms per byte write
  65.  
  66.         dcb.DCBlength = (uint)Marshal.SizeOf(dcb);
  67.         if(!WinApi.GetCommState(handle, ref dcb)) Throw.WinIO("COM{0} get settings", port);
  68.         dcb.DCBlength = (uint)Marshal.SizeOf(dcb);
  69.         dcb.Flags = WinApi.DCB.fBinary|WinApi.DCB.fCtsFlow|WinApi.DCB.fDtrOn|WinApi.DCB.fRtsOn|WinApi.DCB.fAbort;
  70.         dcb.ByteSize = 8;
  71.         dcb.Parity = 0;
  72.         dcb.StopBits = 0;
  73.  
  74.     } catch { SafeClearHandle(); throw; } return; }
  75. #endif
  76.     string name = WinApi.WinVer != WinVer.Unix ? "COM" + port.ToString()
  77.         : port < 20 ? "/dev/ttyS" + port.ToString()
  78.         : port < 50 ? "/dev/ttyACM" + (port-20).ToString()
  79.         : "/dev/ttyUSB" + (port-50).ToString();
  80.     if(WinApi.WinVer == WinVer.Unix && !File.Exists(name))
  81.         Throw.IO("{0} does not exist", name);
  82.     serport = new SerialPort(name, 115200) {
  83.         DtrEnable = true, RtsEnable = true };
  84. }
  85. protected void SetCommState() {
  86. #if !MONO
  87.     if(serport != null) return;
  88.     if(!WinApi.SetCommState(handle, ref dcb)) Throw.WinIO("COM{0} set settings", port);
  89. #endif
  90. }
  91. protected void SetCommTimeouts() {
  92. #if !MONO
  93.     if(serport != null) return;
  94.     if(!WinApi.SetCommTimeouts(handle, ref tmos)) Throw.WinIO("COM{0} set timeouts", port);
  95. #endif
  96. }
  97. protected void Init() {
  98.     try {
  99.     #if MONO
  100.         serport.Open();
  101.     #else
  102.         if(UseSerialPort)
  103.             serport.Open();
  104.         else {
  105.             SetCommState();
  106.             SetCommTimeouts();
  107.             if(UseFileStream) fstream = new FileStream(handle, FileAccess.ReadWrite, 0x1000, UseAsync);
  108.         }
  109.     #endif
  110.     } catch { SafeClearHandle(); throw; }}
  111. protected static byte CheckPortNumber(int port) {
  112.     if(port < 0 || port > 99) Throw.Range("port");
  113.     return (byte)port; }
  114. public ComStream(int port) : this(CheckPortNumber(port)) { Init(); }
  115. public ComStream(int port, uint rate) : this(CheckPortNumber(port)) {
  116. #if MONO
  117.     serport.BaudRate = rate > 0 ? (int)rate : 115200;
  118. #else
  119.     dcb.BaudRate = rate;
  120. #endif
  121.     Init(); }
  122. public ComStream(int port, uint rate, Handshake flow) : this(CheckPortNumber(port)) {
  123. #if MONO
  124.     serport.BaudRate = rate > 0? (int)rate : 115200;
  125.     serport.Handshake = flow;
  126. #else
  127.     dcb.Flags &=~(WinApi.DCB.fRtsMask|WinApi.DCB.fXIn|WinApi.DCB.fXOut);
  128.     dcb.Flags |= (flow & Handshake.RequestToSend) != Handshake.None ? WinApi.DCB.fRtsFlow : WinApi.DCB.fRtsOn;
  129.     if((flow & Handshake.XOnXOff) != Handshake.None) dcb.Flags |= WinApi.DCB.fXOut|WinApi.DCB.fXIn;
  130.     dcb.BaudRate = rate;
  131. #endif
  132.     Init(); }
  133. //--------------------------------------------------------------------------------------------------
  134. public int BytesToRead { get {
  135.     if(serport != null) return serport.BytesToRead;
  136.     WinApi.COMSTAT stat = new WinApi.COMSTAT();
  137.     WinApi.ClearCommError(handle, IntPtr.Zero, out stat);
  138.     return (int)stat.cbInQue; } }
  139. #if !MONO
  140. private int read(byte[] buffer, int offset, int count) {
  141.     if(serport != null) return serport.Read(buffer, offset, count);
  142.     if(fstream != null) return fstream.Read(buffer, offset, count);
  143.     return WinApi.ReadFile(handle, buffer, offset, count); }
  144. #endif
  145. public override int Read(byte[] buffer, int offset, int count) {
  146.     if(count <= 0) return 0;
  147. #if MONO
  148.     int inq = serport.BytesToRead;
  149.     if(inq <= 0) return inq;
  150.     if(count > inq) count = inq;
  151.     return serport.Read(buffer, offset, count);
  152. #else
  153.     int inq = BytesToRead;
  154.     if(inq > 0) {
  155.         if(count > inq) count = inq;
  156.         return read(buffer, offset, count); }
  157.     int num = read(buffer, offset, 1);
  158.     if(num <= 0) return num;
  159.     offset += num;
  160.     count  -= num;
  161.     inq = BytesToRead;
  162.     if(count > inq) count = inq;
  163.     return num + read(buffer, offset, count);
  164. #endif
  165. }
  166. public override void Write(byte[] buffer, int offset, int count) {
  167. #if MONO
  168.     serport.Write(buffer, offset, count);
  169. #else
  170.     if(serport != null) { serport.Write(buffer, offset, count); }
  171.     else if(fstream != null) { fstream.Write(buffer, offset, count); fstream.Flush(); }
  172.     else WinApi.WriteFile(handle, buffer, offset, count);
  173. #endif
  174. }
  175. public override void Flush() {
  176. #if !MONO
  177. //  can result in lockdown on win7
  178. //  if(handle != null) WinApi.FlushFileBuffers(handle);
  179.     if(fstream != null) fstream.Flush();
  180. #endif
  181. }
  182. //--------------------------------------------------------------------------------------------------
  183. public byte Port {
  184.     get { return port; } }
  185. public Handshake Handshake {
  186.     get {
  187.     #if MONO
  188.         return serport.Handshake;
  189.     #else
  190.         if(serport != null) return serport.Handshake;
  191.         Handshake flow = Handshake.None;
  192.         if((dcb.Flags & WinApi.DCB.fRtsFlow) != 0) flow |= Handshake.RequestToSend;
  193.         if((dcb.Flags & WinApi.DCB.fXIn) != 0) flow |= Handshake.XOnXOff;
  194.         return flow;
  195.     #endif
  196.     }
  197.     set {
  198.     #if MONO
  199.         serport.Handshake = value;
  200.     #else
  201.         if(serport != null) {
  202.             serport.Handshake = value; return; }
  203.         uint flags = dcb.Flags;
  204.         try {
  205.             dcb.Flags &=~(WinApi.DCB.fRtsMask|WinApi.DCB.fXIn|WinApi.DCB.fXOut);
  206.             dcb.Flags |= (value & Handshake.RequestToSend) != Handshake.None ? WinApi.DCB.fRtsFlow : WinApi.DCB.fRtsOn;
  207.             if((value & Handshake.XOnXOff) != Handshake.None) dcb.Flags |= WinApi.DCB.fXOut|WinApi.DCB.fXIn;
  208.             if(!WinApi.SetCommState(handle, ref dcb)) Throw.WinIO("COM{0} set settings", port);
  209.         } catch {
  210.             dcb.Flags = flags;
  211.             throw; }
  212.     #endif
  213.     }}
  214. public uint BaudRate {
  215.     get {
  216.     #if MONO
  217.         return (uint)serport.BaudRate;
  218.     #else
  219.         return dcb.BaudRate;
  220.     #endif
  221.     }
  222.     set {
  223.     #if MONO
  224.         serport.BaudRate = (int)value;
  225.     #else
  226.         uint rate = dcb.BaudRate;
  227.         try {
  228.             dcb.BaudRate = value;
  229.             SetCommState();
  230.         } catch {
  231.             dcb.BaudRate = rate;
  232.             throw; }
  233.     #endif
  234.     }}
  235. //--------------------------------------------------------------------------------------------------
  236. #if MONO
  237. public override bool CanRead { get { return serport != null; } }
  238. public override bool CanWrite { get { return serport != null; } }
  239. #else
  240. public override bool CanRead { get { return handle != null || serport != null; } }
  241. public override bool CanWrite { get { return handle != null || serport != null; } }
  242. #endif
  243. public override bool CanTimeout { get { return false; /* TODO */ } }
  244. public override bool CanSeek { get { return false; } }
  245. public override long Length { get { throw new NotImplementedException(); } }
  246. public override void SetLength(long value) { throw new NotImplementedException(); }
  247. public override long Position {
  248.     get { throw new NotImplementedException(); }
  249.     set { throw new NotImplementedException(); } }
  250. public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); }
  251. }}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement