From 6acfd0d76b21cf1c7857d8bc16fa1e039cad295b Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sat, 1 May 2021 14:16:33 +0100 Subject: [PATCH] updates --- CodeMaid.config | 2 +- Directory.Build.props | 17 +-- SerialPortRx.sln | 2 + SerialPortRx/IDisposableExtensions.cs | 19 ++- SerialPortRx/ISerialPortRx.cs | 24 ++-- SerialPortRx/Properties/AssemblyInfo.cs | 7 +- SerialPortRx/SerialPortRx.cs | 150 +++++++++++++++++------- SerialPortRx/SerialPortRxMixins.cs | 134 ++++++++++++--------- appveyor.yml | 2 +- 9 files changed, 235 insertions(+), 122 deletions(-) diff --git a/CodeMaid.config b/CodeMaid.config index 06094b4..1e8265c 100644 --- a/CodeMaid.config +++ b/CodeMaid.config @@ -15,7 +15,7 @@ 2 - True + False Structs||9||Structs diff --git a/Directory.Build.props b/Directory.Build.props index 7fdfb9e..77d06d6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -22,12 +22,13 @@ true - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/SerialPortRx.sln b/SerialPortRx.sln index 15126aa..1aa9524 100644 --- a/SerialPortRx.sln +++ b/SerialPortRx.sln @@ -7,9 +7,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SerialPortRx", "SerialPortR EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ConfigFiles", "ConfigFiles", "{D4EE9FBC-EA31-4BF1-8F9D-A8D1E0B9500C}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig appveyor.yml = appveyor.yml Directory.Build.props = Directory.Build.props README.md = README.md + stylecop.json = stylecop.json Version.json = Version.json EndProjectSection EndProject diff --git a/SerialPortRx/IDisposableExtensions.cs b/SerialPortRx/IDisposableExtensions.cs index b31f3f9..48632b7 100644 --- a/SerialPortRx/IDisposableExtensions.cs +++ b/SerialPortRx/IDisposableExtensions.cs @@ -1,18 +1,25 @@ -using System.Collections.Generic; +// +// Copyright (c) Chris Pulman. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; namespace CP.IO.Ports { - using System; - /// - /// IDisposable Extensions + /// IDisposable Extensions. /// public static class IDisposableExtensions - { /// - /// Add disposable(self) to CompositeDisposable(or other ICollection) + /// Add disposable(self) to CompositeDisposable(or other ICollection). /// + /// The type. + /// The disposable. + /// The container. + /// Type of T. public static T AddTo(this T disposable, ICollection container) where T : IDisposable { diff --git a/SerialPortRx/ISerialPortRx.cs b/SerialPortRx/ISerialPortRx.cs index 2d1009c..0238bd5 100644 --- a/SerialPortRx/ISerialPortRx.cs +++ b/SerialPortRx/ISerialPortRx.cs @@ -1,11 +1,16 @@ -namespace CP.IO.Ports -{ - using System; - using System.IO.Ports; - using System.Threading.Tasks; +// +// Copyright (c) Chris Pulman. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.IO.Ports; +using System.Threading.Tasks; +namespace CP.IO.Ports +{ /// - /// Serial Port Rx interface + /// Serial Port Rx interface. /// public interface ISerialPortRx : IDisposable { @@ -46,9 +51,11 @@ public interface ISerialPortRx : IDisposable bool IsDisposed { get; } /// - /// Gets the is open. + /// Gets a value indicating whether gets the is open. /// - /// The is open. + /// + /// The is open. + /// bool IsOpen { get; } /// @@ -95,6 +102,7 @@ public interface ISerialPortRx : IDisposable /// /// Opens this instance. /// + /// A Task. Task Open(); /// diff --git a/SerialPortRx/Properties/AssemblyInfo.cs b/SerialPortRx/Properties/AssemblyInfo.cs index 64c9859..4860cdf 100644 --- a/SerialPortRx/Properties/AssemblyInfo.cs +++ b/SerialPortRx/Properties/AssemblyInfo.cs @@ -1,4 +1,9 @@ -using System.Reflection; +// +// Copyright (c) Chris Pulman. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Reflection; using System.Runtime.InteropServices; [assembly: ComVisible(false)] diff --git a/SerialPortRx/SerialPortRx.cs b/SerialPortRx/SerialPortRx.cs index b83164f..af2bb80 100644 --- a/SerialPortRx/SerialPortRx.cs +++ b/SerialPortRx/SerialPortRx.cs @@ -1,20 +1,25 @@ -namespace CP.IO.Ports +// +// Copyright (c) Chris Pulman. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO.Ports; +using System.Linq; +using System.Reactive; +using System.Reactive.Disposables; +using System.Reactive.Linq; +using System.Reactive.Subjects; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace CP.IO.Ports { - using System; - using System.ComponentModel; - using System.Diagnostics; - using System.IO.Ports; - using System.Linq; - using System.Reactive; - using System.Reactive.Disposables; - using System.Reactive.Linq; - using System.Reactive.Subjects; - using System.Text; - using System.Threading; - using System.Threading.Tasks; - /// - /// Serial Port Rx + /// Serial Port Rx. /// /// public class SerialPortRx : ISerialPortRx @@ -104,10 +109,13 @@ public SerialPortRx(string port, int baudRate) } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The port. - public SerialPortRx(string port) { PortName = port; } + public SerialPortRx(string port) + { + PortName = port; + } /// /// Initializes a new instance of the class. @@ -173,7 +181,7 @@ public SerialPortRx() public bool IsDisposed { get; private set; } = false; /// - /// Gets the is open. + /// Gets a value indicating whether gets the is open. /// /// The is open. [Browsable(true)] @@ -231,13 +239,17 @@ public SerialPortRx() [MonitoringDescription("WriteTimeout")] public int WriteTimeout { get; set; } = -1; - private IObservable Connect => Observable.Create(obs => { + private IObservable Connect => Observable.Create(obs => + { var dis = new CompositeDisposable(); // Check that the port exists - if (!SerialPort.GetPortNames().Any(name => name.Equals(PortName))) { + if (!SerialPort.GetPortNames().Any(name => name.Equals(PortName))) + { obs.OnError(new Exception($"Serial Port {PortName} does not exist")); - } else { + } + else + { // Setup Com Port var port = new SerialPort(PortName, BaudRate, Parity, DataBits, StopBits); dis.Add(port); @@ -246,20 +258,26 @@ public SerialPortRx() port.ReadTimeout = ReadTimeout; port.WriteTimeout = WriteTimeout; port.Encoding = Encoding; - try { + try + { port.Open(); - } catch (Exception ex) { + } + catch (Exception ex) + { errors.OnNext(ex); obs.OnCompleted(); } + isOpen.OnNext(port.IsOpen); IsOpen = port.IsOpen; // Clear any existing buffers - if (IsOpen) { + if (IsOpen) + { port.DiscardInBuffer(); port.DiscardOutBuffer(); } + Thread.Sleep(100); // Subscribe to port errors @@ -273,28 +291,58 @@ from data in port.ReadExisting() dis.Add(dataStream.Subscribe(dataReceived.OnNext, obs.OnError)); // setup Write streams - dis.Add(writeString.Subscribe(x => { - try { port?.Write(x); } catch (Exception ex) { + dis.Add(writeString.Subscribe( + x => + { + try + { + port?.Write(x); + } + catch (Exception ex) + { obs.OnError(ex); } }, obs.OnError)); - dis.Add(writeStringLine.Subscribe(x => { - try { port?.WriteLine(x); } catch (Exception ex) { + dis.Add(writeStringLine.Subscribe( + x => + { + try + { + port?.WriteLine(x); + } + catch (Exception ex) + { obs.OnError(ex); } }, obs.OnError)); - dis.Add(writeByte.Subscribe(x => { - try { port?.Write(x.Item1, x.Item2, x.Item3); } catch (Exception ex) { + dis.Add(writeByte.Subscribe( + x => + { + try + { + port?.Write(x.Item1, x.Item2, x.Item3); + } + catch (Exception ex) + { obs.OnError(ex); } }, obs.OnError)); - dis.Add(writeChar.Subscribe(x => { - try { port?.Write(x.Item1, x.Item2, x.Item3); } catch (Exception ex) { + dis.Add(writeChar.Subscribe( + x => + { + try + { + port?.Write(x.Item1, x.Item2, x.Item3); + } + catch (Exception ex) + { obs.OnError(ex); } }, obs.OnError)); } - return Disposable.Create(() => { + + return Disposable.Create(() => + { IsOpen = false; isOpen.OnNext(false); dis.Dispose(); @@ -306,29 +354,39 @@ from data in port.ReadExisting() /// /// The poll interval. /// The poll limit, once number is reached observable will complete. - /// + /// Observable string. /// The port names. - public static IObservable PortNames(int pollInterval = 500, int pollLimit = 0) => Observable.Create(obs => { + public static IObservable PortNames(int pollInterval = 500, int pollLimit = 0) => Observable.Create(obs => + { string[] compare = null; var numberOfPolls = 0; - return Observable.Interval(TimeSpan.FromMilliseconds(pollInterval)).Subscribe(_ => { + return Observable.Interval(TimeSpan.FromMilliseconds(pollInterval)).Subscribe(_ => + { var compareNew = SerialPort.GetPortNames(); - if (compareNew.Length == 0) { + if (compareNew.Length == 0) + { compareNew = new string[] { "NoPorts" }; } - if (compare == null) { + if (compare == null) + { compare = compareNew; obs.OnNext(compareNew); } - if (string.Concat(compare) != string.Concat(compareNew)) { + + if (string.Concat(compare) != string.Concat(compareNew)) + { obs.OnNext(compareNew); compare = compareNew; } - if (numberOfPolls > pollLimit) { + + if (numberOfPolls > pollLimit) + { obs.OnCompleted(); } - if (pollLimit > 0 && numberOfPolls < pollLimit) { + + if (pollLimit > 0 && numberOfPolls < pollLimit) + { numberOfPolls++; } }); @@ -349,11 +407,15 @@ public void Close() public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } /// /// Opens this instance. /// + /// + /// A Task. + /// public Task Open() { return disposablePort?.Count == 0 ? Task.Run(() => Connect.Subscribe().AddTo(disposablePort)) : Task.CompletedTask; @@ -426,8 +488,10 @@ public void WriteLine(string text) /// protected virtual void Dispose(bool disposing) { - if (!IsDisposed) { - if (disposing) { + if (!IsDisposed) + { + if (disposing) + { disposablePort?.Dispose(); } diff --git a/SerialPortRx/SerialPortRxMixins.cs b/SerialPortRx/SerialPortRxMixins.cs index 86c2fde..c71a7d0 100644 --- a/SerialPortRx/SerialPortRxMixins.cs +++ b/SerialPortRx/SerialPortRxMixins.cs @@ -1,17 +1,20 @@ -using System.Collections.Generic; +// +// Copyright (c) Chris Pulman. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.IO.Ports; +using System.Reactive; +using System.Reactive.Concurrency; +using System.Reactive.Disposables; +using System.Reactive.Linq; namespace CP.IO.Ports { - using System; - using System.IO.Ports; - using System.Reactive; - using System.Reactive.Concurrency; - using System.Reactive.Disposables; - using System.Reactive.Linq; - using System.Text; - /// - /// Serial Port Rx Mixins + /// Serial Port Rx Mixins. /// public static class SerialPortRxMixins { @@ -19,21 +22,21 @@ public static class SerialPortRxMixins /// transforms a byte into a single value Observable. /// /// The value. - /// An Observable char + /// An Observable char. public static IObservable AsObservable(this byte value) => Observable.Return(Convert.ToChar(value)); /// /// transforms a int into a single value Observable. /// /// The value. - /// An Observable char + /// An Observable char. public static IObservable AsObservable(this int value) => Observable.Return(Convert.ToChar(value)); /// /// transforms a short into a single value Observable. /// /// The value. - /// An Observable char + /// An Observable char. public static IObservable AsObservable(this short value) => Observable.Return(Convert.ToChar(value)); /// @@ -43,37 +46,44 @@ public static class SerialPortRxMixins /// The starts with. /// The ends with. /// The time out. - /// A string made up from the char values between the start and end chars - public static IObservable BufferUntil(this IObservable @this, IObservable startsWith, IObservable endsWith, int timeOut) => Observable.Create(o => { + /// A string made up from the char values between the start and end chars. + public static IObservable BufferUntil(this IObservable @this, IObservable startsWith, IObservable endsWith, int timeOut) => Observable.Create(o => + { var dis = new CompositeDisposable(); - var str = ""; + var str = string.Empty; var startFound = false; var elapsedTime = 0; var startsWithL = ' '; - startsWith.Subscribe(sw => { + startsWith.Subscribe(sw => + { startsWithL = sw; elapsedTime = 0; }).AddTo(dis); var endsWithL = ' '; var ewd = endsWith.Subscribe(ew => endsWithL = ew).AddTo(dis); - var sub = @this.Subscribe(s => { + var sub = @this.Subscribe(s => + { elapsedTime = 0; - if (startFound || s == startsWithL) { + if (startFound || s == startsWithL) + { startFound = true; str += s; - if (s == endsWithL) { + if (s == endsWithL) + { o.OnNext(str); startFound = false; - str = ""; + str = string.Empty; } } }).AddTo(dis); - Observable.Interval(TimeSpan.FromMilliseconds(1)).Subscribe(_ => { + Observable.Interval(TimeSpan.FromMilliseconds(1)).Subscribe(_ => + { elapsedTime++; - if (elapsedTime > timeOut) { + if (elapsedTime > timeOut) + { startFound = false; - str = ""; + str = string.Empty; elapsedTime = 0; } }).AddTo(dis); @@ -90,15 +100,17 @@ public static IObservable BufferUntil(this IObservable @this, IObs /// The ends with. /// The default value. /// The time out. - /// A string made up from the char values between the start and end chars - public static IObservable BufferUntil(this IObservable @this, IObservable startsWith, IObservable endsWith, IObservable defaultValue, int timeOut) => Observable.Create(o => { + /// A string made up from the char values between the start and end chars. + public static IObservable BufferUntil(this IObservable @this, IObservable startsWith, IObservable endsWith, IObservable defaultValue, int timeOut) => Observable.Create(o => + { var dis = new CompositeDisposable(); - var str = ""; + var str = string.Empty; var startFound = false; var elapsedTime = 0; var startsWithL = ' '; - startsWith.Subscribe(sw => { + startsWith.Subscribe(sw => + { startsWithL = sw; elapsedTime = 0; }).AddTo(dis); @@ -106,25 +118,30 @@ public static IObservable BufferUntil(this IObservable @this, IObs endsWith.Subscribe(ew => endsWithL = ew).AddTo(dis); var defaultValueL = string.Empty; defaultValue.Subscribe(dv => defaultValueL = dv).AddTo(dis); - @this.Subscribe(s => { + @this.Subscribe(s => + { elapsedTime = 0; - if (startFound || s == startsWithL) { + if (startFound || s == startsWithL) + { startFound = true; str += s; - if (s == endsWithL) { + if (s == endsWithL) + { o.OnNext(str); startFound = false; - str = ""; + str = string.Empty; } } }).AddTo(dis); - Observable.Interval(TimeSpan.FromMilliseconds(1)).Subscribe(_ => { + Observable.Interval(TimeSpan.FromMilliseconds(1)).Subscribe(_ => + { elapsedTime++; - if (elapsedTime > timeOut) { + if (elapsedTime > timeOut) + { o.OnNext(defaultValueL); startFound = false; - str = ""; + str = string.Empty; elapsedTime = 0; } }).AddTo(dis); @@ -136,31 +153,37 @@ public static IObservable BufferUntil(this IObservable @this, IObs /// Monitors the received observer. /// /// The this. - /// + /// Observable value. public static IObservable> DataReceivedObserver(this SerialPort @this) => Observable.FromEventPattern(h => @this.DataReceived += h, h => @this.DataReceived -= h); /// /// Monitors the Errors observer. /// /// The this. - /// + /// Observable value. public static IObservable> ErrorReceivedObserver(this SerialPort @this) => Observable.FromEventPattern(h => @this.ErrorReceived += h, h => @this.ErrorReceived -= h); /// /// Fors the each. /// - /// + /// The type. /// The this. - /// + /// Observable value. public static IObservable ForEach(this IObservable @this) => - Observable.Create(obs => { - return @this.Subscribe(list => { - foreach (var item in list) { - if (!EqualityComparer.Default.Equals(item, default)) { + Observable.Create(obs => + { + return @this.Subscribe( + list => + { + foreach (var item in list) + { + if (!EqualityComparer.Default.Equals(item, default)) + { obs.OnNext(item); } } - }, obs.OnError, obs.OnCompleted); + }, obs.OnError, + obs.OnCompleted); }); /// @@ -169,7 +192,7 @@ public static IObservable ForEach(this IObservable @this) => /// /// The type of the source. /// The source. - /// + /// Observable value. public static IObservable OnErrorRetry(this IObservable source) => source.Retry(); /// @@ -179,7 +202,7 @@ public static IObservable ForEach(this IObservable @this) => /// The type of the exception. /// The source. /// The on error. - /// + /// Observable value. public static IObservable OnErrorRetry(this IObservable source, Action onError) where TException : Exception => source.OnErrorRetry(onError, TimeSpan.Zero); @@ -191,7 +214,7 @@ public static IObservable OnErrorRetry(this IObser /// The source. /// The on error. /// The delay. - /// + /// Observable value. public static IObservable OnErrorRetry(this IObservable source, Action onError, TimeSpan delay) where TException : Exception => source.OnErrorRetry(onError, int.MaxValue, delay); @@ -203,7 +226,7 @@ public static IObservable OnErrorRetry(this IObser /// The source. /// The on error. /// The retry count. - /// + /// Observable value. public static IObservable OnErrorRetry(this IObservable source, Action onError, int retryCount) where TException : Exception => source.OnErrorRetry(onError, retryCount, TimeSpan.Zero); @@ -217,7 +240,7 @@ public static IObservable OnErrorRetry(this IObser /// The on error. /// The retry count. /// The delay. - /// + /// Observable value. public static IObservable OnErrorRetry(this IObservable source, Action onError, int retryCount, TimeSpan delay) where TException : Exception => source.OnErrorRetry(onError, retryCount, delay, Scheduler.Default); @@ -232,18 +255,20 @@ public static IObservable OnErrorRetry(this IObser /// The retry count. /// The delay. /// The delay scheduler. - /// + /// Observable value. public static IObservable OnErrorRetry( this IObservable source, Action onError, int retryCount, TimeSpan delay, IScheduler delayScheduler) where TException : Exception { - var result = Observable.Defer(() => { + var result = Observable.Defer(() => + { var dueTime = (delay.Ticks < 0) ? TimeSpan.Zero : delay; var empty = Observable.Empty(); var count = 0; IObservable self = null; - self = source.Catch((TException ex) => { + self = source.Catch((TException ex) => + { onError(ex); return (++count < retryCount) ? (dueTime == TimeSpan.Zero) @@ -263,9 +288,10 @@ public static IObservable OnErrorRetry( /// /// The serial port. /// The timespan at which to notify. - /// + /// Observable value. public static IObservable WhileIsOpen(this SerialPortRx @this, TimeSpan timespan) => - Observable.Defer(() => Observable.Create(obs => { + Observable.Defer(() => Observable.Create(obs => + { var isOpen = Observable.Interval(timespan).CombineLatest(@this.isOpen, (_, b) => b).Where(x => x); return isOpen.Subscribe(obs); })); diff --git a/appveyor.yml b/appveyor.yml index fbd66a8..5d24aae 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,4 +14,4 @@ artifacts: deploy: - provider: NuGet api_key: - secure: CIdiwHmj8amXRtjE0AwwlBSj55TGDg0yLqm/YthICWaUncKoJmYabpu2YqXIuOVd + secure: OQ4BOWt3gN84SnaLslkpd5hqTbkBPmV6UiiV/JDXXVoyZdeUaF2VTTyidEAwNpNI \ No newline at end of file