diff --git a/AutoTools.ChmDataExtract/Program.cs b/AutoTools.ChmDataExtract/Program.cs index 93701da..7f1dcae 100644 --- a/AutoTools.ChmDataExtract/Program.cs +++ b/AutoTools.ChmDataExtract/Program.cs @@ -1,6 +1,8 @@ using System.Collections.Specialized; using System.Diagnostics; using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Text.RegularExpressions; using HtmlAgilityPack; using MewtocolNet; @@ -10,8 +12,7 @@ namespace AutoTools.ChmDataExtract; internal class Program { const string sysVarsLoc = @"Panasonic-ID SUNX Control\Control FPWIN Pro 7\Mak\Res_Eng\SysVars.chm"; - - const string sysVarsTempPath = @"Decomp"; + const string funcNamesLoc = @"Panasonic-ID SUNX Control\Control FPWIN Pro 7\Mak\Res_Eng\FPWINPro.chm"; static Dictionary> plcGroups = new() { { "FP7 CPS41/31 E/ES", new List { @@ -112,21 +113,136 @@ internal class Program { } + internal class FPFunction { + + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string RedundantName { get; set; } = null!; + + public string Description { get; set; } = null!; + + } + static void Main(string[] args) => Task.Run(AsyncMain).Wait(); static async Task AsyncMain () { - CheckGroupCoverage(); - - await GetSystemRegisters(); + GetFunctionNames(); + //await GetSystemRegisters(); } - static void CheckGroupCoverage () { + static void GetFunctionNames () { - //foreach (var key in Enum.GetNames(PlcType)) { + var functions = new Dictionary(); - //} + var progLoc = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!; + var progFilesPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); + var sysVarsPath = Path.Combine(progFilesPath, funcNamesLoc); + + Directory.SetCurrentDirectory(progLoc); + File.Copy(sysVarsPath, "./FPWINPro.chm", true); + + var startInfo = new ProcessStartInfo { + WorkingDirectory = progLoc, + FileName = "hh.exe", + Arguments = $"-decompile ./DecompFuncs ./FPWINPro.chm", + }; + + //call the hh.exe decompiler for chm + if (!File.Exists("./DecompFuncs/topics/availability.html")) { + var proc = Process.Start(startInfo)!; + proc.WaitForExit(); + } + + var doc = new HtmlDocument(); + doc.Load("./DecompFuncs/topics/availability.html"); + + //[contains(@class, 'table mainbody')] + foreach (HtmlNode table in doc.DocumentNode.SelectNodes("//table[1]")) { + + var rows = table?.SelectSingleNode("tbody")?.SelectNodes("tr"); + if (rows == null) continue; + + foreach (var row in rows) { + + var columns = row.SelectNodes("td"); + if (columns == null) continue; + + var itemRow = columns?.FirstOrDefault()?.SelectSingleNode("p/a[contains(@class,'xref')]"); + + string rowName = itemRow?.InnerText ?? "Unnamed"; + + if (!Regex.IsMatch(rowName, @"^F[0-9]{1,3}_.*$")) continue; + + FPFunction functionIns = new FPFunction(); + + //Console.Write($"Var: {rowName, -50}"); + + var href = itemRow?.GetAttributeValue("href", null); + + if (href != null) { + + //Console.Write($" {href}"); + + var docSub = new HtmlDocument(); + docSub.Load($"./DecompFuncs{href}"); + + var noteSection = docSub.DocumentNode.SelectSingleNode("//section/div[contains(@class,'note note')]"); + var xrefRedundant = noteSection?.SelectSingleNode("p/a[contains(@class,'xref')]"); + var xrefNodeContent = noteSection?.SelectSingleNode("p/span"); + + HtmlNode? descrSection = null; + + if (xrefRedundant != null && xrefNodeContent != null && xrefNodeContent.InnerText.StartsWith("This is a redundant F instruction")) { + + descrSection = docSub.DocumentNode.SelectSingleNode("//section[2]"); + + functionIns.RedundantName = xrefRedundant.InnerText; + + //Console.Write($"{xrefRedundant.InnerText}"); + + } else { + + descrSection = docSub.DocumentNode.SelectSingleNode("//section[1]"); + + } + + if (descrSection != null) { + + var descrText = descrSection?.InnerText; + + if(descrText != null) { + + descrText = descrText.Replace("\r", "").Replace("\n", "").Trim(); + + functionIns.Description = descrText; + + //Console.Write($" {descrText}"); + + } + + } + + } + + functions.Add(rowName, functionIns); + + //compatibility matrix + //for (int i = 1; i < columns?.Count - 1; i++) { + + // bool isChecked = columns?.ElementAtOrDefault(i)?.SelectSingleNode("p")?.InnerHtml != ""; + + // Console.Write($"{(isChecked ? "1" : "0")}, "); + + //} + + } + + } + + var funcsJson = JsonSerializer.Serialize(functions, new JsonSerializerOptions { WriteIndented = true }); + + Console.WriteLine(funcsJson); } diff --git a/AutoTools.DocBuilder/Docs/plctypes.md b/AutoTools.DocBuilder/Docs/plctypes.md index 7d83f3e..e3c4c8f 100644 --- a/AutoTools.DocBuilder/Docs/plctypes.md +++ b/AutoTools.DocBuilder/Docs/plctypes.md @@ -1,5 +1,5 @@ # PLC Type Table -Auto Generated @ **2023-07-21 16:30:21Z** +Auto Generated @ **2023-07-22 17:21:07Z** All supported PLC types for auto recognition are listed in this table. Other ones might also be supported but are shown as unknown in the library. Some models are never uniquely identifiable by their typecode and need extra hints like Prog Capacity in EXRT or RT. @@ -7,9 +7,9 @@ Typecode explained: ``` From left to right 0x -07 <= extended code (00 non mewtocol 7 devices) -20 <= Is hex for 32 (Prog capacity) -A5 <= Is the actual typecode, can overlap with others +07 <= extended code (00 for non Mewtocol 7 devices) +0120 <= for 120k (Prog capacity), with RT/EXRT/MEW7 override order +A5 <= Is the actual typecode, with RT/EXRT/MEW7 override order ``` > Discontinued PLCs
> These are PLCs that are no longer sold by Panasonic. Marked with ⚠️ @@ -33,7 +33,7 @@ A5 <= Is the actual typecode, can overlap with others ELC500 0k -0x070010 +0x7000010 ECOLOGIX_0k__ELC500 ⚠️ ❌ @@ -48,26 +48,26 @@ A5 <= Is the actual typecode, can overlap with others 0x000340 FP0_2c7k__C10_C14_C16 ⚠️ - ❌ - ❌ + ✅ + ✅ C32, SL1 5k -0x000041 +0x000541 FP0_5k__C32_SL1 ⚠️ - ❌ - ❌ + ✅ + ✅ T32 10k -0x000A42 +0x001042 FP0_10c0k__T32 ⚠️ - ❌ - ❌ + ✅ + ✅ 📟 FP0H @@ -75,7 +75,7 @@ A5 <= Is the actual typecode, can overlap with others C32ET/EP 32k -0x0020B1 +0x0032B1 FP0H_32k__C32ETsEP ✅ ❌ @@ -83,7 +83,7 @@ A5 <= Is the actual typecode, can overlap with others C32T/P 32k -0x0020B0 +0x0032B0 FP0H_32k__C32TsP ✅ ❌ @@ -94,34 +94,34 @@ A5 <= Is the actual typecode, can overlap with others C10, C14, C16 16k -0x000046 +0x001646 FP0R_16k__C10_C14_C16 ✅ - ❌ + ✅ C32 32k -0x002047 +0x003247 FP0R_32k__C32 ✅ - ❌ + ✅ F32 32k -0x002049 +0x003249 FP0R_32k__F32 ✅ - ❌ + ✅ T32 32k -0x002048 +0x003248 FP0R_32k__T32 ✅ - ❌ + ✅ 📟 FP1 @@ -147,7 +147,7 @@ A5 <= Is the actual typecode, can overlap with others C56, C72 5k -0x000006 +0x000506 FP1_5k__C56_C72 ⚠️ ❌ @@ -159,7 +159,7 @@ A5 <= Is the actual typecode, can overlap with others - 30k -0x001E20 +0x003020 FP10_30k ⚠️ ❌ @@ -168,7 +168,7 @@ A5 <= Is the actual typecode, can overlap with others - 60k -0x003C20 +0x006020 FP10_60k ⚠️ ❌ @@ -180,7 +180,7 @@ A5 <= Is the actual typecode, can overlap with others - 30k -0x001E20 +0x003020 FP10S_30k ⚠️ ❌ @@ -192,28 +192,28 @@ A5 <= Is the actual typecode, can overlap with others - 30k -0x001E30 +0x003030 FP10SH_30k ⚠️ - ❌ + ✅ ❌ - 60k -0x003C30 +0x006030 FP10SH_60k ⚠️ - ❌ + ✅ ❌ - 120k -0x007830 +0x012030 FP10SH_120k ⚠️ - ❌ + ✅ ❌ @@ -222,20 +222,20 @@ A5 <= Is the actual typecode, can overlap with others - 16k -0x001050 +0x001650 FP2_16k ⚠️ - ❌ - ❌ + ✅ + ✅ - 32k -0x002050 +0x003250 FP2_32k ⚠️ - ❌ - ❌ + ✅ + ✅ 📟 FP2SH @@ -243,25 +243,25 @@ A5 <= Is the actual typecode, can overlap with others - 32k -0x002062 +0x003262 FP2SH_32k ⚠️ ✅ - ❌ + ✅ - 60k -0x003C60 +0x006060 FP2SH_60k ⚠️ ✅ - ❌ + ✅ - 120k -0x0078E0 +0x012060 FP2SH_120k ⚠️ ✅ @@ -273,7 +273,7 @@ A5 <= Is the actual typecode, can overlap with others - 10k -0x000A03 +0x001003 FP3_10k ⚠️ ❌ @@ -282,7 +282,7 @@ A5 <= Is the actual typecode, can overlap with others - 16k -0x001013 +0x001613 FP3_16k ⚠️ ❌ @@ -294,7 +294,7 @@ A5 <= Is the actual typecode, can overlap with others - 16k -0x001002 +0x001602 FP5_16k ⚠️ ❌ @@ -303,7 +303,7 @@ A5 <= Is the actual typecode, can overlap with others - 24k -0x001812 +0x002412 FP5_24k ⚠️ ❌ @@ -315,7 +315,7 @@ A5 <= Is the actual typecode, can overlap with others CPS21 64k -0x074009 +0x7006409 FP7_64k__CPS21 ❌ ❌ @@ -323,7 +323,7 @@ A5 <= Is the actual typecode, can overlap with others CPS31 120k -0x077805 +0x7012005 FP7_120k__CPS31 ❌ ❌ @@ -331,7 +331,7 @@ A5 <= Is the actual typecode, can overlap with others CPS31E 120k -0x077804 +0x7012004 FP7_120k__CPS31E ❌ ❌ @@ -339,7 +339,7 @@ A5 <= Is the actual typecode, can overlap with others CPS31ES 120k -0x077807 +0x7012007 FP7_120k__CPS31ES ❌ ❌ @@ -347,7 +347,7 @@ A5 <= Is the actual typecode, can overlap with others CPS31S 120k -0x077808 +0x7012008 FP7_120k__CPS31S ❌ ❌ @@ -355,7 +355,7 @@ A5 <= Is the actual typecode, can overlap with others CPS41E 196k -0x07C403 +0x7019603 FP7_196k__CPS41E ❌ ❌ @@ -363,7 +363,7 @@ A5 <= Is the actual typecode, can overlap with others CPS41ES 196k -0x07C406 +0x7019606 FP7_196k__CPS41ES ❌ ❌ @@ -374,7 +374,7 @@ A5 <= Is the actual typecode, can overlap with others - 16k -0x001013 +0x001613 FPdC_16k ⚠️ ❌ @@ -416,7 +416,7 @@ A5 <= Is the actual typecode, can overlap with others C20RC, C20TC, C32TC 5k -0x000006 +0x000506 FPdM_5k__C20RC_C20TC_C32TC ⚠️ ❌ @@ -428,7 +428,7 @@ A5 <= Is the actual typecode, can overlap with others - 12k -0x000C43 +0x001243 FPdSIGMA_12k ⚠️ ✅ @@ -437,7 +437,7 @@ A5 <= Is the actual typecode, can overlap with others - 16k -0x0010E1 +0x0016E1 FPdSIGMA_16k ⚠️ ✅ @@ -446,16 +446,16 @@ A5 <= Is the actual typecode, can overlap with others - 32k -0x002044 +0x003244 FPdSIGMA_32k ⚠️ ✅ - ❌ + ✅ - 40k -0x0028E1 +0x0040E1 FPdSIGMA_40k ⚠️ ✅ @@ -476,7 +476,7 @@ A5 <= Is the actual typecode, can overlap with others C14R 16k -0x001070 +0x001670 FPdX_16k__C14R ⚠️ ✅ @@ -485,7 +485,7 @@ A5 <= Is the actual typecode, can overlap with others C14T/P 16k -0x001076 +0x001676 FPdX_16k__C14TsP ⚠️ ✅ @@ -494,7 +494,7 @@ A5 <= Is the actual typecode, can overlap with others L14 16k -0x001073 +0x001673 FPdX_16k__L14 ⚠️ ✅ @@ -503,7 +503,7 @@ A5 <= Is the actual typecode, can overlap with others C30R, C60R 32k -0x002071 +0x003271 FPdX_32k__C30R_C60R ⚠️ ✅ @@ -512,7 +512,7 @@ A5 <= Is the actual typecode, can overlap with others C30T/P, C60T/P, C38AT, C40T 32k -0x002077 +0x003277 FPdX_32k__C30TsP_C60TsP_C38AT_C40T ⚠️ ✅ @@ -521,7 +521,7 @@ A5 <= Is the actual typecode, can overlap with others L30, L60 32k -0x002074 +0x003274 FPdX_32k__L30_L60 ⚠️ ✅ @@ -551,7 +551,7 @@ A5 <= Is the actual typecode, can overlap with others L40, L60 16k -0x00107F +0x00167F FPdX0_16k__L40_L60 ⚠️ ✅ @@ -563,7 +563,7 @@ A5 <= Is the actual typecode, can overlap with others C14R 16k -0x0010A0 +0x0016A0 FPdXH_16k__C14R ✅ ✅ @@ -571,7 +571,7 @@ A5 <= Is the actual typecode, can overlap with others C14T/P 16k -0x0010A4 +0x0016A4 FPdXH_16k__C14TsP ✅ ❌ @@ -579,7 +579,7 @@ A5 <= Is the actual typecode, can overlap with others C30R, C40R, C60R 32k -0x0020A1 +0x0032A1 FPdXH_32k__C30R_C40R_C60R ✅ ❌ @@ -587,7 +587,7 @@ A5 <= Is the actual typecode, can overlap with others C30T/P, C40T, C60T/P 32k -0x0020A5 +0x0032A5 FPdXH_32k__C30TsP_C40T_C60TsP ✅ ✅ @@ -595,7 +595,7 @@ A5 <= Is the actual typecode, can overlap with others C38AT 32k -0x0020A7 +0x0032A7 FPdXH_32k__C38AT ✅ ❌ @@ -603,7 +603,7 @@ A5 <= Is the actual typecode, can overlap with others C40ET, C60ET 32k -0x0020AE +0x0032AE FPdXH_32k__C40ET_C60ET ✅ ❌ @@ -611,7 +611,7 @@ A5 <= Is the actual typecode, can overlap with others C60ETF 32k -0x0020AF +0x0032AF FPdXH_32k__C60ETF ✅ ❌ @@ -619,7 +619,7 @@ A5 <= Is the actual typecode, can overlap with others M4T/L 32k -0x0020A8 +0x0032A8 FPdXH_32k__M4TsL ✅ ❌ @@ -627,7 +627,7 @@ A5 <= Is the actual typecode, can overlap with others M8N16T/P 32k -0x0020AC +0x0032AC FPdXH_32k__M8N16TsP ✅ ❌ @@ -635,7 +635,7 @@ A5 <= Is the actual typecode, can overlap with others M8N30T 32k -0x0020AD +0x0032AD FPdXH_32k__M8N30T ✅ ❌ diff --git a/AutoTools.DocBuilder/Docs/program-read-write.md b/AutoTools.DocBuilder/Docs/program-read-write.md new file mode 100644 index 0000000..71fee4c --- /dev/null +++ b/AutoTools.DocBuilder/Docs/program-read-write.md @@ -0,0 +1,2 @@ +# Reading and writing programs + diff --git a/AutoTools.DocBuilder/Docs/reverse_engineering_data.md b/AutoTools.DocBuilder/Docs/reverse_engineering_data.md index 46629e4..f4b7b45 100644 --- a/AutoTools.DocBuilder/Docs/reverse_engineering_data.md +++ b/AutoTools.DocBuilder/Docs/reverse_engineering_data.md @@ -145,6 +145,111 @@ FP-XH 16k C14R | 2819 | System register size | 20130000080070004 | ? +## FP0 5k C32,SL1 + +### %EE$RT + +|Reponse Byte|Description| +|------------|-----------| +| 06 | Model code | +| 12 | Version | +| 05 | Prog capacity | +| 82 | Op mode | +| 00 | Link unit | +| 00 | Error flag | +| 0000 | Self diag error | + +### %EE$EX00RT + +|Reponse Byte|Description| +|------------|-----------| +| 00 | Extended mode +| 32 | Data item count +| 41 | Machine type +| 00 | Version (Fixed to 00) +| 03 | Prog capacity in K +| 82 | Operation mode / status +| 00 | Link unit +| 00 | Error flag +| 0000 | Self diag error +| 23 | Version +| 01 | Hardware information +| 0 | Number of programs +| 4100 | Program size BCD +| 0501 | Header size (no. of words) bcd +| 2819 | System register size +| 20130000080070004 | ? + +## FP0 10k + +### %EE$RT + +|Reponse Byte|Description| +|------------|-----------| +| 42 | Model code | +| 12 | Version | +| 10 | Prog capacity | +| 82 | Op mode | +| 00 | Link unit | +| 00 | Error flag | +| 0000 | Self diag error | + +### %EE$EX00RT + +|Reponse Byte|Description| +|------------|-----------| +| 00 | Extended mode +| 32 | Data item count +| 42 | Machine type +| 00 | Version (Fixed to 00) +| 10 | Prog capacity in K +| 82 | Operation mode / status +| 00 | Link unit +| 00 | Error flag +| 0000 | Self diag error +| 23 | Version +| 01 | Hardware information +| 0 | Number of programs +| 4100 | Program size BCD +| 1001 | Header size (no. of words) bcd +| 2819 | System register size +| 20130000080070004 | ? + +## FP2SH 60k + +### %EE$RT + +|Reponse Byte|Description| +|------------|-----------| +| 60 | Model code | +| 12 | Version | +| 00 | Prog capacity | +| 82 | Op mode | +| 00 | Link unit | +| 00 | Error flag | +| 0000 | Self diag error | + +### %EE$EX00RT + +|Reponse Byte|Description| +|------------|-----------| +| 00 | Extended mode +| 32 | Data item count +| 60 | Machine type +| 00 | Version (Fixed to 00) +| 00 | Prog capacity in K +| 82 | Operation mode / status +| 00 | Link unit +| 00 | Error flag +| 0000 | Self diag error +| 23 | Version +| 01 | Hardware information +| 0 | Number of programs +| 4100 | Program size BCD +| 6001 | Header size (no. of words) bcd +| 2819 | System register size +| 20130000000080004 | ? + # Mewtocol-7 Com ## Getting the status of the plc diff --git a/AutoTools.DocBuilder/Docs/system-registers.md b/AutoTools.DocBuilder/Docs/system-registers.md new file mode 100644 index 0000000..f9577ab --- /dev/null +++ b/AutoTools.DocBuilder/Docs/system-registers.md @@ -0,0 +1,16 @@ +3 byte system registers, read with RR + +|RR Adress|Interpreting type|Description| +|-|-|-| +|RR000|uint16|Program size steps capacity| +|RR005|uint16|Start address counter| +|RR006|uint16|Start address timer/counter| +|RR007|uint16|Start WR area (self reliant)| +|RR008 - RR009|uint32|Start DT area (self reliant)| + +4 byte / 1 word system registers read with R + +|WR Adress|Interpreting type|Description| +|-|-|-| +|R900|uint16|Self diag error| +|R902|uint16|Mode info| \ No newline at end of file diff --git a/AutoTools.DocBuilder/Program.cs b/AutoTools.DocBuilder/Program.cs index a884180..0295877 100644 --- a/AutoTools.DocBuilder/Program.cs +++ b/AutoTools.DocBuilder/Program.cs @@ -133,9 +133,9 @@ $"Typecode explained:\n" + $"```\n" + $"From left to right\n" + $"0x\n" + -$"07 <= extended code (00 non mewtocol 7 devices)\n" + -$"20 <= Is hex for 32 (Prog capacity)\n" + -$"A5 <= Is the actual typecode, can overlap with others\n" + +$"07 <= extended code (00 for non Mewtocol 7 devices)\n" + +$"0120 <= for 120k (Prog capacity), with RT/EXRT/MEW7 override order\n" + +$"A5 <= Is the actual typecode, with RT/EXRT/MEW7 override order\n" + $"```" ); diff --git a/Examples.BasicEthernet/Program.cs b/Examples.BasicEthernet/Program.cs index e201899..6c9862c 100644 --- a/Examples.BasicEthernet/Program.cs +++ b/Examples.BasicEthernet/Program.cs @@ -26,6 +26,7 @@ internal class Program { //connect async to the plc await plc.ConnectAsync(); + await plc.SendCommandAsync($"%EE#RP0000000004"); //check if the connection was established if (!plc.IsConnected) { @@ -62,6 +63,14 @@ internal class Program { plc.ConfigureConnection("192.168.115.214", 9094); await plc.ConnectAsync(); + plc.Disconnect(); + + plc.ConfigureConnection("192.168.178.55", 9094); + await plc.ConnectAsync(); + //await plc.SendCommandAsync($"%EE#RR0000100"); + //await plc.SendCommandAsync($"%EE#RCCR09030903"); + await plc.SendCommandAsync($"%EE#RP0000000067"); + } //you can also find any applicable source endpoints by using: diff --git a/Examples.ProgramReadWrite/Examples.ProgramReadWrite.csproj b/Examples.ProgramReadWrite/Examples.ProgramReadWrite.csproj new file mode 100644 index 0000000..957d69a --- /dev/null +++ b/Examples.ProgramReadWrite/Examples.ProgramReadWrite.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/Examples.ProgramReadWrite/Program.cs b/Examples.ProgramReadWrite/Program.cs new file mode 100644 index 0000000..3375e1a --- /dev/null +++ b/Examples.ProgramReadWrite/Program.cs @@ -0,0 +1,11 @@ +namespace Examples.ProgramReadWrite; + +internal class Program { + + static void Main(string[] args) { + + MewtocolNet.ProgramParsing.PlcBinaryProgram.ParseFromFile(@"C:\Users\feli1\Documents\Test\prog4.fp").AnalyzeProgram(); + + } + +} diff --git a/MewTerminal/Commands/ListSupportCommand.cs b/MewTerminal/Commands/ListSupportCommand.cs index c69aec8..06d23fe 100644 --- a/MewTerminal/Commands/ListSupportCommand.cs +++ b/MewTerminal/Commands/ListSupportCommand.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Xml.Linq; using CommandLine; using MewtocolNet; using MewtocolNet.ComCassette; @@ -21,8 +22,9 @@ internal class ListSupportCommand : CommandLineExcecuteable { var decomp = plcT.ToNameDecompose(); - foreach (var name in decomp) - lst.Add(name); + if (decomp == null) continue; + + lst.Add(decomp); } diff --git a/MewtocolNet.sln b/MewtocolNet.sln index 8a191a0..4f748d7 100644 --- a/MewtocolNet.sln +++ b/MewtocolNet.sln @@ -19,9 +19,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples.Polling", "Example EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoTools", "AutoTools", "{BAEF983A-EFF2-48DF-A74E-57084166BB4D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoTools.ChmDataExtract", "AutoTools.ChmDataExtract\AutoTools.ChmDataExtract.csproj", "{5A9DE453-AD64-4F8D-8215-3BB26674D164}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoTools.ChmDataExtract", "AutoTools.ChmDataExtract\AutoTools.ChmDataExtract.csproj", "{5A9DE453-AD64-4F8D-8215-3BB26674D164}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoTools.DocBuilder", "AutoTools.DocBuilder\AutoTools.DocBuilder.csproj", "{00ACA0AB-3988-4EF7-98A6-B39A36B136DA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoTools.DocBuilder", "AutoTools.DocBuilder\AutoTools.DocBuilder.csproj", "{00ACA0AB-3988-4EF7-98A6-B39A36B136DA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Examples.ProgramReadWrite", "Examples.ProgramReadWrite\Examples.ProgramReadWrite.csproj", "{51BDABAA-05B0-4802-AA37-243DAE22D5DC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -129,6 +131,18 @@ Global {00ACA0AB-3988-4EF7-98A6-B39A36B136DA}.Release|x64.Build.0 = Release|Any CPU {00ACA0AB-3988-4EF7-98A6-B39A36B136DA}.Release|x86.ActiveCfg = Release|Any CPU {00ACA0AB-3988-4EF7-98A6-B39A36B136DA}.Release|x86.Build.0 = Release|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Debug|x64.ActiveCfg = Debug|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Debug|x64.Build.0 = Debug|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Debug|x86.ActiveCfg = Debug|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Debug|x86.Build.0 = Debug|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Release|Any CPU.Build.0 = Release|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Release|x64.ActiveCfg = Release|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Release|x64.Build.0 = Release|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Release|x86.ActiveCfg = Release|Any CPU + {51BDABAA-05B0-4802-AA37-243DAE22D5DC}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -139,6 +153,7 @@ Global {9A36F2B1-FF9E-47BF-9931-3D3EB3C46B61} = {323729B0-5FB2-4592-9FA6-220C46BBF84C} {5A9DE453-AD64-4F8D-8215-3BB26674D164} = {BAEF983A-EFF2-48DF-A74E-57084166BB4D} {00ACA0AB-3988-4EF7-98A6-B39A36B136DA} = {BAEF983A-EFF2-48DF-A74E-57084166BB4D} + {51BDABAA-05B0-4802-AA37-243DAE22D5DC} = {323729B0-5FB2-4592-9FA6-220C46BBF84C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4ABB8137-CD8F-4691-9802-9ED371012F47} diff --git a/MewtocolNet/Helpers/MewtocolHelpers.cs b/MewtocolNet/Helpers/MewtocolHelpers.cs index 48e41a5..e6af4e6 100644 --- a/MewtocolNet/Helpers/MewtocolHelpers.cs +++ b/MewtocolNet/Helpers/MewtocolHelpers.cs @@ -292,6 +292,16 @@ namespace MewtocolNet { #region PLC Type Enum Parsing + /// + /// Gets synonim names for a plc type enum + /// + /// All or just one of there are no synonims for the same + public static string[] GetSynonims (this PlcType plcType) { + + return Enum.GetNames(typeof(PlcType)).Where(n => Enum.Parse(typeof(PlcType), n).Equals(plcType)).ToArray(); + + } + /// /// Converts the enum to a plc name string /// diff --git a/MewtocolNet/IPlc.cs b/MewtocolNet/IPlc.cs index 1b8b310..e1015f5 100644 --- a/MewtocolNet/IPlc.cs +++ b/MewtocolNet/IPlc.cs @@ -97,6 +97,13 @@ namespace MewtocolNet { /// The success state of the write operation Task RestartProgramAsync(); + /// + /// Factory resets the PLC, this includes the current program + /// and data in the EEPROM + /// + /// + Task FactoryResetAsync(); + /// /// Use this to await the first poll iteration after connecting, /// This also completes if the initial connection fails diff --git a/MewtocolNet/MewtocolInterfaceRequests.cs b/MewtocolNet/MewtocolInterfaceRequests.cs index 3f16c2b..7e32e71 100644 --- a/MewtocolNet/MewtocolInterfaceRequests.cs +++ b/MewtocolNet/MewtocolInterfaceRequests.cs @@ -102,6 +102,18 @@ namespace MewtocolNet { } + /// + public async Task FactoryResetAsync () { + + //set to prog mode + await SetOperationModeAsync(false); + + //reset plc + await SendCommandAsync($"%EE#0F"); + await SendCommandAsync($"%EE#21"); + + } + #endregion #region Byte range writing / reading to registers diff --git a/MewtocolNet/ProgramParsing/PlcBinaryProgram.cs b/MewtocolNet/ProgramParsing/PlcBinaryProgram.cs new file mode 100644 index 0000000..7688461 --- /dev/null +++ b/MewtocolNet/ProgramParsing/PlcBinaryProgram.cs @@ -0,0 +1,152 @@ +using System.Text; +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; + +namespace MewtocolNet.ProgramParsing { + + public class PlcBinaryProgram { + + static readonly Dictionary stepCommands = new Dictionary { + { 0x00FF, "SUB 0" }, + + { 0xB0FF, "DF" }, + { 0xFAF8, "ED" }, + { 0xFDF8, "RET" }, //return + { 0xF6F8, "CALL" }, + + { 0x21CC, "OT R501" }, + { 0x21AC, "ST R501" }, + { 0xF7FF, "ST R9010" }, + + }; + + // ST R50_1 21 AC => WR system area start was set to 50 + // ST R57_1 91 AC => WR system area start was set to 57 + // ST R901_3 F7 FF 53 A9 + // ST R901_C F7 FF 5C A9 + // AN/ R900_B F7 FF 4B 49 + + static readonly Dictionary stepFunctions = new Dictionary { + { "F0", "MV" }, + { "F1", "DMV" }, + { "F2", "MVN" }, + { "F3", "DMVN" }, + { "F5", "BTM" }, + { "F8", "DMV2" }, + { "F11", "COPY" }, + { "F61", "DCMP" }, + { "F246", "CALL" }, + }; + + const int STEP_BYTE_LEN = 2; + + const int PROG_AUTHOR_INDEX = 57; + const int PROG_AUTHOR_MAX_CHARS = 12; + + const int PROG_DESCRIPTION_INDEX = 17; + const int PROG_DESCRIPTION_MAX_CHARS = 40; + + const int PROG_SIZE_START = 1139; + const int PROG_DATA_START = 1179; + + public List rawSteps; + + public string Author { get; internal set; } + + public string Description { get; internal set; } + + public static PlcBinaryProgram ParseFromFile (string path) { + + var retInstance = new PlcBinaryProgram(); + + var rawBytes = File.ReadAllBytes(path); + + if (rawBytes.Length < 2 || (rawBytes[0] != 0x46 && rawBytes[1] != 0x50)) + throw new NotSupportedException("The loaded file was no FP file"); + + var rawString = Encoding.ASCII.GetString(rawBytes); + + //get author and description + var progAuthor = Encoding.ASCII.GetString(rawBytes, PROG_AUTHOR_INDEX, PROG_AUTHOR_MAX_CHARS).Replace("\0", ""); + var progDescription = Encoding.ASCII.GetString(rawBytes, PROG_DESCRIPTION_INDEX, PROG_DESCRIPTION_MAX_CHARS).Replace("\0", ""); + var progSizeSteps = BitConverter.ToInt32(rawBytes, PROG_SIZE_START); + + //improve performance later + var steps = new List(); + + for (int i = 0; i < progSizeSteps; i++) { + + //00-FF F8 => 0-255 default function + //FF F8 => extended function, look for next step + + var step = rawBytes.Skip(PROG_DATA_START + (i * STEP_BYTE_LEN)).Take(STEP_BYTE_LEN).ToArray(); + + steps.Add(step); + + } + + retInstance.rawSteps = steps; + + return retInstance; + + } + + public void AnalyzeProgram () { + + for (int i = 0; i < rawSteps.Count; i++) { + + var step = rawSteps[i]; + + var stepAscii = Encoding.ASCII.GetString(step); + var stepBytesString = string.Join(" ", step.Select(x => x.ToString("X2"))); + + Console.Write($"{i,3} => {stepBytesString} "); + + var stepKey = BitConverter.ToUInt16(step.Reverse().ToArray(), 0); + + if (stepCommands.ContainsKey(stepKey)) { + + Console.Write($"{stepCommands[stepKey]}"); + + } else if (stepKey == 0xFFF8) { + + //custom function that goes over FF, the F instruction number is calced by + //the next step first byte plus 190 + + var nextStep = rawSteps[i + 1]; + var stepID = nextStep[0] + 190; + + string funcName = GetFunctionName($"F{stepID}"); + Console.Write(funcName); + + } else if (step[1] == 0xF8) { + + string funcName = GetFunctionName($"F{step[0]}"); + Console.Write(funcName); + + } + + //if (stepBytesString.StartsWith("F")) { + // Console.Write(" STEP COMMAND"); + //} + + Console.WriteLine(); + + } + + + Console.WriteLine(); + + } + + private string GetFunctionName (string funcName) { + + return stepFunctions.ContainsKey(funcName) ? $"{funcName} ({stepFunctions[funcName]})" : funcName; + + } + + } + +} diff --git a/MewtocolNet/PublicEnums/PlcType.cs b/MewtocolNet/PublicEnums/PlcType.cs index 2b0965a..b2e767d 100644 --- a/MewtocolNet/PublicEnums/PlcType.cs +++ b/MewtocolNet/PublicEnums/PlcType.cs @@ -8,31 +8,33 @@ namespace MewtocolNet { //MISSING! FP7 and EcoLogix // Byte layout explained: - // PLCs that are identifiable by just one byte have just one byte as their code 0x00 - // PLCs that are not identifiable by just one byte and also need a prog size param to identfy use the second byte for capacity 0x32_00 => 32k of type 00 - // PLCs that use the mewtocol 7 identifcation method (currently only fp7 and EL500) use the third byte for their inital identifier (07 for fp7) => 0x07_00_09 - // Sometimes the type is no directly identifable, then two types share the same code and make logically no difference - //special codes for mem size are: 02 = 2.5k, 03 = 2.7k + // left to right + // 07 => Mewtocol7 type code (only for FP7 / ELC500 at this time) + // 0120 => prog size received from RT / EXRT message, the EXRT code always overrides the RT one (0x0120 == 120k) + // 41 => special identfier from RT / EXRT message, the EXRT code always overrides the RT one + + //special codes prog size for float point vals are: ?? = 0.9k, 02 = 2.5k, 03 = 2.7k /// /// Type identifier of the plc /// - public enum PlcType { + public enum PlcType : uint { + //NON SIMULATION TEST POSSIBLE #region FP5 Family (Legacy) /// /// FP5 16k /// [PlcLegacy] - FP5_16k = 0x10_02, + FP5_16k = 0x0016_02, /// /// FP5 24k /// [PlcLegacy] - FP5_24k = 0x18_12, + FP5_24k = 0x0024_12, #endregion @@ -41,44 +43,46 @@ namespace MewtocolNet { /// /// FP2 16k /// - [PlcLegacy] - FP2_16k = 0x10_50, + [PlcLegacy, PlcEXRT, PlcCodeTested] + FP2_16k = 0x0016_50, /// /// FP2 32k /// - [PlcLegacy] - FP2_32k = 0x20_50, + [PlcLegacy, PlcEXRT, PlcCodeTested] + FP2_32k = 0x0032_50, #endregion + //NON SIMULATION TEST POSSIBLE #region FP3/FP-C Family (Legacy) /// /// FP3 10k /// [PlcLegacy] - FP3_10k = 0x0A_03, + FP3_10k = 0x0010_03, /// /// FP-C 16k /// [PlcLegacy] - FPdC_16k = 0x10_13, + FPdC_16k = 0x0016_13, /// /// FP3 /// [PlcLegacy] FP3_16k = FPdC_16k, - + #endregion + //NON SIMULATION TEST POSSIBLE #region FP1 / FPM Family (Legacy) /// /// FP1 0.9k C14,C16 /// [PlcLegacy] - FP1_0c9k__C14_C16 = 0x00_04, + FP1_0c9k__C14_C16 = 0x0000_04, /// /// FP-M 0.9k C16T /// @@ -88,7 +92,7 @@ namespace MewtocolNet { /// FP1 2.7k C24,C40 /// [PlcLegacy] - FP1_2c7k__C24_C40 = 0x03_05, + FP1_2c7k__C24_C40 = 0x0003_05, /// /// FP-M 2.7k C20R,C20T,C32T /// @@ -98,7 +102,7 @@ namespace MewtocolNet { /// FP1 5.0k C56,C72 /// [PlcLegacy] - FP1_5k__C56_C72 = 0x00_06, + FP1_5k__C56_C72 = 0x0005_06, /// /// FPM 5.0k C20RC,C20TC,C32TC /// @@ -107,13 +111,14 @@ namespace MewtocolNet { #endregion + //NON SIMULATION TEST POSSIBLE #region FP10 Family (Legacy) /// /// FP10S 30k /// [PlcLegacy] - FP10S_30k = 0x1E_20, + FP10S_30k = 0x0030_20, /// /// FP10 30k /// @@ -123,27 +128,28 @@ namespace MewtocolNet { /// FP10 60k /// [PlcLegacy] - FP10_60k = 0x3C_20, + FP10_60k = 0x0060_20, #endregion + //NON SIMULATION TEST POSSIBLE #region FP10SH Family (Legacy) /// /// FP10SH 30k /// - [PlcLegacy] - FP10SH_30k = 0x1E_30, + [PlcLegacy, PlcEXRT] + FP10SH_30k = 0x0030_30, /// /// FP10SH 60k /// - [PlcLegacy] - FP10SH_60k = 0x3C_30, + [PlcLegacy, PlcEXRT] + FP10SH_60k = 0x0060_30, /// /// FP10SH 120k /// - [PlcLegacy] - FP10SH_120k = 0x78_30, + [PlcLegacy, PlcEXRT] + FP10SH_120k = 0x0120_30, #endregion @@ -152,53 +158,55 @@ namespace MewtocolNet { /// /// FP0 2.7k C10,C14,C16 /// - [PlcLegacy] - FP0_2c7k__C10_C14_C16 = 0x03_40, + [PlcLegacy, PlcEXRT, PlcCodeTested] + FP0_2c7k__C10_C14_C16 = 0x0003_40, /// /// FP0 5k /// - [PlcLegacy] - FP0_5k__C32_SL1 = 0x00_41, + [PlcLegacy, PlcEXRT, PlcCodeTested] + FP0_5k__C32_SL1 = 0x0005_41, /// /// FP0 10k /// - [PlcLegacy] - FP0_10c0k__T32 = 0x0A_42, + [PlcLegacy, PlcEXRT, PlcCodeTested] + FP0_10c0k__T32 = 0x0010_42, #endregion + //PARTIAL SIMULATION TEST POSSIBLE #region FP-Sigma Family (Legacy) /// /// FP-SIGMA 12k /// [PlcLegacy, PlcEXRT] - FPdSIGMA_12k = 0x0C_43, + FPdSIGMA_12k = 0x0012_43, /// /// FP-SIGMA 32k /// - [PlcLegacy, PlcEXRT] - FPdSIGMA_32k = 0x20_44, + [PlcLegacy, PlcEXRT, PlcCodeTested] + FPdSIGMA_32k = 0x0032_44, /// /// FP-SIGMA 16k /// [PlcLegacy, PlcEXRT] - FPdSIGMA_16k = 0x10_E1, + FPdSIGMA_16k = 0x0016_E1, /// /// FP-SIGMA 40k (never supported) /// [PlcLegacy, PlcEXRT] - FPdSIGMA_40k = 0x28_E1, + FPdSIGMA_40k = 0x0040_E1, #endregion + //NON SIMULATION TEST POSSIBLE #region FP-e Family (Legacy) /// /// FP-e 2.7k /// [PlcLegacy, PlcEXRT] - FPde_2c7k = 0x03_45, + FPde_2c7k = 0x0003_45, #endregion @@ -207,23 +215,23 @@ namespace MewtocolNet { /// /// FP0R 16k C10,C14,C16 /// - [PlcEXRT] - FP0R_16k__C10_C14_C16 = 0x46, + [PlcEXRT, PlcCodeTested] + FP0R_16k__C10_C14_C16 = 0x0016_46, /// /// FP0R 32k C32 /// - [PlcEXRT] - FP0R_32k__C32 = 0x20_47, + [PlcEXRT, PlcCodeTested] + FP0R_32k__C32 = 0x0032_47, /// /// FP0R 32k T32 /// - [PlcEXRT] - FP0R_32k__T32 = 0x20_48, + [PlcEXRT, PlcCodeTested] + FP0R_32k__T32 = 0x0032_48, /// /// FP0R 32k F32 /// - [PlcEXRT] - FP0R_32k__F32 = 0x20_49, + [PlcEXRT, PlcCodeTested] + FP0R_32k__F32 = 0x0032_49, #endregion @@ -232,18 +240,18 @@ namespace MewtocolNet { /// /// FP2SH 32k /// - [PlcLegacy, PlcEXRT] - FP2SH_32k = 0x20_62, + [PlcLegacy, PlcEXRT, PlcCodeTested] + FP2SH_32k = 0x0032_62, /// /// FP2SH 60k /// - [PlcLegacy, PlcEXRT] - FP2SH_60k = 0x3C_60, + [PlcLegacy, PlcEXRT, PlcCodeTested] + FP2SH_60k = 0x0060_60, /// /// FP2SH 120k /// [PlcLegacy, PlcEXRT] - FP2SH_120k = 0x78_E0, + FP2SH_120k = 0x0120_60, #endregion @@ -253,52 +261,52 @@ namespace MewtocolNet { /// FP-X 16k C14R /// [PlcLegacy, PlcEXRT, PlcCodeTested] - FPdX_16k__C14R = 0x10_70, + FPdX_16k__C14R = 0x0016_70, /// /// FP-X 32k C30R,C60R /// [PlcLegacy, PlcEXRT] - FPdX_32k__C30R_C60R = 0x20_71, + FPdX_32k__C30R_C60R = 0x0032_71, /// /// FP-X0 2.5k L14,L30 /// [PlcLegacy, PlcEXRT] - FPdX0_2c5k__L14_L30 = 0x02_72, + FPdX0_2c5k__L14_L30 = 0x0002_72, /// /// FP-X 16k L14 /// [PlcLegacy, PlcEXRT] - FPdX_16k__L14 = 0x10_73, + FPdX_16k__L14 = 0x0016_73, /// /// FP-X 32k L30,L60 /// [PlcLegacy, PlcEXRT] - FPdX_32k__L30_L60 = 0x20_74, + FPdX_32k__L30_L60 = 0x0032_74, /// /// FP-X0 8k L40,L60 /// [PlcLegacy, PlcEXRT] - FPdX0_8k__L40_L60 = 0x08_75, + FPdX0_8k__L40_L60 = 0x0008_75, /// /// FP-X 16k C14T/P /// [PlcLegacy, PlcEXRT] - FPdX_16k__C14TsP = 0x10_76, + FPdX_16k__C14TsP = 0x0016_76, /// /// FP-X 32k C30T/P,C60T/P,C38AT,C40T /// [PlcLegacy, PlcEXRT, PlcCodeTested] - FPdX_32k__C30TsP_C60TsP_C38AT_C40T = 0x20_77, + FPdX_32k__C30TsP_C60TsP_C38AT_C40T = 0x0032_77, /// /// FP-X 2.5k C40RT0A /// [PlcLegacy, PlcEXRT] - FPdX_2c5k__C40RT0A = 0x02_7A, + FPdX_2c5k__C40RT0A = 0x0002_7A, /// /// FP-X0 16k L40,L60 /// [PlcLegacy, PlcEXRT] - FPdX0_16k__L40_L60 = 0x10_7F, + FPdX0_16k__L40_L60 = 0x0016_7F, #endregion @@ -308,52 +316,52 @@ namespace MewtocolNet { /// FP-XH 16k C14R /// [PlcEXRT, PlcCodeTested] - FPdXH_16k__C14R = 0x10_A0, + FPdXH_16k__C14R = 0x0016_A0, /// /// FP-XH 32k C30R,C40R,C60R /// [PlcEXRT] - FPdXH_32k__C30R_C40R_C60R = 0x20_A1, + FPdXH_32k__C30R_C40R_C60R = 0x0032_A1, /// /// FP-XH 16k C14T/P /// [PlcEXRT] - FPdXH_16k__C14TsP = 0x10_A4, + FPdXH_16k__C14TsP = 0x0016_A4, /// /// FP-XH 32k C30T/P,C40T,C60T/P /// [PlcEXRT, PlcCodeTested] - FPdXH_32k__C30TsP_C40T_C60TsP = 0x20_A5, + FPdXH_32k__C30TsP_C40T_C60TsP = 0x0032_A5, /// /// FP-XH 32k C38AT /// [PlcEXRT] - FPdXH_32k__C38AT = 0x20_A7, + FPdXH_32k__C38AT = 0x0032_A7, /// /// FP-XH 32k M4T/L /// [PlcEXRT] - FPdXH_32k__M4TsL = 0x20_A8, + FPdXH_32k__M4TsL = 0x0032_A8, /// /// FP-XH 32k M8N16T/P (RTEX) /// [PlcEXRT] - FPdXH_32k__M8N16TsP = 0x20_AC, + FPdXH_32k__M8N16TsP = 0x0032_AC, /// /// FP-XH 32k M8N30T (RTEX) /// [PlcEXRT] - FPdXH_32k__M8N30T = 0x20_AD, + FPdXH_32k__M8N30T = 0x0032_AD, /// /// FP-XH 32k C40ET,C60ET /// [PlcEXRT] - FPdXH_32k__C40ET_C60ET = 0x20_AE, + FPdXH_32k__C40ET_C60ET = 0x0032_AE, /// /// FP-XH 32k C60ETF /// [PlcEXRT] - FPdXH_32k__C60ETF = 0x20_AF, + FPdXH_32k__C60ETF = 0x0032_AF, #endregion @@ -363,12 +371,12 @@ namespace MewtocolNet { /// FP0H 32k C32T/P /// [PlcEXRT] - FP0H_32k__C32TsP = 0x20_B0, + FP0H_32k__C32TsP = 0x0032_B0, /// /// FP0H 32k C32ET/EP /// [PlcEXRT] - FP0H_32k__C32ETsEP = 0x20_B1, + FP0H_32k__C32ETsEP = 0x0032_B1, #endregion @@ -377,31 +385,31 @@ namespace MewtocolNet { /// /// FP7 CPS41E (Series code 7) /// - FP7_196k__CPS41E = 0x07_C4_03, + FP7_196k__CPS41E = 0x07_0196_03, /// /// FP7 CPS31E (Series code 7) /// - FP7_120k__CPS31E = 0x07_78_04, + FP7_120k__CPS31E = 0x07_0120_04, /// /// FP7 CPS31 (Series code 7) /// - FP7_120k__CPS31 = 0x07_78_05, + FP7_120k__CPS31 = 0x07_0120_05, /// /// FP7 CPS41ES (Series code 7) /// - FP7_196k__CPS41ES = 0x07_C4_06, + FP7_196k__CPS41ES = 0x07_0196_06, /// /// FP7 CPS31ES (Series code 7) /// - FP7_120k__CPS31ES = 0x07_78_07, + FP7_120k__CPS31ES = 0x07_0120_07, /// /// FP7 CPS31S (Series code 7) /// - FP7_120k__CPS31S = 0x07_78_08, + FP7_120k__CPS31S = 0x07_0120_08, /// /// FP7 CPS21 (Series code 7) /// - FP7_64k__CPS21 = 0x07_40_09, + FP7_64k__CPS21 = 0x07_0064_09, #endregion @@ -411,7 +419,7 @@ namespace MewtocolNet { /// EcoLogiX (Series code 7) /// [PlcLegacy] - ECOLOGIX_0k__ELC500 = 0x07_00_10, + ECOLOGIX_0k__ELC500 = 0x07_0000_10, #endregion diff --git a/MewtocolTests/TestPlcTypeEnumDuplicates.cs b/MewtocolTests/TestPlcTypeEnumDuplicates.cs index 13df0af..ec04eb2 100644 --- a/MewtocolTests/TestPlcTypeEnumDuplicates.cs +++ b/MewtocolTests/TestPlcTypeEnumDuplicates.cs @@ -3,17 +3,64 @@ using Xunit; using Xunit.Abstractions; using MewtocolNet.Helpers; +using Newtonsoft.Json.Linq; +using System.Linq; namespace MewtocolTests { public class TestPlcTypeEnumDuplicates { + private readonly List allowedSynonims = new() { + + PlcType.FP1_0c9k__C14_C16.GetSynonims(), + PlcType.FPdM_2c7k__C20R_C20T_C32T.GetSynonims(), + PlcType.FPdM_5k__C20RC_C20TC_C32TC.GetSynonims(), + PlcType.FPdC_16k.GetSynonims(), + PlcType.FP10S_30k.GetSynonims(), + + }; + private readonly ITestOutputHelper output; public TestPlcTypeEnumDuplicates(ITestOutputHelper output) { this.output = output; } + [Fact(DisplayName = "Check if the PLC type enums contain duplicates")] + public void NumericRegisterMewtocolIdentifiers() { + + int nameCount = Enum.GetNames().Length; + int enumCount = Enum.GetValues().Cast().Distinct().Count(); + + var groupedCodes = Enum.GetValues().Cast().GroupBy(x => x); + + foreach (var item in groupedCodes) { + + if (item.Count() <= 1) continue; + + output.WriteLine($"Code: {item.Key.ToString("X6")}"); + + var synonims = ((PlcType)item.Key).GetSynonims(); + + var sononymousGroup = allowedSynonims.FirstOrDefault(x => x.Contains(synonims.First())); + + if (sononymousGroup == null) Assert.Fail($"The synonymous group doesn't exist ({synonims.First()})"); + + Assert.Equal(sononymousGroup.OrderBy(x => x).ToArray(), synonims.OrderBy(x => x).ToArray()); + + foreach (var syn in synonims) { + + output.WriteLine($"Synonim: {syn}"); + + } + + } + + output.WriteLine($"Indivual names: {nameCount}"); + output.WriteLine($"Indivual enums: {enumCount}"); + + } + } } \ No newline at end of file