Last active
November 18, 2023 02:37
-
-
Save heiswayi/80eda1a6905ba4edee8bd21a45f3a22d to your computer and use it in GitHub Desktop.
Singleton .NET SerialPort wrapper class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
MIT License | |
Copyright (c) 2016 Heiswayi Nrird | |
Permission is hereby granted, free of charge, to any person obtaining a copy | |
of this software and associated documentation files (the "Software"), to deal | |
in the Software without restriction, including without limitation the rights | |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the Software is | |
furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in all | |
copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
SOFTWARE. | |
*/ | |
using System; | |
using System.IO; | |
using System.IO.Ports; | |
using System.Threading; | |
namespace HeiswayiNrird.Singletons | |
{ | |
public sealed class SerialPortManager | |
{ | |
private static readonly Lazy<SerialPortManager> lazy = new Lazy<SerialPortManager>(() => new SerialPortManager()); | |
public static SerialPortManager Instance { get { return lazy.Value; } } | |
private SerialPort _serialPort; | |
private Thread _readThread; | |
private volatile bool _keepReading; | |
private SerialPortManager() | |
{ | |
_serialPort = new SerialPort(); | |
_readThread = null; | |
_keepReading = false; | |
} | |
/// <summary> | |
/// Update the serial port status to the event subscriber | |
/// </summary> | |
public event EventHandler<string> OnStatusChanged; | |
/// <summary> | |
/// Update received data from the serial port to the event subscriber | |
/// </summary> | |
public event EventHandler<string> OnDataReceived; | |
/// <summary> | |
/// Update TRUE/FALSE for the serial port connection to the event subscriber | |
/// </summary> | |
public event EventHandler<bool> OnSerialPortOpened; | |
/// <summary> | |
/// Return TRUE if the serial port is currently connected | |
/// </summary> | |
public bool IsOpen { get { return _serialPort.IsOpen; } } | |
/// <summary> | |
/// Open the serial port connection using basic serial port settings | |
/// </summary> | |
/// <param name="portname">COM1 / COM3 / COM4 / etc.</param> | |
/// <param name="baudrate">0 / 100 / 300 / 600 / 1200 / 2400 / 4800 / 9600 / 14400 / 19200 / 38400 / 56000 / 57600 / 115200 / 128000 / 256000</param> | |
/// <param name="parity">None / Odd / Even / Mark / Space</param> | |
/// <param name="databits">5 / 6 / 7 / 8</param> | |
/// <param name="stopbits">None / One / Two / OnePointFive</param> | |
/// <param name="handshake">None / XOnXOff / RequestToSend / RequestToSendXOnXOff</param> | |
public void Open( | |
string portname = "COM1", | |
int baudrate = 9600, | |
Parity parity = Parity.None, | |
int databits = 8, | |
StopBits stopbits = StopBits.One, | |
Handshake handshake = Handshake.None) | |
{ | |
Close(); | |
try | |
{ | |
_serialPort.PortName = portname; | |
_serialPort.BaudRate = baudrate; | |
_serialPort.Parity = parity; | |
_serialPort.DataBits = databits; | |
_serialPort.StopBits = stopbits; | |
_serialPort.Handshake = handshake; | |
_serialPort.ReadTimeout = 50; | |
_serialPort.WriteTimeout = 50; | |
_serialPort.Open(); | |
StartReading(); | |
} | |
catch (IOException) | |
{ | |
if (OnStatusChanged != null) | |
OnStatusChanged(this, string.Format("{0} does not exist.", portname)); | |
} | |
catch (UnauthorizedAccessException) | |
{ | |
if (OnStatusChanged != null) | |
OnStatusChanged(this, string.Format("{0} already in use.", portname)); | |
} | |
catch (Exception ex) | |
{ | |
if (OnStatusChanged != null) | |
OnStatusChanged(this, "Error: " + ex.Message); | |
} | |
if (_serialPort.IsOpen) | |
{ | |
string sb = StopBits.None.ToString().Substring(0, 1); | |
switch (_serialPort.StopBits) | |
{ | |
case StopBits.One: | |
sb = "1"; break; | |
case StopBits.OnePointFive: | |
sb = "1.5"; break; | |
case StopBits.Two: | |
sb = "2"; break; | |
default: | |
break; | |
} | |
string p = _serialPort.Parity.ToString().Substring(0, 1); | |
string hs = _serialPort.Handshake == Handshake.None ? "No Handshake" : _serialPort.Handshake.ToString(); | |
if (OnStatusChanged != null) | |
OnStatusChanged(this, string.Format( | |
"Connected to {0}: {1} bps, {2}{3}{4}, {5}.", | |
_serialPort.PortName, | |
_serialPort.BaudRate, | |
_serialPort.DataBits, | |
p, | |
sb, | |
hs)); | |
if (OnSerialPortOpened != null) | |
OnSerialPortOpened(this, true); | |
} | |
else | |
{ | |
if (OnStatusChanged != null) | |
OnStatusChanged(this, string.Format( | |
"{0} already in use.", | |
portname)); | |
if (OnSerialPortOpened != null) | |
OnSerialPortOpened(this, false); | |
} | |
} | |
/// <summary> | |
/// Close the serial port connection | |
/// </summary> | |
public void Close() | |
{ | |
StopReading(); | |
_serialPort.Close(); | |
if (OnStatusChanged != null) | |
OnStatusChanged(this, "Connection closed."); | |
if (OnSerialPortOpened != null) | |
OnSerialPortOpened(this, false); | |
} | |
/// <summary> | |
/// Send/write string to the serial port | |
/// </summary> | |
/// <param name="message"></param> | |
public void SendString(string message) | |
{ | |
if (_serialPort.IsOpen) | |
{ | |
try | |
{ | |
_serialPort.Write(message); | |
if (OnStatusChanged != null) | |
OnStatusChanged(this, string.Format( | |
"Message sent: {0}", | |
message)); | |
} | |
catch (Exception ex) | |
{ | |
if (OnStatusChanged != null) | |
OnStatusChanged(this, string.Format( | |
"Failed to send string: {0}", | |
ex.Message)); | |
} | |
} | |
} | |
private void StartReading() | |
{ | |
if (!_keepReading) | |
{ | |
_keepReading = true; | |
_readThread = new Thread(ReadPort); | |
_readThread.Start(); | |
} | |
} | |
private void StopReading() | |
{ | |
if (_keepReading) | |
{ | |
_keepReading = false; | |
_readThread.Join(); | |
_readThread = null; | |
} | |
} | |
private void ReadPort() | |
{ | |
while (_keepReading) | |
{ | |
if (_serialPort.IsOpen) | |
{ | |
//byte[] readBuffer = new byte[_serialPort.ReadBufferSize + 1]; | |
try | |
{ | |
//int count = _serialPort.Read(readBuffer, 0, _serialPort.ReadBufferSize); | |
//string data = Encoding.ASCII.GetString(readBuffer, 0, count); | |
string data = _serialPort.ReadLine(); | |
if (OnDataReceived != null) | |
OnDataReceived(this, data); | |
} | |
catch (TimeoutException) { } | |
} | |
else | |
{ | |
TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50); | |
Thread.Sleep(waitTime); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment