From 11e06e3b86026743b07c75f8f6d088f8649f367c Mon Sep 17 00:00:00 2001 From: IlyaChernov Date: Sun, 6 Sep 2020 15:00:11 +0300 Subject: [PATCH] Updated macro engine. Added Jint library, now macroses support variables, calculations and machine state. --- grbl Master.sln | 6 + grbl Master.sln.DotSettings | 7 +- .../{Implementation => }/GrblDispatcher.cs | 11 +- .../{Implementation => }/GrblPrompt.cs | 9 +- .../{Implementation => }/GrblStatus.cs | 43 +++--- grbl.Master.BL/grbl.Master.BL.csproj | 18 +-- .../Enum/ConnectionState.cs | 2 +- .../Interfaces/BL}/IGrblDispatcher.cs | 2 +- .../Interfaces/BL}/IGrblPrompt.cs | 2 +- .../Interfaces/BL}/IGrblStatus.cs | 11 +- .../Service}/IApplicationSettingsService.cs | 2 +- .../Interfaces/Service}/ICOMService.cs | 4 +- .../Interfaces/Service}/ICommandSender.cs | 11 +- .../Interfaces/Service}/IGCodeFileService.cs | 2 +- .../Service}/IGrblCommandPreProcessor.cs | 2 +- .../Service}/IGrblResponseTypeFinder.cs | 2 +- grbl.Master.Common/Properties/AssemblyInfo.cs | 35 +++++ grbl.Master.Common/app.config | 19 +++ grbl.Master.Common/grbl.Master.Common.csproj | 83 +++++++++++ grbl.Master.Common/packages.config | 9 ++ .../Attribute/ChangeCommandAttribute.cs | 4 +- .../Converters/EnumToDescription.cs | 5 +- .../Enum/CommandSourceRunMode.cs | 1 + grbl.Master.Model/Enum/CommandSourceType.cs | 1 + ...nsation.cs => CutterRadiusCompensation.cs} | 2 +- grbl.Master.Model/GrblSettings.cs | 7 +- grbl.Master.Model/GrblStatusModel.cs | 8 +- .../Interface/IGrblStatusModel.cs | 93 ++++++++++++ grbl.Master.Model/Macros.cs | 3 + grbl.Master.Model/grbl.Master.Model.csproj | 12 +- grbl.Master.Model/packages.config | 1 + .../ApplicationSettingsService.cs | 11 +- .../{Implementation => }/COMService.cs | 64 +++++---- .../{Implementation => }/CommandSender.cs | 68 +++++---- grbl.Master.Service/Enum/EnumHelper.cs | 2 +- .../{Implementation => }/GCodeFileService.cs | 8 +- .../GrblCommandPreProcessor.cs | 133 ++++++++++++++++++ .../GrblResponseTypeFinder.cs | 4 +- .../Implementation/GrblCommandPreProcessor.cs | 80 ----------- .../grbl.Master.Service.csproj | 32 ++--- grbl.Master.Service/packages.config | 1 + grbl.Master.UI/Bootstrapper.cs | 15 +- .../Converters/EnumToDescription.cs | 19 +-- .../Converters/IntegerMask3ToDescription.cs | 12 +- .../Converters/IntegerToBinaryString.cs | 2 +- .../Converters/ListDoubleToString.cs | 2 +- grbl.Master.UI/Input/KeyTrigger.cs | 6 +- .../ViewModels/COMConnectionViewModel.cs | 8 +- grbl.Master.UI/ViewModels/MasterViewModel.cs | 60 ++++++-- grbl.Master.UI/Views/MasterView.xaml | 100 ++++++++++++- grbl.Master.UI/grbl.Master.UI.csproj | 4 + grbl.Master.Utilities/XMLSerializerUtil.cs | 8 +- 52 files changed, 756 insertions(+), 300 deletions(-) rename grbl.Master.BL/{Implementation => }/GrblDispatcher.cs (88%) rename grbl.Master.BL/{Implementation => }/GrblPrompt.cs (78%) rename grbl.Master.BL/{Implementation => }/GrblStatus.cs (98%) rename {grbl.Master.Service => grbl.Master.Common}/Enum/ConnectionState.cs (67%) rename {grbl.Master.BL/Interface => grbl.Master.Common/Interfaces/BL}/IGrblDispatcher.cs (57%) rename {grbl.Master.BL/Interface => grbl.Master.Common/Interfaces/BL}/IGrblPrompt.cs (71%) rename {grbl.Master.BL/Interface => grbl.Master.Common/Interfaces/BL}/IGrblStatus.cs (59%) rename {grbl.Master.Service/Interface => grbl.Master.Common/Interfaces/Service}/IApplicationSettingsService.cs (80%) rename {grbl.Master.Service/Interface => grbl.Master.Common/Interfaces/Service}/ICOMService.cs (84%) rename {grbl.Master.Service/Interface => grbl.Master.Common/Interfaces/Service}/ICommandSender.cs (67%) rename {grbl.Master.Service/Interface => grbl.Master.Common/Interfaces/Service}/IGCodeFileService.cs (74%) rename {grbl.Master.Service/Interface => grbl.Master.Common/Interfaces/Service}/IGrblCommandPreProcessor.cs (72%) rename {grbl.Master.Service/Interface => grbl.Master.Common/Interfaces/Service}/IGrblResponseTypeFinder.cs (73%) create mode 100644 grbl.Master.Common/Properties/AssemblyInfo.cs create mode 100644 grbl.Master.Common/app.config create mode 100644 grbl.Master.Common/grbl.Master.Common.csproj create mode 100644 grbl.Master.Common/packages.config rename grbl.Master.Model/Enum/{CutterRaduisCompensation.cs => CutterRadiusCompensation.cs} (87%) create mode 100644 grbl.Master.Model/Interface/IGrblStatusModel.cs rename grbl.Master.Service/{Implementation => }/ApplicationSettingsService.cs (96%) rename grbl.Master.Service/{Implementation => }/COMService.cs (70%) rename grbl.Master.Service/{Implementation => }/CommandSender.cs (80%) rename grbl.Master.Service/{Implementation => }/GCodeFileService.cs (96%) create mode 100644 grbl.Master.Service/GrblCommandPreProcessor.cs rename grbl.Master.Service/{Implementation => }/GrblResponseTypeFinder.cs (97%) delete mode 100644 grbl.Master.Service/Implementation/GrblCommandPreProcessor.cs diff --git a/grbl Master.sln b/grbl Master.sln index 9238660..5792635 100644 --- a/grbl Master.sln +++ b/grbl Master.sln @@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "grbl.Master.BL", "grbl.Mast EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "grbl.Master.Utilities", "grbl.Master.Utilities\grbl.Master.Utilities.csproj", "{9FE0DAFE-CC25-420D-9909-F4D53FD966B0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "grbl.Master.Common", "grbl.Master.Common\grbl.Master.Common.csproj", "{292BC2BE-A547-4567-8592-9CE4D9290E54}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {9FE0DAFE-CC25-420D-9909-F4D53FD966B0}.Debug|Any CPU.Build.0 = Debug|Any CPU {9FE0DAFE-CC25-420D-9909-F4D53FD966B0}.Release|Any CPU.ActiveCfg = Release|Any CPU {9FE0DAFE-CC25-420D-9909-F4D53FD966B0}.Release|Any CPU.Build.0 = Release|Any CPU + {292BC2BE-A547-4567-8592-9CE4D9290E54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {292BC2BE-A547-4567-8592-9CE4D9290E54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {292BC2BE-A547-4567-8592-9CE4D9290E54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {292BC2BE-A547-4567-8592-9CE4D9290E54}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/grbl Master.sln.DotSettings b/grbl Master.sln.DotSettings index fc453e1..d865ccb 100644 --- a/grbl Master.sln.DotSettings +++ b/grbl Master.sln.DotSettings @@ -1,7 +1,12 @@  COM EEPROM + NA XML + True + True True True - True \ No newline at end of file + True + True + True \ No newline at end of file diff --git a/grbl.Master.BL/Implementation/GrblDispatcher.cs b/grbl.Master.BL/GrblDispatcher.cs similarity index 88% rename from grbl.Master.BL/Implementation/GrblDispatcher.cs rename to grbl.Master.BL/GrblDispatcher.cs index 5c53036..0f6bbd7 100644 --- a/grbl.Master.BL/Implementation/GrblDispatcher.cs +++ b/grbl.Master.BL/GrblDispatcher.cs @@ -1,11 +1,12 @@ -namespace grbl.Master.BL.Implementation +namespace grbl.Master.BL { - using grbl.Master.BL.Interface; - using grbl.Master.Model.Enum; - using grbl.Master.Service.Enum; - using grbl.Master.Service.Interface; using System; + using grbl.Master.Common.Enum; + using grbl.Master.Common.Interfaces.BL; + using grbl.Master.Common.Interfaces.Service; + using grbl.Master.Model.Enum; + public class GrblDispatcher : IGrblDispatcher { private readonly IGrblStatus _grblStatus; diff --git a/grbl.Master.BL/Implementation/GrblPrompt.cs b/grbl.Master.BL/GrblPrompt.cs similarity index 78% rename from grbl.Master.BL/Implementation/GrblPrompt.cs rename to grbl.Master.BL/GrblPrompt.cs index d61c28c..d412693 100644 --- a/grbl.Master.BL/Implementation/GrblPrompt.cs +++ b/grbl.Master.BL/GrblPrompt.cs @@ -1,15 +1,16 @@ -namespace grbl.Master.BL.Implementation +namespace grbl.Master.BL { - using grbl.Master.BL.Interface; - using grbl.Master.Service.Interface; using System; using System.Text.RegularExpressions; + using grbl.Master.Common.Interfaces.BL; + using grbl.Master.Common.Interfaces.Service; + public class GrblPrompt : IGrblPrompt { private const string PromptTag = "^Grbl.{6}\\[.*\\]$"; - readonly Regex _promptReg = new Regex(PromptTag); + private readonly Regex _promptReg = new Regex(PromptTag); public GrblPrompt(IComService comService) { diff --git a/grbl.Master.BL/Implementation/GrblStatus.cs b/grbl.Master.BL/GrblStatus.cs similarity index 98% rename from grbl.Master.BL/Implementation/GrblStatus.cs rename to grbl.Master.BL/GrblStatus.cs index 24c847d..eb4670f 100644 --- a/grbl.Master.BL/Implementation/GrblStatus.cs +++ b/grbl.Master.BL/GrblStatus.cs @@ -1,10 +1,5 @@ -namespace grbl.Master.BL.Implementation +namespace grbl.Master.BL { - using grbl.Master.BL.Interface; - using grbl.Master.Model; - using grbl.Master.Model.Enum; - using grbl.Master.Service.Enum; - using grbl.Master.Service.Interface; using System; using System.Collections.Generic; using System.Linq; @@ -14,13 +9,22 @@ using System.Text.RegularExpressions; using System.Threading; + using grbl.Master.Common.Enum; + using grbl.Master.Common.Interfaces.BL; + using grbl.Master.Common.Interfaces.Service; + using grbl.Master.Model; + using grbl.Master.Model.Enum; + using grbl.Master.Model.Interface; + public class GrblStatus : IGrblStatus { private readonly ICommandSender _commandSender; + //private readonly IGrblStatusModel _grblStatusModel; + private readonly string _decimalSeparator = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator; - readonly Subject _stopSubject = new Subject(); + private readonly Subject _stopSubject = new Subject(); private struct ResponseProcessingDefinition { @@ -45,9 +49,10 @@ private string TranslateMessageKey(string key) return Model.Resources.Mssages.ResourceManager.GetString(key); } - public GrblStatus(IComService comService, ICommandSender commandSender) + public GrblStatus(IComService comService, ICommandSender commandSender, IGrblStatusModel grblStatusModel) { _commandSender = commandSender; + GrblStatusModel = grblStatusModel; comService.ConnectionStateChanged += ComServiceConnectionStateChanged; _commandSender.ResponseReceived += CommandSenderResponseReceived; @@ -84,10 +89,10 @@ public GrblStatus(IComService comService, ICommandSender commandSender) var setting = new GrblSetting { Index = index, - Value = parts[1], + Value = parts[1], OriginalValue = parts[1] }; - + GrblStatusModel.Settings.AddOrUpdate(setting); } } @@ -97,7 +102,7 @@ public GrblStatus(IComService comService, ICommandSender commandSender) { ResponseType.FeedbackMessage, new ResponseProcessingDefinition { SplitAction =s =>s.Split(new[]{'[', ']'},StringSplitOptions.RemoveEmptyEntries), - ProcessActions = new List{new ResponseProcessor() + ProcessActions = new List{new ResponseProcessor { TagExpression = "MSG:.*", Action = s => @@ -109,7 +114,7 @@ public GrblStatus(IComService comService, ICommandSender commandSender) { ResponseType.HelpMessage, new ResponseProcessingDefinition { SplitAction =s =>s.Split(new[]{'[', ']'},StringSplitOptions.RemoveEmptyEntries), - ProcessActions = new List{new ResponseProcessor() + ProcessActions = new List{new ResponseProcessor { TagExpression = "HLP:.*", Action = s => @@ -120,7 +125,7 @@ public GrblStatus(IComService comService, ICommandSender commandSender) }}, { ResponseType.Error, new ResponseProcessingDefinition { - ProcessActions = new List{new ResponseProcessor() + ProcessActions = new List{new ResponseProcessor { TagExpression = "error:.*", Action = s => @@ -258,7 +263,7 @@ public GrblStatus(IComService comService, ICommandSender commandSender) if (accessoryParts.Length == 2) { if(accessoryParts[1].Contains('S')) - { + { GrblStatusModel.AccessoryState.Spindle = SpindleState.M3; } else if(accessoryParts[1].Contains('C')) @@ -294,12 +299,12 @@ public GrblStatus(IComService comService, ICommandSender commandSender) part => { var lineParts = part.Split(new[] { ':', '[', ']' }, StringSplitOptions.RemoveEmptyEntries); - if (ParsePosition(part, out var position)) + if (ParsePosition(part.Remove(part.Length-2), out var position)) { GrblStatusModel.ProbePosition.Update(position); } - if (lineParts.Length == 5 && int.TryParse(lineParts.Last().Trim(), out var probingResult)) + if (lineParts.Length == 3 && int.TryParse(lineParts.Last().Trim(), out var probingResult)) { GrblStatusModel.ProbeState = probingResult!= 0; } @@ -428,8 +433,8 @@ public GrblStatus(IComService comService, ICommandSender commandSender) new ResponseProcessor{TagExpression = "^G40$", Action = s => { - Enum.TryParse(s.Replace('.', '_'), true, out var result); - GrblStatusModel.CutterRaduisCompensation = result; + Enum.TryParse(s.Replace('.', '_'), true, out var result); + GrblStatusModel.CutterRadiusCompensation = result; }}, new ResponseProcessor{TagExpression = "^G4(3\\.1|9)$", Action = s => @@ -496,7 +501,7 @@ private void CommandSenderResponseReceived(object sender, Response e) } } - public GrblStatusModel GrblStatusModel { get; set; } = new GrblStatusModel(); + public IGrblStatusModel GrblStatusModel { get; } //=> _grblStatusModel; // { get; set; } = new GrblStatusModel(); private bool _isRunning; diff --git a/grbl.Master.BL/grbl.Master.BL.csproj b/grbl.Master.BL/grbl.Master.BL.csproj index 2229e8f..3b67cee 100644 --- a/grbl.Master.BL/grbl.Master.BL.csproj +++ b/grbl.Master.BL/grbl.Master.BL.csproj @@ -49,27 +49,23 @@ ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll - - - - - - - + + + + + {292BC2BE-A547-4567-8592-9CE4D9290E54} + grbl.Master.Common + {B21C205E-5CE2-436E-AFA4-F2A3DAC60D21} grbl.Master.Model - - {5233400E-E720-4DE5-8BED-6B11F2AE14C6} - grbl.Master.Service - diff --git a/grbl.Master.Service/Enum/ConnectionState.cs b/grbl.Master.Common/Enum/ConnectionState.cs similarity index 67% rename from grbl.Master.Service/Enum/ConnectionState.cs rename to grbl.Master.Common/Enum/ConnectionState.cs index 03277fd..e9159c8 100644 --- a/grbl.Master.Service/Enum/ConnectionState.cs +++ b/grbl.Master.Common/Enum/ConnectionState.cs @@ -1,4 +1,4 @@ -namespace grbl.Master.Service.Enum +namespace grbl.Master.Common.Enum { public enum ConnectionState { diff --git a/grbl.Master.BL/Interface/IGrblDispatcher.cs b/grbl.Master.Common/Interfaces/BL/IGrblDispatcher.cs similarity index 57% rename from grbl.Master.BL/Interface/IGrblDispatcher.cs rename to grbl.Master.Common/Interfaces/BL/IGrblDispatcher.cs index b787627..edefb6d 100644 --- a/grbl.Master.BL/Interface/IGrblDispatcher.cs +++ b/grbl.Master.Common/Interfaces/BL/IGrblDispatcher.cs @@ -1,4 +1,4 @@ -namespace grbl.Master.BL.Interface +namespace grbl.Master.Common.Interfaces.BL { public interface IGrblDispatcher { diff --git a/grbl.Master.BL/Interface/IGrblPrompt.cs b/grbl.Master.Common/Interfaces/BL/IGrblPrompt.cs similarity index 71% rename from grbl.Master.BL/Interface/IGrblPrompt.cs rename to grbl.Master.Common/Interfaces/BL/IGrblPrompt.cs index cef9903..13737cb 100644 --- a/grbl.Master.BL/Interface/IGrblPrompt.cs +++ b/grbl.Master.Common/Interfaces/BL/IGrblPrompt.cs @@ -1,4 +1,4 @@ -namespace grbl.Master.BL.Interface +namespace grbl.Master.Common.Interfaces.BL { using System; diff --git a/grbl.Master.BL/Interface/IGrblStatus.cs b/grbl.Master.Common/Interfaces/BL/IGrblStatus.cs similarity index 59% rename from grbl.Master.BL/Interface/IGrblStatus.cs rename to grbl.Master.Common/Interfaces/BL/IGrblStatus.cs index 800ce6c..9bf4376 100644 --- a/grbl.Master.BL/Interface/IGrblStatus.cs +++ b/grbl.Master.Common/Interfaces/BL/IGrblStatus.cs @@ -1,19 +1,20 @@ -namespace grbl.Master.BL.Interface +namespace grbl.Master.Common.Interfaces.BL { - using System; - using grbl.Master.Model; + using System; + + using grbl.Master.Model.Interface; public interface IGrblStatus { void StartRequesting(TimeSpan positionsInterval, TimeSpan gStateInterval,TimeSpan offsetsInterval); void InitialRequest(); - void StopRequesting(); + void StopRequesting(); //bool IsRunning //{ // get; //} - GrblStatusModel GrblStatusModel { get; set; } + IGrblStatusModel GrblStatusModel { get; } } } diff --git a/grbl.Master.Service/Interface/IApplicationSettingsService.cs b/grbl.Master.Common/Interfaces/Service/IApplicationSettingsService.cs similarity index 80% rename from grbl.Master.Service/Interface/IApplicationSettingsService.cs rename to grbl.Master.Common/Interfaces/Service/IApplicationSettingsService.cs index 9512aba..ced9280 100644 --- a/grbl.Master.Service/Interface/IApplicationSettingsService.cs +++ b/grbl.Master.Common/Interfaces/Service/IApplicationSettingsService.cs @@ -1,4 +1,4 @@ -namespace grbl.Master.Service.Interface +namespace grbl.Master.Common.Interfaces.Service { using grbl.Master.Model; diff --git a/grbl.Master.Service/Interface/ICOMService.cs b/grbl.Master.Common/Interfaces/Service/ICOMService.cs similarity index 84% rename from grbl.Master.Service/Interface/ICOMService.cs rename to grbl.Master.Common/Interfaces/Service/ICOMService.cs index e1cd254..9a95735 100644 --- a/grbl.Master.Service/Interface/ICOMService.cs +++ b/grbl.Master.Common/Interfaces/Service/ICOMService.cs @@ -1,9 +1,9 @@ -namespace grbl.Master.Service.Interface +namespace grbl.Master.Common.Interfaces.Service { using System; using System.Collections.Generic; - using grbl.Master.Service.Enum; + using grbl.Master.Common.Enum; public interface IComService { diff --git a/grbl.Master.Service/Interface/ICommandSender.cs b/grbl.Master.Common/Interfaces/Service/ICommandSender.cs similarity index 67% rename from grbl.Master.Service/Interface/ICommandSender.cs rename to grbl.Master.Common/Interfaces/Service/ICommandSender.cs index e9c5e31..cd4d5eb 100644 --- a/grbl.Master.Service/Interface/ICommandSender.cs +++ b/grbl.Master.Common/Interfaces/Service/ICommandSender.cs @@ -1,4 +1,4 @@ -namespace grbl.Master.Service.Interface +namespace grbl.Master.Common.Interfaces.Service { using System; using System.Collections.ObjectModel; @@ -7,10 +7,15 @@ public interface ICommandSender { + event EventHandler CommandQueueLengthChanged; + CommandSource SystemCommands { get; } - CommandSource ManualCommands { get; } + CommandSource ManualCommands { get; } + CommandSource MacroCommands { get; } CommandSource FileCommands { get; } + int CommandQueueLength { get; } + ObservableCollection CommunicationLog { get; @@ -24,7 +29,7 @@ ObservableCollection CommunicationLog void Send(string command, string onResult = null); - Command Prepare(string command); + //Command Prepare(string command); void PurgeQueues(); } diff --git a/grbl.Master.Service/Interface/IGCodeFileService.cs b/grbl.Master.Common/Interfaces/Service/IGCodeFileService.cs similarity index 74% rename from grbl.Master.Service/Interface/IGCodeFileService.cs rename to grbl.Master.Common/Interfaces/Service/IGCodeFileService.cs index c34469e..8729b3e 100644 --- a/grbl.Master.Service/Interface/IGCodeFileService.cs +++ b/grbl.Master.Common/Interfaces/Service/IGCodeFileService.cs @@ -1,4 +1,4 @@ -namespace grbl.Master.Service.Interface +namespace grbl.Master.Common.Interfaces.Service { using grbl.Master.Model; diff --git a/grbl.Master.Service/Interface/IGrblCommandPreProcessor.cs b/grbl.Master.Common/Interfaces/Service/IGrblCommandPreProcessor.cs similarity index 72% rename from grbl.Master.Service/Interface/IGrblCommandPreProcessor.cs rename to grbl.Master.Common/Interfaces/Service/IGrblCommandPreProcessor.cs index 797fa98..ac9ef28 100644 --- a/grbl.Master.Service/Interface/IGrblCommandPreProcessor.cs +++ b/grbl.Master.Common/Interfaces/Service/IGrblCommandPreProcessor.cs @@ -1,4 +1,4 @@ -namespace grbl.Master.Service.Interface +namespace grbl.Master.Common.Interfaces.Service { using grbl.Master.Model; diff --git a/grbl.Master.Service/Interface/IGrblResponseTypeFinder.cs b/grbl.Master.Common/Interfaces/Service/IGrblResponseTypeFinder.cs similarity index 73% rename from grbl.Master.Service/Interface/IGrblResponseTypeFinder.cs rename to grbl.Master.Common/Interfaces/Service/IGrblResponseTypeFinder.cs index f319acc..bb4d69d 100644 --- a/grbl.Master.Service/Interface/IGrblResponseTypeFinder.cs +++ b/grbl.Master.Common/Interfaces/Service/IGrblResponseTypeFinder.cs @@ -1,4 +1,4 @@ -namespace grbl.Master.Service.Interface +namespace grbl.Master.Common.Interfaces.Service { using grbl.Master.Model.Enum; diff --git a/grbl.Master.Common/Properties/AssemblyInfo.cs b/grbl.Master.Common/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0262776 --- /dev/null +++ b/grbl.Master.Common/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +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("grbl.Master.Common")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("grbl.Master.Common")] +[assembly: AssemblyCopyright("Copyright © 2020")] +[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("292bc2be-a547-4567-8592-9ce4d9290e54")] + +// 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/grbl.Master.Common/app.config b/grbl.Master.Common/app.config new file mode 100644 index 0000000..33ded1e --- /dev/null +++ b/grbl.Master.Common/app.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/grbl.Master.Common/grbl.Master.Common.csproj b/grbl.Master.Common/grbl.Master.Common.csproj new file mode 100644 index 0000000..0c3d4ce --- /dev/null +++ b/grbl.Master.Common/grbl.Master.Common.csproj @@ -0,0 +1,83 @@ + + + + + Debug + AnyCPU + {292BC2BE-A547-4567-8592-9CE4D9290E54} + Library + Properties + grbl.Master.Common + grbl.Master.Common + v4.8 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Meziantou.Framework.WPF.1.1.0\lib\net461\Meziantou.Framework.WPF.dll + + + + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + + ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + + + + + + + + + + + + + + + + {B21C205E-5CE2-436E-AFA4-F2A3DAC60D21} + grbl.Master.Model + + + + + + + + + + + \ No newline at end of file diff --git a/grbl.Master.Common/packages.config b/grbl.Master.Common/packages.config new file mode 100644 index 0000000..a181048 --- /dev/null +++ b/grbl.Master.Common/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/grbl.Master.Model/Attribute/ChangeCommandAttribute.cs b/grbl.Master.Model/Attribute/ChangeCommandAttribute.cs index b4230aa..68d6dd6 100644 --- a/grbl.Master.Model/Attribute/ChangeCommandAttribute.cs +++ b/grbl.Master.Model/Attribute/ChangeCommandAttribute.cs @@ -5,11 +5,11 @@ [AttributeUsage(AttributeTargets.All)] public class ChangeCommandAttribute : Attribute { - public string Comand { get; internal set; } + public string Command { get; internal set; } public ChangeCommandAttribute(string command) { - Comand = command; + this.Command = command; } } } diff --git a/grbl.Master.Model/Converters/EnumToDescription.cs b/grbl.Master.Model/Converters/EnumToDescription.cs index 297a520..77dbcbe 100644 --- a/grbl.Master.Model/Converters/EnumToDescription.cs +++ b/grbl.Master.Model/Converters/EnumToDescription.cs @@ -2,7 +2,6 @@ { using System; using System.ComponentModel; - using System.Reflection; public class EnumToDescription : EnumConverter { @@ -17,11 +16,11 @@ public override object ConvertTo(ITypeDescriptorContext context, System.Globaliz { if (value != null) { - FieldInfo fi = value.GetType().GetField(value.ToString()); + var fi = value.GetType().GetField(value.ToString()); if (fi != null) { var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); - return (attributes.Length > 0) && (!string.IsNullOrEmpty(attributes[0].Description)) ? attributes[0].Description : value.ToString(); + return attributes.Length > 0 && !string.IsNullOrEmpty(attributes[0].Description) ? attributes[0].Description : value.ToString(); } } diff --git a/grbl.Master.Model/Enum/CommandSourceRunMode.cs b/grbl.Master.Model/Enum/CommandSourceRunMode.cs index 742c312..cfbdc4f 100644 --- a/grbl.Master.Model/Enum/CommandSourceRunMode.cs +++ b/grbl.Master.Model/Enum/CommandSourceRunMode.cs @@ -4,6 +4,7 @@ public enum CommandSourceRunMode { Infinite, StopInTheEnd, + LineByOk, LineByLine } } diff --git a/grbl.Master.Model/Enum/CommandSourceType.cs b/grbl.Master.Model/Enum/CommandSourceType.cs index 7f5aeab..4ad2fcb 100644 --- a/grbl.Master.Model/Enum/CommandSourceType.cs +++ b/grbl.Master.Model/Enum/CommandSourceType.cs @@ -4,6 +4,7 @@ public enum CommandSourceType { System, Manual, + Macros, File } } diff --git a/grbl.Master.Model/Enum/CutterRaduisCompensation.cs b/grbl.Master.Model/Enum/CutterRadiusCompensation.cs similarity index 87% rename from grbl.Master.Model/Enum/CutterRaduisCompensation.cs rename to grbl.Master.Model/Enum/CutterRadiusCompensation.cs index 386c08f..b4d5430 100644 --- a/grbl.Master.Model/Enum/CutterRaduisCompensation.cs +++ b/grbl.Master.Model/Enum/CutterRadiusCompensation.cs @@ -7,7 +7,7 @@ namespace grbl.Master.Model.Enum using grbl.Master.Model.Converters; [TypeConverter(typeof(EnumToDescription))] - public enum CutterRaduisCompensation + public enum CutterRadiusCompensation { [Description("Disabled")] G40 diff --git a/grbl.Master.Model/GrblSettings.cs b/grbl.Master.Model/GrblSettings.cs index 7f72dfe..b4cb914 100644 --- a/grbl.Master.Model/GrblSettings.cs +++ b/grbl.Master.Model/GrblSettings.cs @@ -72,12 +72,7 @@ public void AddOrUpdate(GrblSetting setting) private GrblSettingType FindType(int index) { - if (_typeTable.Any(x => x.Value.Any(y => y == index))) - { - return _typeTable.FirstOrDefault(x => x.Value.Any(y => y == index)).Key; - } - - return GrblSettingType.Integer; + return this._typeTable.Any(x => x.Value.Any(y => y == index)) ? this._typeTable.FirstOrDefault(x => x.Value.Any(y => y == index)).Key : GrblSettingType.Integer; } } } diff --git a/grbl.Master.Model/GrblStatusModel.cs b/grbl.Master.Model/GrblStatusModel.cs index 41879ba..a903a1a 100644 --- a/grbl.Master.Model/GrblStatusModel.cs +++ b/grbl.Master.Model/GrblStatusModel.cs @@ -5,7 +5,9 @@ using System; using System.Linq; - public class GrblStatusModel : NotifyPropertyChanged + using grbl.Master.Model.Interface; + + public class GrblStatusModel : NotifyPropertyChanged, IGrblStatusModel { public event EventHandler MachineStateChanged; @@ -60,7 +62,7 @@ public MachineState MachineState public UnitsMode UnitsMode { get; set; } - public CutterRaduisCompensation CutterRaduisCompensation { get; set; } + public CutterRadiusCompensation CutterRadiusCompensation { get; set; } public ToolLengthMode ToolLengthMode { get; set; } @@ -70,7 +72,7 @@ public MachineState MachineState public CoolantState CoolantState { get; set; } - public virtual void OnMachineStateChanged() + private void OnMachineStateChanged() { MachineStateChanged?.Invoke(this, MachineState); } diff --git a/grbl.Master.Model/Interface/IGrblStatusModel.cs b/grbl.Master.Model/Interface/IGrblStatusModel.cs new file mode 100644 index 0000000..ebd8fea --- /dev/null +++ b/grbl.Master.Model/Interface/IGrblStatusModel.cs @@ -0,0 +1,93 @@ +namespace grbl.Master.Model.Interface +{ + using System; + using System.ComponentModel; + + using grbl.Master.Model; + using grbl.Master.Model.Enum; + + using Meziantou.Framework.WPF.Collections; + + public interface IGrblStatusModel + { + event EventHandler MachineStateChanged; + + ConcurrentObservableCollection Messages { get; } + + GrblSettings Settings { get; } + + string LastMessage { get; set; } + + MachineState MachineState { get; set; } + + MotionMode MotionMode { get; set; } + + CoordinateSystem CoordinateSystem { get; set; } + + ActivePlane ActivePlane { get; set; } + + DistanceMode DistanceMode { get; set; } + + ArcDistanceMode ArcDistanceMode { get; set; } + + FeedRateMode FeedRateMode { get; set; } + + UnitsMode UnitsMode { get; set; } + + CutterRadiusCompensation CutterRadiusCompensation { get; set; } + + ToolLengthMode ToolLengthMode { get; set; } + + ProgramMode ProgramMode { get; set; } + + SpindleState SpindleState { get; set; } + + CoolantState CoolantState { get; set; } + + Position MachinePosition { get; set; } + + Position WorkPosition { get; set; } + + decimal ToolLengthOffset { get; set; } + + bool ProbeState { get; set; } + + Position ProbePosition { get; set; } + + Position G54Position { get; set; } + + Position G55Position { get; set; } + + Position G56Position { get; set; } + + Position G57Position { get; set; } + + Position G58Position { get; set; } + + Position G59Position { get; set; } + + Position G28Position { get; set; } + + Position G30Position { get; set; } + + Position G92Position { get; set; } + + Position WorkOffset { get; set; } + + BufferState BufferState { get; set; } + + long LineNumber { get; set; } + + FeedAndSpeed FeedAndSpeed { get; set; } + + InputPinState InputPinState { get; set; } + + OverrideValues OverrideValues { get; set; } + + AccessoryState AccessoryState { get; set; } + + //void OnMachineStateChanged(); + + event PropertyChangedEventHandler PropertyChanged; + } +} \ No newline at end of file diff --git a/grbl.Master.Model/Macros.cs b/grbl.Master.Model/Macros.cs index 468d5e1..00063f4 100644 --- a/grbl.Master.Model/Macros.cs +++ b/grbl.Master.Model/Macros.cs @@ -1,6 +1,7 @@ namespace grbl.Master.Model { using System; + using System.Windows.Media; [Serializable] public class Macros @@ -10,5 +11,7 @@ public class Macros public string Command { get; set; } public int Index { get; set; } = -1; + + public Color? Color { get; set; } = null; } } diff --git a/grbl.Master.Model/grbl.Master.Model.csproj b/grbl.Master.Model/grbl.Master.Model.csproj index 2e305db..ef26c34 100644 --- a/grbl.Master.Model/grbl.Master.Model.csproj +++ b/grbl.Master.Model/grbl.Master.Model.csproj @@ -43,9 +43,14 @@ ..\packages\JetBrains.Annotations.2019.1.3\lib\net20\JetBrains.Annotations.dll + + ..\packages\Jint.2.11.58\lib\net451\Jint.dll + ..\packages\Meziantou.Framework.WPF.1.1.0\lib\net461\Meziantou.Framework.WPF.dll + + ..\packages\PropertyChanged.Fody.3.2.6\lib\net40\PropertyChanged.dll @@ -58,10 +63,10 @@ ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll - ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll @@ -78,8 +83,8 @@ ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll - + @@ -107,7 +112,7 @@ - + @@ -117,6 +122,7 @@ + diff --git a/grbl.Master.Model/packages.config b/grbl.Master.Model/packages.config index 040331f..98c74f4 100644 --- a/grbl.Master.Model/packages.config +++ b/grbl.Master.Model/packages.config @@ -3,6 +3,7 @@ + diff --git a/grbl.Master.Service/Implementation/ApplicationSettingsService.cs b/grbl.Master.Service/ApplicationSettingsService.cs similarity index 96% rename from grbl.Master.Service/Implementation/ApplicationSettingsService.cs rename to grbl.Master.Service/ApplicationSettingsService.cs index c7cd4a2..59d61f8 100644 --- a/grbl.Master.Service/Implementation/ApplicationSettingsService.cs +++ b/grbl.Master.Service/ApplicationSettingsService.cs @@ -1,14 +1,15 @@ -namespace grbl.Master.Service.Implementation +namespace grbl.Master.Service { - using grbl.Master.Model; - using grbl.Master.Service.Interface; - using grbl.Master.Utilities; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; + using grbl.Master.Common.Interfaces.Service; + using grbl.Master.Model; + using grbl.Master.Utilities; + public class ApplicationSettingsService : IApplicationSettingsService { public ApplicationSettings Settings { get; internal set; } = new ApplicationSettings(); @@ -49,7 +50,7 @@ private string ListDoubleToString(IEnumerable value) { if (value is { } elements) { - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); foreach (var element in elements) { sb.AppendLine(element.ToString()); diff --git a/grbl.Master.Service/Implementation/COMService.cs b/grbl.Master.Service/COMService.cs similarity index 70% rename from grbl.Master.Service/Implementation/COMService.cs rename to grbl.Master.Service/COMService.cs index f51c380..8f895d3 100644 --- a/grbl.Master.Service/Implementation/COMService.cs +++ b/grbl.Master.Service/COMService.cs @@ -1,7 +1,5 @@ -namespace grbl.Master.Service.Implementation +namespace grbl.Master.Service { - using grbl.Master.Service.Enum; - using grbl.Master.Service.Interface; using System; using System.Collections.Generic; using System.IO.Ports; @@ -11,11 +9,13 @@ using System.Reactive.Subjects; using System.Text; + using grbl.Master.Common.Enum; + using grbl.Master.Common.Interfaces.Service; using grbl.Master.Utilities; public class COMService : IComService { - readonly SerialPort _sp = new SerialPort(); + private readonly SerialPort _sp = new SerialPort(); public event EventHandler LineReceived; @@ -23,7 +23,7 @@ public class COMService : IComService private string _buffer = ""; - readonly Subject _stopSubject = new Subject(); + private readonly Subject _stopSubject = new Subject(); public virtual void OnLineReceived(string e) { @@ -80,34 +80,38 @@ private void PortMonitoring() private void SpDataReceived(object sender, SerialDataReceivedEventArgs e) { - var cnt = _sp.BytesToRead; - byte[] buffer = new byte[cnt]; - if (!IsConnected) + if (_sp.IsOpen) { - throw new InvalidOperationException("Serial port is closed."); - } - _sp.Read(buffer, 0, cnt); + var cnt = _sp.BytesToRead; + var buffer = new byte[cnt]; + if (!IsConnected) + { + throw new InvalidOperationException("Serial port is closed."); + } - var serialData = Encoding.UTF8.GetString(buffer); + _sp.Read(buffer, 0, cnt); - var lines = (_buffer + serialData).Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + var serialData = Encoding.UTF8.GetString(buffer); - if (lines.Any()) - { - if (lines.Last() == string.Empty) + var lines = (_buffer + serialData).Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); + + if (lines.Any()) { - _buffer = string.Empty; - foreach (var line in lines) + if (lines.Last() == string.Empty) { - OnLineReceived(line); + _buffer = string.Empty; + foreach (var line in lines) + { + OnLineReceived(line); + } } - } - else - { - _buffer = lines.Last(); - foreach (var line in lines.Take(lines.Length - 1)) + else { - OnLineReceived(line); + _buffer = lines.Last(); + foreach (var line in lines.Take(lines.Length - 1)) + { + OnLineReceived(line); + } } } } @@ -142,7 +146,6 @@ public void Disconnect() public List GetPortNames() { - return SerialPort.GetPortNames().ToList(); } @@ -159,7 +162,14 @@ public void Send(string data) { if (IsConnected) { - _sp.WriteLine(data.RemoveSpace()); + try + { + _sp.WriteLine(data.RemoveSpace()); + } + catch (Exception ex) + { + Console.Write(ex); + } } } } diff --git a/grbl.Master.Service/Implementation/CommandSender.cs b/grbl.Master.Service/CommandSender.cs similarity index 80% rename from grbl.Master.Service/Implementation/CommandSender.cs rename to grbl.Master.Service/CommandSender.cs index 376b71b..10ff141 100644 --- a/grbl.Master.Service/Implementation/CommandSender.cs +++ b/grbl.Master.Service/CommandSender.cs @@ -1,7 +1,5 @@ -namespace grbl.Master.Service.Implementation +namespace grbl.Master.Service { - using grbl.Master.Service.Enum; - using grbl.Master.Service.Interface; using System; using System.Collections.Concurrent; using System.Collections.ObjectModel; @@ -11,13 +9,14 @@ using System.Reactive.Subjects; using System.Threading; + using grbl.Master.Common.Enum; + using grbl.Master.Common.Interfaces.Service; using grbl.Master.Model; using grbl.Master.Model.Enum; using grbl.Master.Utilities; public class CommandSender : ICommandSender { - private readonly IComService _comService; private readonly IGrblResponseTypeFinder _responseTypeFinder; @@ -30,7 +29,7 @@ public class CommandSender : ICommandSender private readonly SynchronizationContext _uiContext; - readonly Subject _stopSubject = new Subject(); + private readonly Subject _stopSubject = new Subject(); private readonly ConcurrentQueue _waitingCommandQueue = new ConcurrentQueue(); @@ -52,21 +51,16 @@ private void ProcessQueue() Observable.Timer(TimeSpan.Zero, TimeSpan.Zero).TakeUntil(_stopSubject).Subscribe( l => { - if ((SystemCommands.TryPeekCommand(out var cmd) || ManualCommands.TryPeekCommand(out cmd) || FileCommands.TryPeekCommand(out cmd)) && cmd != null && cmd.Data.RemoveSpace().Length + _waitingCommandQueue.Sum(x => x.Data.RemoveSpace().Length) <= _bufferSizeLimit) + if ((SystemCommands.TryPeekCommand(out var cmd) || ManualCommands.TryPeekCommand(out cmd) || FileCommands.TryPeekCommand(out cmd) || this.FileCommands.State != CommandSourceState.Running && this._waitingCommandQueue.Count == 0 && this.MacroCommands.TryPeekCommand(out cmd)) && cmd != null && cmd.Data.RemoveSpace().Length + CommandQueueLength <= _bufferSizeLimit) { - var continueProcess = false; - switch (cmd.Source) - { - case CommandSourceType.System: - continueProcess = SystemCommands.TryGetCommand(out cmd); - break; - case CommandSourceType.Manual: - continueProcess = ManualCommands.TryGetCommand(out cmd); - break; - case CommandSourceType.File: - continueProcess = FileCommands.TryGetCommand(out cmd); - break; - } + var continueProcess = cmd.Source switch + { + CommandSourceType.System => this.SystemCommands.TryGetCommand(out cmd), + CommandSourceType.Macros => this.MacroCommands.TryGetCommand(out cmd), + CommandSourceType.Manual => this.ManualCommands.TryGetCommand(out cmd), + CommandSourceType.File => this.FileCommands.TryGetCommand(out cmd), + _ => false + }; if (!continueProcess) return; @@ -77,12 +71,18 @@ private void ProcessQueue() }); } + public event EventHandler CommandQueueLengthChanged; + public CommandSource SystemCommands { get; } = new CommandSource(CommandSourceType.System, CommandSourceRunMode.Infinite); + public CommandSource MacroCommands { get; } = new CommandSource(CommandSourceType.Macros, CommandSourceRunMode.LineByOk); + public CommandSource ManualCommands { get; } = new CommandSource(CommandSourceType.Manual, CommandSourceRunMode.Infinite); public CommandSource FileCommands { get; } = new CommandSource(CommandSourceType.File, CommandSourceRunMode.StopInTheEnd); + public int CommandQueueLength => _waitingCommandQueue.Sum(x => x.Data.RemoveSpace().Length); + public ObservableCollection CommunicationLog { get; } = new ObservableCollection(); public event EventHandler ResponseReceived; @@ -140,14 +140,14 @@ public void Send(string command, string onResult = null) } } - public Command Prepare(string command) - { - var cmd = new Command { Data = command }; + //public Command Prepare(string command) + //{ + // var cmd = new Command { Data = command }; - _commandPreProcessor.Process(ref cmd); + // _commandPreProcessor.Process(ref cmd); - return cmd; - } + // return cmd; + //} public void SendAsync(string command, string onResult = null) { @@ -159,6 +159,7 @@ public void PurgeQueues() while (_waitingCommandQueue.Count > 0) { _waitingCommandQueue.TryDequeue(out var dummy); + CommandQueueLengthChanged?.Invoke(this, CommandQueueLength); } SystemCommands.Purge(); @@ -174,13 +175,15 @@ private void ComServiceConnectionStateChanged(object sender, ConnectionState e) ProcessQueue(); SystemCommands.StartProcessing(); ManualCommands.StartProcessing(); + MacroCommands.StartProcessing(); } else { _stopSubject.OnNext(Unit.Default); - this._processing = false; + _processing = false; SystemCommands.PauseProcessing(); ManualCommands.PauseProcessing(); + MacroCommands.PauseProcessing(); } } @@ -225,6 +228,7 @@ private void ComServiceLineReceived(object sender, string e) if ((type == ResponseType.Ok || type == ResponseType.Error || type == ResponseType.Alarm) && _waitingCommandQueue.Any() && _waitingCommandQueue.TryDequeue(out var cmd)) { + CommandQueueLengthChanged?.Invoke(this, CommandQueueLength); if (type == ResponseType.Ok) { cmd.ResultType = CommandResultType.Ok; @@ -239,7 +243,7 @@ private void ComServiceLineReceived(object sender, string e) FileCommands.PauseProcessing(); } } - else if(type == ResponseType.Alarm) + else if (type == ResponseType.Alarm) { cmd.ResultType = CommandResultType.Alarm; cmd.CommandResultCause = e.Split(':')[1]; @@ -279,6 +283,9 @@ private void ComServiceLineReceived(object sender, string e) case CommandSourceType.File: FileCommands.CommandList.Add(cmd); break; + case CommandSourceType.Macros: + MacroCommands.CommandList.Add(cmd); + break; default: throw new ArgumentOutOfRangeException(); } @@ -288,11 +295,11 @@ private void ComServiceLineReceived(object sender, string e) }, null); } - else if (_waitingCommandQueue.Any() && _waitingCommandQueue.TryPeek(out var comd)) + else if (_waitingCommandQueue.Any() && _waitingCommandQueue.TryPeek(out var peekCmd)) { - if (comd.ExpectedResponses.Any(x => x == type)) + if (peekCmd.ExpectedResponses.Any(x => x == type)) { - comd.Result += (string.IsNullOrEmpty(comd.Result) ? "" : Environment.NewLine) + e; + peekCmd.Result += (string.IsNullOrEmpty(peekCmd.Result) ? "" : Environment.NewLine) + e; } } } @@ -309,6 +316,7 @@ private void Send(Command cmd) { _waitingCommandQueue.Enqueue(cmd); } + CommandQueueLengthChanged?.Invoke(this, CommandQueueLength); _comService.Send(cmd.Data); } diff --git a/grbl.Master.Service/Enum/EnumHelper.cs b/grbl.Master.Service/Enum/EnumHelper.cs index 997594a..898815a 100644 --- a/grbl.Master.Service/Enum/EnumHelper.cs +++ b/grbl.Master.Service/Enum/EnumHelper.cs @@ -15,6 +15,6 @@ public static class EnumHelper var type = enumVal.GetType(); var memInfo = type.GetMember(enumVal.ToString()); var attributes = memInfo[0].GetCustomAttributes(typeof(T), false); - return (attributes.Length > 0) ? (T)attributes[0] : null; + return attributes.Length > 0 ? (T)attributes[0] : null; } }} \ No newline at end of file diff --git a/grbl.Master.Service/Implementation/GCodeFileService.cs b/grbl.Master.Service/GCodeFileService.cs similarity index 96% rename from grbl.Master.Service/Implementation/GCodeFileService.cs rename to grbl.Master.Service/GCodeFileService.cs index 54b1857..9527952 100644 --- a/grbl.Master.Service/Implementation/GCodeFileService.cs +++ b/grbl.Master.Service/GCodeFileService.cs @@ -1,10 +1,12 @@ -namespace grbl.Master.Service.Implementation +namespace grbl.Master.Service { + using System.IO; + + using grbl.Master.Common.Interfaces.Service; using grbl.Master.Model; using grbl.Master.Model.Enum; - using grbl.Master.Service.Interface; + using ICSharpCode.AvalonEdit.Document; - using System.IO; public class GCodeFileService : IGCodeFileService { diff --git a/grbl.Master.Service/GrblCommandPreProcessor.cs b/grbl.Master.Service/GrblCommandPreProcessor.cs new file mode 100644 index 0000000..722a355 --- /dev/null +++ b/grbl.Master.Service/GrblCommandPreProcessor.cs @@ -0,0 +1,133 @@ +namespace grbl.Master.Service +{ + using System.Collections.Generic; + using System.Linq; + using System.Text.RegularExpressions; + + using grbl.Master.Common.Interfaces.Service; + using grbl.Master.Model; + using grbl.Master.Model.Attribute; + using grbl.Master.Model.Enum; + using grbl.Master.Model.Interface; + using grbl.Master.Service.Enum; + + using Jint; + + public class GrblCommandPreProcessor : IGrblCommandPreProcessor + { + private readonly IGrblStatusModel _grblStatusModel; + + private readonly Engine _evaluator; + + readonly Regex _macroTag = new Regex("{[^{}]+}"); + + private struct Metadata + { + public RequestType? Type; + + public string RegularExpression; + + private Regex _regex; + + public Regex Regex + { + get + { + return _regex ??= string.IsNullOrEmpty(RegularExpression) + ? null + : new Regex(RegularExpression); + } + } + + public List CharList; + + public List ExpectedTypes; + } + + private Dictionary _regexTable; + + public GrblCommandPreProcessor(IGrblStatusModel grblStatusModel) + { + _grblStatusModel = grblStatusModel; + _evaluator = new Engine(); + + PrepareRegexTable(); + } + + private void PrepareRegexTable() + { + _regexTable = System.Enum.GetValues(typeof(CommandType)).Cast().ToDictionary( + type => type, + type => new Metadata + { + RegularExpression = type.GetAttributeOfType()?.RegularExpression, + ExpectedTypes = + type.GetAttributeOfType()?.ResponseTypes?.ToList(), + CharList = type.GetAttributeOfType()?.Characters?.ToList(), + Type = type.GetAttributeOfType()?.Type + }); + } + + public void Process(ref Command cmd) + { + var line = cmd.Data; + try + { + var result = line.Length > 1 + ? _regexTable.Where(x => x.Value.Regex != null) + .Single(x => x.Value.Regex.IsMatch(line)) + : _regexTable.Where(x => x.Value.CharList != null) + .Single(x => x.Value.CharList.Any(y => y == line[0])); + + cmd.Type = result.Value.Type; + cmd.ExpectedResponses = result.Value.ExpectedTypes; + } + catch + { + cmd.Type = RequestType.GCode; + cmd.ExpectedResponses = new List { ResponseType.Ok, ResponseType.Error }; + } + + if (cmd.Source == CommandSourceType.Macros) + { + cmd.Data = UnwrapMacros(line); + } + } + + private string UnwrapMacros(string line) + { + _evaluator.SetValue("STATUS", _grblStatusModel); + + var matches = _macroTag.Matches(line); + + foreach (Match match in matches) + { + var macroPart = match.Value.Replace("{", "").Replace("}", ""); + + var result = Evaluate(macroPart); + + line = line.Replace(match.Value, result); + } + + if (matches.Count > 0) + { + line = UnwrapMacros(line); + } + + return line; + } + + private string Evaluate(string line) + { + try + { + return (_evaluator.Execute(line).GetCompletionValue().ToObject() ?? string.Empty).ToString() + .Replace(',', '.'); + } + catch + { + return string.Empty; + } + } + } +} diff --git a/grbl.Master.Service/Implementation/GrblResponseTypeFinder.cs b/grbl.Master.Service/GrblResponseTypeFinder.cs similarity index 97% rename from grbl.Master.Service/Implementation/GrblResponseTypeFinder.cs rename to grbl.Master.Service/GrblResponseTypeFinder.cs index cfd6f27..27c5855 100644 --- a/grbl.Master.Service/Implementation/GrblResponseTypeFinder.cs +++ b/grbl.Master.Service/GrblResponseTypeFinder.cs @@ -1,11 +1,11 @@ -namespace grbl.Master.Service.Implementation +namespace grbl.Master.Service { using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; + using grbl.Master.Common.Interfaces.Service; using grbl.Master.Model.Enum; - using grbl.Master.Service.Interface; public class GrblResponseTypeFinder : IGrblResponseTypeFinder { diff --git a/grbl.Master.Service/Implementation/GrblCommandPreProcessor.cs b/grbl.Master.Service/Implementation/GrblCommandPreProcessor.cs deleted file mode 100644 index 6272a23..0000000 --- a/grbl.Master.Service/Implementation/GrblCommandPreProcessor.cs +++ /dev/null @@ -1,80 +0,0 @@ -namespace grbl.Master.Service.Implementation -{ - using System.Collections.Generic; - using System.Linq; - using System.Text.RegularExpressions; - - using grbl.Master.Model; - using grbl.Master.Model.Attribute; - using grbl.Master.Model.Enum; - using grbl.Master.Service.Enum; - using grbl.Master.Service.Interface; - - public class GrblCommandPreProcessor : IGrblCommandPreProcessor - { - private struct Metadata - { - public RequestType? Type; - - public string RegularExpression; - - private Regex _regex; - - public Regex Regex - { - get - { - return _regex ??= (string.IsNullOrEmpty(RegularExpression) - ? null - : new Regex(RegularExpression)); - } - } - - public List CharList; - - public List ExpectedTypes; - } - - private Dictionary _regexeTable; - - public GrblCommandPreProcessor() - { - PrepareregexTable(); - } - - private void PrepareregexTable() - { - _regexeTable = System.Enum.GetValues(typeof(CommandType)).Cast().ToDictionary( - type => type, - type => new Metadata - { - RegularExpression = type.GetAttributeOfType()?.RegularExpression, - ExpectedTypes = - type.GetAttributeOfType()?.ResponseTypes?.ToList(), - CharList = type.GetAttributeOfType()?.Characters?.ToList(), - Type = type.GetAttributeOfType()?.Type - }); - } - - public void Process(ref Command cmd) - { - var line = cmd.Data; - try - { - var result = line.Length > 1 - ? _regexeTable.Where(x => x.Value.Regex != null) - .Single(x => x.Value.Regex.IsMatch(line)) - : _regexeTable.Where(x => x.Value.CharList != null) - .Single(x => x.Value.CharList.Any(y => y == line[0])); - - cmd.Type = result.Value.Type; - cmd.ExpectedResponses = result.Value.ExpectedTypes; - } - catch - { - cmd.Type = RequestType.GCode; - cmd.ExpectedResponses = new List { ResponseType.Ok, ResponseType.Error }; - } - } - } -} diff --git a/grbl.Master.Service/grbl.Master.Service.csproj b/grbl.Master.Service/grbl.Master.Service.csproj index 8bbf917..bd6aff4 100644 --- a/grbl.Master.Service/grbl.Master.Service.csproj +++ b/grbl.Master.Service/grbl.Master.Service.csproj @@ -37,10 +37,13 @@ ..\packages\AvalonEdit.6.0.1\lib\net45\ICSharpCode.AvalonEdit.dll + + ..\packages\Jint.2.11.58\lib\net451\Jint.dll + ..\packages\Meziantou.Framework.WPF.1.1.0\lib\net461\Meziantou.Framework.WPF.dll - + ..\packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll @@ -49,10 +52,10 @@ ..\packages\System.Collections.Immutable.1.7.0\lib\netstandard2.0\System.Collections.Immutable.dll + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll - ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll @@ -69,25 +72,18 @@ ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll - + - - - - - - - - - - - - - + + + + + + @@ -96,6 +92,10 @@ + + {292BC2BE-A547-4567-8592-9CE4D9290E54} + grbl.Master.Common + {b21c205e-5ce2-436e-afa4-f2a3dac60d21} grbl.Master.Model diff --git a/grbl.Master.Service/packages.config b/grbl.Master.Service/packages.config index 381a45b..f1a26db 100644 --- a/grbl.Master.Service/packages.config +++ b/grbl.Master.Service/packages.config @@ -1,6 +1,7 @@  + diff --git a/grbl.Master.UI/Bootstrapper.cs b/grbl.Master.UI/Bootstrapper.cs index ec66b6c..22c0a57 100644 --- a/grbl.Master.UI/Bootstrapper.cs +++ b/grbl.Master.UI/Bootstrapper.cs @@ -10,10 +10,12 @@ namespace grbl.Master.UI { using Bluegrams.Application; - using grbl.Master.BL.Implementation; - using grbl.Master.BL.Interface; - using grbl.Master.Service.Implementation; - using grbl.Master.Service.Interface; + using grbl.Master.BL; + using grbl.Master.Common.Interfaces.BL; + using grbl.Master.Common.Interfaces.Service; + using grbl.Master.Model; + using grbl.Master.Model.Interface; + using grbl.Master.Service; public class Bootstrapper : BootstrapperBase { @@ -60,9 +62,10 @@ protected override void Configure() _container.RegisterSingleton(typeof(IGrblCommandPreProcessor), null, typeof(GrblCommandPreProcessor)); _container.RegisterSingleton(typeof(ICommandSender), null, typeof(CommandSender)); _container.RegisterSingleton(typeof(IApplicationSettingsService), null, typeof(ApplicationSettingsService)); - this._container.RegisterSingleton(typeof(IGCodeFileService), null, typeof(GCodeFileService)); + _container.RegisterSingleton(typeof(IGCodeFileService), null, typeof(GCodeFileService)); _container.RegisterSingleton(typeof(IGrblPrompt), null, typeof(GrblPrompt)); + _container.RegisterSingleton(typeof(IGrblStatusModel), null, typeof(GrblStatusModel)); _container.RegisterSingleton(typeof(IGrblStatus), null, typeof(GrblStatus)); @@ -92,7 +95,7 @@ protected override void Configure() return new KeyTrigger { Key = key }; case "Gesture": - var mkg = (MultiKeyGesture)(new MultiKeyGestureConverter()).ConvertFrom(splits[1]); + var mkg = (MultiKeyGesture)new MultiKeyGestureConverter().ConvertFrom(splits[1]); if (mkg != null) { diff --git a/grbl.Master.UI/Converters/EnumToDescription.cs b/grbl.Master.UI/Converters/EnumToDescription.cs index a0fdc48..779720d 100644 --- a/grbl.Master.UI/Converters/EnumToDescription.cs +++ b/grbl.Master.UI/Converters/EnumToDescription.cs @@ -2,6 +2,7 @@ { using System; using System.ComponentModel; + using System.Linq; using System.Windows; using System.Windows.Data; @@ -11,20 +12,13 @@ public class EnumToDescription : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { - if (value == null) return DependencyProperty.UnsetValue; - - return GetDescription((Enum)value); + return value == null ? DependencyProperty.UnsetValue : GetDescription((Enum)value); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value == null) return null; - foreach (Enum one in Enum.GetValues(targetType)) - { - if (value.ToString() == GetDescription(one)) - return one; - } - return null; + return Enum.GetValues(targetType).Cast().FirstOrDefault(one => value.ToString() == GetDescription(one)); } public static string GetDescription(Enum en) @@ -32,12 +26,7 @@ public static string GetDescription(Enum en) var attr = en.GetAttributeOfType(); - if (attr != null) - { - return attr.Description; - } - - return en.ToString(); + return attr != null ? attr.Description : en.ToString(); } } } \ No newline at end of file diff --git a/grbl.Master.UI/Converters/IntegerMask3ToDescription.cs b/grbl.Master.UI/Converters/IntegerMask3ToDescription.cs index e5936d2..1b55e1e 100644 --- a/grbl.Master.UI/Converters/IntegerMask3ToDescription.cs +++ b/grbl.Master.UI/Converters/IntegerMask3ToDescription.cs @@ -7,12 +7,12 @@ public class IntegerMask3ToDescription : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { - switch (value as string) - { - case "0": return "Enable WPos: Disable MPos:."; - case "1": return "Enable MPos:. Disable WPos:."; - default: return "Enabled Buf: field appears with planner and serial RX available buffer."; - } + return value as string switch + { + "0" => "Enable WPos: Disable MPos:.", + "1" => "Enable MPos:. Disable WPos:.", + _ => "Enabled Buf: field appears with planner and serial RX available buffer." + }; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) diff --git a/grbl.Master.UI/Converters/IntegerToBinaryString.cs b/grbl.Master.UI/Converters/IntegerToBinaryString.cs index 8c89865..36802a4 100644 --- a/grbl.Master.UI/Converters/IntegerToBinaryString.cs +++ b/grbl.Master.UI/Converters/IntegerToBinaryString.cs @@ -6,7 +6,7 @@ public class IntegerToBinaryString : IValueConverter { - static readonly Regex Binary = new Regex("^[01]{1,32}$", RegexOptions.Compiled); + private static readonly Regex Binary = new Regex("^[01]{1,32}$", RegexOptions.Compiled); public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { diff --git a/grbl.Master.UI/Converters/ListDoubleToString.cs b/grbl.Master.UI/Converters/ListDoubleToString.cs index 345ee2a..a7bc814 100644 --- a/grbl.Master.UI/Converters/ListDoubleToString.cs +++ b/grbl.Master.UI/Converters/ListDoubleToString.cs @@ -12,7 +12,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn { if (value is ObservableCollection elements) { - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); foreach (var element in elements) { sb.AppendLine(element.ToString()); diff --git a/grbl.Master.UI/Input/KeyTrigger.cs b/grbl.Master.UI/Input/KeyTrigger.cs index 83f744d..2bf5a53 100644 --- a/grbl.Master.UI/Input/KeyTrigger.cs +++ b/grbl.Master.UI/Input/KeyTrigger.cs @@ -40,14 +40,14 @@ protected override void OnDetaching() private void OnAssociatedObjectKeyDown(object sender, KeyEventArgs e) { - var key = (e.Key == Key.System) ? e.SystemKey : e.Key; - if ((key == Key) && (Keyboard.Modifiers == GetActualModifiers(e.Key, Modifiers))) + var key = e.Key == Key.System ? e.SystemKey : e.Key; + if (key == this.Key && Keyboard.Modifiers == GetActualModifiers(e.Key, this.Modifiers)) { InvokeActions(e); } } - static ModifierKeys GetActualModifiers(Key key, ModifierKeys modifiers) + private static ModifierKeys GetActualModifiers(Key key, ModifierKeys modifiers) { switch (key) { diff --git a/grbl.Master.UI/ViewModels/COMConnectionViewModel.cs b/grbl.Master.UI/ViewModels/COMConnectionViewModel.cs index 6222661..a096c39 100644 --- a/grbl.Master.UI/ViewModels/COMConnectionViewModel.cs +++ b/grbl.Master.UI/ViewModels/COMConnectionViewModel.cs @@ -3,10 +3,12 @@ namespace grbl.Master.UI.ViewModels { - using grbl.Master.Service.Enum; - using grbl.Master.Service.Interface; + using System.Windows; + using grbl.Master.Common.Enum; + using grbl.Master.Common.Interfaces.Service; + public class COMConnectionViewModel : Screen { private readonly IComService _comService; @@ -95,7 +97,7 @@ public void ReloadComPorts() public bool CanChangePortBaud => !_comService.IsConnected; - public bool CanConnect => (!string.IsNullOrWhiteSpace(SelectedComPort) && SelectedBaudRate > 0) || _comService.IsConnected; + public bool CanConnect => !string.IsNullOrWhiteSpace(this.SelectedComPort) && this.SelectedBaudRate > 0 || _comService.IsConnected; public void Connect() { diff --git a/grbl.Master.UI/ViewModels/MasterViewModel.cs b/grbl.Master.UI/ViewModels/MasterViewModel.cs index ea2f5fe..6bbd2cf 100644 --- a/grbl.Master.UI/ViewModels/MasterViewModel.cs +++ b/grbl.Master.UI/ViewModels/MasterViewModel.cs @@ -1,11 +1,8 @@ namespace grbl.Master.UI.ViewModels { using Caliburn.Micro; - using grbl.Master.BL.Interface; using grbl.Master.Model; using grbl.Master.Model.Enum; - using grbl.Master.Service.Enum; - using grbl.Master.Service.Interface; using grbl.Master.Utilities; using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.AvalonEdit.Highlighting.Xshd; @@ -25,6 +22,12 @@ using System.Threading; using System.Windows.Controls; using System.Xml; + + using grbl.Master.Common.Enum; + using grbl.Master.Common.Interfaces.BL; + using grbl.Master.Common.Interfaces.Service; + using grbl.Master.Model.Interface; + using Xceed.Wpf.Toolkit; public class MasterViewModel : Screen @@ -50,10 +53,6 @@ public class MasterViewModel : Screen private string _manualCommand; - //private double _selectedFeedRate = 1000; - - //private double _selectedJoggingDistance = 10; - public MasterViewModel( IComService comService, IGrblStatus grblStatus, @@ -77,6 +76,7 @@ public class MasterViewModel : Screen _grblStatus.GrblStatusModel.PropertyChanged += GrblStatusModelPropertyChanged; _comService.ConnectionStateChanged += ComServiceConnectionStateChanged; _commandSender.CommunicationLogUpdated += CommandSenderCommunicationLogUpdated; + _commandSender.CommandQueueLengthChanged += CommandSenderCommandQueueLengthChanged; _commandSender.FileCommands.CommandList.CollectionChanged += (sender, args) => { @@ -86,21 +86,26 @@ public class MasterViewModel : Screen StartNotifications(); } - private IHighlightingDefinition _GCodeHighlighting; + private void CommandSenderCommandQueueLengthChanged(object sender, int e) + { + NotifyOfPropertyChange(() => CommandQueueLength); + } + + private IHighlightingDefinition _gCodeHighlighting; public IHighlightingDefinition GCodeHighlighting { get { - return _GCodeHighlighting ??= GetHighlightingDefinition(); + return this._gCodeHighlighting ??= GetHighlightingDefinition(); } } private IHighlightingDefinition GetHighlightingDefinition() { var assembly = Assembly.GetExecutingAssembly(); - using Stream s = assembly.GetManifestResourceStream("grbl.Master.UI.GCodeHighlighting.xshd"); - using XmlTextReader reader = new XmlTextReader(s); + using var s = assembly.GetManifestResourceStream("grbl.Master.UI.GCodeHighlighting.xshd"); + using var reader = new XmlTextReader(s); return HighlightingLoader.Load(reader, HighlightingManager.Instance); } @@ -167,12 +172,16 @@ public double SelectedFeedRate public int FileLinesProcessed => FileCommandsCollection.Count; - public GrblStatusModel GrblStatus => _grblStatus.GrblStatusModel; + public IGrblStatusModel GrblStatus => _grblStatus.GrblStatusModel; + + public int CommandQueueLength => _commandSender.CommandQueueLength; public ObservableCollection CommunicationLog => _commandSender.CommunicationLog; public ObservableCollection ManualCommandsCollection => _commandSender.ManualCommands.CommandList; + public ObservableCollection MacroCommandsCollection => _commandSender.MacroCommands.CommandList; + public ObservableCollection SystemCommandsCollection => _commandSender.SystemCommands.CommandList; public ObservableCollection FileCommandsCollection => _commandSender.FileCommands.CommandList; @@ -342,6 +351,26 @@ public void SendManualCommand() _commandSender.SendAsync(ManualCommand); } + public void RefreshSystemLog() + { + _commandSender.SystemCommands.CommandList.Clear(); + } + + public void RefreshManualLog() + { + _commandSender.ManualCommands.CommandList.Clear(); + } + + public void RefreshMacroLog() + { + _commandSender.MacroCommands.CommandList.Clear(); + } + + public void RefreshFullLog() + { + _commandSender.CommunicationLog.Clear();; + } + public void SendEnterCommand() { SendManualCommand(); @@ -395,7 +424,7 @@ public void JoggingCommand(string code) _joggingCount = 0; _jogStopSubject.OnNext(Unit.Default); - var requestspeed = (SelectedJoggingDistance / (SelectedFeedRate / 60000)) * 0.9; + var requestSpeed = this.SelectedJoggingDistance / (this.SelectedFeedRate / 60000) * 0.9; _commandSender.SendAsync( "$J=" + string.Format( @@ -403,7 +432,7 @@ public void JoggingCommand(string code) SelectedJoggingDistance.ToGrblString(), SelectedFeedRate.ToGrblString())); - Observable.Timer(TimeSpan.FromMilliseconds(300), TimeSpan.FromMilliseconds(requestspeed)).TakeUntil(_jogStopSubject).Subscribe( + Observable.Timer(TimeSpan.FromMilliseconds(300), TimeSpan.FromMilliseconds(requestSpeed)).TakeUntil(_jogStopSubject).Subscribe( l => { _joggingCount++; @@ -489,7 +518,8 @@ public void ResetGrbl() public void RunMacro(Macros macro) { var lines = macro.Command.Split(new[] { Environment.NewLine, "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries); - _commandSender.ManualCommands.Add(lines); + _commandSender.MacroCommands.Add(lines); + _commandSender.MacroCommands.StartProcessing(); } public void DeleteMacro(Macros macro) diff --git a/grbl.Master.UI/Views/MasterView.xaml b/grbl.Master.UI/Views/MasterView.xaml index 100309a..a4a2c34 100644 --- a/grbl.Master.UI/Views/MasterView.xaml +++ b/grbl.Master.UI/Views/MasterView.xaml @@ -97,6 +97,7 @@ + @@ -179,6 +180,8 @@ + @@ -457,6 +460,8 @@ + + @@ -623,7 +628,36 @@ Content="{Binding GrblStatus.G30Position}" ContentTemplate="{StaticResource OffsetsData}" IsEnabled="False" /> - + + + + + + + + + @@ -820,6 +854,9 @@ Content="{Binding Path=Name}" FontSize="20px" FontWeight="DemiBold" ToolTip="{Binding Path=Name}"> + + +