diff --git a/DocBuilder/DocBuilder.csproj b/DocBuilder/DocBuilder.csproj new file mode 100644 index 0000000..70b2327 --- /dev/null +++ b/DocBuilder/DocBuilder.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/DocBuilder/Docs/plctypes.md b/DocBuilder/Docs/plctypes.md new file mode 100644 index 0000000..72e0eb9 --- /dev/null +++ b/DocBuilder/Docs/plctypes.md @@ -0,0 +1,509 @@ +# PLC Type Table +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 +> Discontinued PLCs
+> These are PLCs that are no longer sold by Panasonic. Marked with ⚠️ + +> EXRT PLCs
+> These are PLCs that utilize the basic `%EE#RT` and `%EE#EX00RT` command. All newer models do this. Old models only use the `%EE#RT` command. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeCapacityCodeEnumDCNTEXRTTested
πŸ“Ÿ FP0
C10, C14, C16 2.7k 0x40FP0_2c7k__C10_C14_C16⚠️ ❌ ❌
C32, SL1 5k 0x41FP0_5k__C32_SL1⚠️ ❌ ❌
T32 10k 0x42FP0_10c0k__T32⚠️ ❌ ❌
πŸ“Ÿ FP0H
C32T/P 32k 0xB0FP0H_32k__C32TsP βœ… ❌
C32ET/EP 32k 0xB1FP0H_32k__C32ETsEP βœ… ❌
πŸ“Ÿ FP0R
C10, C14, C16 16k 0x46FP0R_16k__C10_C14_C16 βœ… ❌
C32 32k 0x47FP0R_32k__C32 βœ… ❌
T32 32k 0x48FP0R_32k__T32 βœ… ❌
F32 32k 0x49FP0R_32k__F32 βœ… ❌
πŸ“Ÿ FP1
C14, C16 0.9k 0x04FP1_0c9k__C14_C16_OR_FPdM_0c9k__C16T⚠️ ❌ ❌
C16T 0.9k 0x04FP1_0c9k__C14_C16_OR_FPdM_0c9k__C16T⚠️ ❌ ❌
C24, C40 2.7k 0x05FP1_2c7k__C24_C40_OR_FPdM_2c7k__C20R_C20T_C32T⚠️ ❌ ❌
C20R, C20T, C32T 2.7k 0x05FP1_2c7k__C24_C40_OR_FPdM_2c7k__C20R_C20T_C32T⚠️ ❌ ❌
C56, C72 5k 0x06FP1_5k__C56_C72⚠️ ❌ ❌
πŸ“Ÿ FP10
- 30k 0x20FP10_30k_OR_FP10S_30k⚠️ ❌ ❌
- 30k 0x20FP10_30k_OR_FP10S_30k⚠️ ❌ ❌
πŸ“Ÿ FP10SH
- 30k 0x30FP10SH_30k⚠️ ❌ ❌
πŸ“Ÿ FP2
- 16k 0x50FP2_16k_OR_FP2_32k⚠️ ❌ ❌
- 32k 0x50FP2_16k_OR_FP2_32k⚠️ ❌ ❌
πŸ“Ÿ FP2SH
- 60k 0x60FP2SH_60k⚠️ βœ… ❌
- 32k 0x62FP2SH_32k⚠️ βœ… ❌
- 120k 0xE0FP2SH_120k⚠️ βœ… ❌
πŸ“Ÿ FP3
- 10k 0x03FP3_10k⚠️ ❌ ❌
- 16k 0x13FP3_16k_OR_FPdC_16k⚠️ ❌ ❌
- 16k 0x13FP3_16k_OR_FPdC_16k⚠️ ❌ ❌
πŸ“Ÿ FP5
- 16k 0x02FP5_16k⚠️ ❌ ❌
- 24k 0x12FP5_24k⚠️ ❌ ❌
πŸ“Ÿ FP-e
- 2.7k 0x45FPde_2c7k⚠️ βœ… ❌
πŸ“Ÿ FP-SIGMA
- 12k 0x43FPdSIGMA_12k⚠️ βœ… ❌
- 32k 0x44FPdSIGMA_32k⚠️ βœ… ❌
- 16k 0xE1FPdSIGMA_16k⚠️ βœ… ❌
πŸ“Ÿ FP-X
C14R 16k 0x70FPdX_16k__C14R⚠️ βœ… βœ…
C30R, C60R 32k 0x71FPdX_32k__C30R_C60R⚠️ βœ… ❌
L14 16k 0x73FPdX_16k__L14⚠️ βœ… ❌
L30, L60 32k 0x74FPdX_32k__L30_L60⚠️ βœ… ❌
C14T/P 16k 0x76FPdX_16k__C14TsP⚠️ βœ… ❌
C30T/P, C60T/P, C38AT, C40T 32k 0x77FPdX_32k__C30TsP_C60TsP_C38AT_C40T⚠️ βœ… βœ…
C40RT0A 2.5k 0x7AFPdX_2c5k__C40RT0A⚠️ βœ… ❌
πŸ“Ÿ FP-X0
L14, L30 2.5k 0x72FPdX0_2c5k__L14_L30⚠️ βœ… ❌
L40, L60 8k 0x75FPdX0_8k__L40_L60⚠️ βœ… ❌
L40, L60 16k 0x7FFPdX0_16k__L40_L60⚠️ βœ… ❌
πŸ“Ÿ FP-XH
C14R 16k 0xA0FPdXH_16k__C14R βœ… βœ…
C30R, C40R, C60R 32k 0xA1FPdXH_32k__C30R_C40R_C60R βœ… ❌
C14T/P 16k 0xA4FPdXH_16k__C14TsP βœ… ❌
C30T/P, C40T, C60T/P 32k 0xA5FPdXH_32k__C30TsP_C40T_C60TsP βœ… βœ…
C38AT 32k 0xA7FPdXH_32k__C38AT βœ… ❌
M4T/L 32k 0xA8FPdXH_32k__M4TsL βœ… ❌
M8N16T/P 32k 0xACFPdXH_32k__M8N16TsP βœ… ❌
M8N30T 32k 0xADFPdXH_32k__M8N30T βœ… ❌
C40ET, C60ET 32k 0xAEFPdXH_32k__C40ET_C60ET βœ… ❌
C60ETF 32k 0xAFFPdXH_32k__C60ETF βœ… ❌
+ + diff --git a/DocBuilder/Docs/reverse_engineering_data.md b/DocBuilder/Docs/reverse_engineering_data.md new file mode 100644 index 0000000..0bb6a8c --- /dev/null +++ b/DocBuilder/Docs/reverse_engineering_data.md @@ -0,0 +1,97 @@ +# Open Questions + +- What is the HW information byte for? +- What are the last bytes of the EXRT message for? + +# Actual Readouts + +| PLC TYPE | CPU Code | Machine Code | HW Information| +|--------------|--------------|--------------|---------------| +| FPX C14 R | 20 | 70 | 02 | +| FPX C30 T | 20 | 77 | 02 | +| FPX-H C14 R | 20 | A0 | 01 | +| FPX-H C30 T | 20 | A5 | 01 | + +## FPX 16k C14R Actual Response Examples + +### %EE$RT + +|Reponse Byte|Description| +|------------|-----------| +| 20 | Model code | +| 25 | Version | +| 16 | Prog capacity | +| 80 | Op mode | +| 00 | Link unit | +| E1 | Error flag | +| 2D00 | Self diag error | + +### %EE$EX00RT Normal Operation + +|Reponse Byte|Description| +|------------|-----------| +| 00 | Extended mode +| 32 | Data item count +| 70 | Machine type +| 00 | Version (Fixed to 00) +| 16 | Prog capacity in K +| 80 | Operation mode / status +| 00 | Link unit +| E1 | Error flag +| 2D00 | Self diag error +| 50 | Version +| 02 | Hardware information +| 0 | Number of programs +| 4100 | Program size BCD +| 1600 | Header size (no. of words) bcd +| 1604 | System register size +| 96230000001480004 | ? + +### %EE$EX00RT with error + +|Reponse Byte|Description| +|------------|-----------| +| 00 | Extended mode +| 32 | Data item count +| 70 | Machine type +| 00 | Version (Fixed to 00) +| 16 | Prog capacity in K +| 81 | Operation mode / status +| 00 | Link unit +| 60 | Error flag +| 0000 | Self diag error +| 50 | Version +| 02 | Hardware information +| 0 | Number of programs +| 4100 | Program size BCD +| 1600 | Header size (no. of words) bcd +| 1604 | System register size +| 96230000001480004 | ? + +What are the last bytes? + +FP-X 16k C14R +96 23 00 00 00 14 80 00 4 + +FP-X 32k C30T/P +96 23 00 00 00 14 80 00 4 + +FP-XH 32k C30T/P +96 23 00 00 00 40 00 00 4 + +FP-XH 16k C14R +96 23 00 00 00 40 00 00 4 + +## FP-XH 16k C14R Actual Response Examples + +### %EE$RT + +|Reponse Byte|Description| +|------------|-----------| +| 20 | Model code | +| 16 | Version | +| 16 | Prog capacity | +| 81 | Op mode | +| 00 | Link unit | +| 60 | Error flag | +| 0000 | Self diag error | \ No newline at end of file diff --git a/DocBuilder/Program.cs b/DocBuilder/Program.cs new file mode 100644 index 0000000..c5333ea --- /dev/null +++ b/DocBuilder/Program.cs @@ -0,0 +1,135 @@ +ο»Ώ//This program builds Markdown and docs for all kinds of data + +using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; +using System.Reflection; +using System.Reflection.PortableExecutable; +using System.Text; +using MewtocolNet; +using MewtocolNet.DocAttributes; + +Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; +Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + +Console.WriteLine("Building docs for PLC types..."); + +var entryLoc = Assembly.GetEntryAssembly(); +ArgumentNullException.ThrowIfNull(entryLoc); + +string filePath = Path.Combine(entryLoc.Location, @"..\..\..\..\Docs\plctypes.md"); +Console.WriteLine($"{filePath}"); + +StringBuilder markdownBuilder = new StringBuilder(); + +var plcs = Enum.GetValues(typeof(PlcType)).Cast().OrderBy(x => x.ToString()); + +void WritePlcTypeTable(IEnumerable vals) { + + var groups = vals.GroupBy(x => x.ToNameDecompose()[0].Group) + .SelectMany(grouping => grouping.OrderBy(b => (int)b)) + .GroupBy(x => x.ToNameDecompose()[0].Group); + + markdownBuilder.AppendLine(""); + + bool isFirstIt = true; + + foreach (var group in groups) { + + group.OrderBy(x => (int)x); + + bool isFirstGroup = true; + + foreach (var enu in group) { + + ParsedPlcName[] decomposed = null!; + string cpuOrMachCode = null!; + + decomposed = enu.ToNameDecompose(); + + cpuOrMachCode = ((int)enu).ToString("X2"); + ArgumentNullException.ThrowIfNull(decomposed); + + //first iteration + if (isFirstIt) { + + markdownBuilder.AppendLine(""); + + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + + markdownBuilder.AppendLine(""); + + isFirstIt = false; + + } + + if(isFirstGroup) { + + markdownBuilder.AppendLine(""); + + markdownBuilder.AppendLine($""); + + markdownBuilder.AppendLine(""); + + isFirstGroup = false; + + } + + foreach (var decomp in decomposed) { + + markdownBuilder.AppendLine(""); + + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + + if(enu.IsDiscontinued()) { + + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + + } else { + + markdownBuilder.AppendLine($""); + + } + + markdownBuilder.AppendLine($""); + markdownBuilder.AppendLine($""); + + markdownBuilder.AppendLine(""); + + } + + + } + + isFirstIt = false; + + } + + markdownBuilder.AppendLine("
TypeCapacityCodeEnumDCNTEXRTTested
πŸ“Ÿ {group.Key}
{(decomp.SubTypes.Length == 0 ? "-" : string.Join(", ", decomp.SubTypes))} {decomp.Size}k 0x{cpuOrMachCode}{enu.ToString()}⚠️{enu.ToString()} {(enu.IsEXRTPLC() ? "βœ…" : "❌")} {(enu.WasTestedLive() ? "βœ…" : "❌")}
"); + markdownBuilder.AppendLine("\n"); + +} + +markdownBuilder.AppendLine($"# PLC Type Table"); +markdownBuilder.AppendLine($"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"); + +markdownBuilder.AppendLine($"> Discontinued PLCs
"); +markdownBuilder.AppendLine($"> These are PLCs that are no longer sold by Panasonic. Marked with ⚠️\n"); + +markdownBuilder.AppendLine($"> EXRT PLCs
"); +markdownBuilder.AppendLine($"> These are PLCs that utilize the basic `%EE#RT` and `%EE#EX00RT` command. All newer models do this. Old models only use the `%EE#RT` command.\n"); + +WritePlcTypeTable(plcs); + + +File.WriteAllText(filePath, markdownBuilder.ToString()); \ No newline at end of file diff --git a/MewtocolNet.sln b/MewtocolNet.sln index 2550c60..0fe6862 100644 --- a/MewtocolNet.sln +++ b/MewtocolNet.sln @@ -9,7 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Examples", "Examples\Exampl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MewtocolTests", "MewtocolTests\MewtocolTests.csproj", "{C1BF3AB0-CDFE-4070-A759-C3B25A20ABE1}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MewExplorer", "MewExplorer\MewExplorer.csproj", "{F243F38A-76D3-4C38-BAE6-C61729479661}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MewExplorer", "MewExplorer\MewExplorer.csproj", "{F243F38A-76D3-4C38-BAE6-C61729479661}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocBuilder", "DocBuilder\DocBuilder.csproj", "{50F2D23F-C875-4006-A0B6-7F5A181BC944}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -75,6 +77,18 @@ Global {F243F38A-76D3-4C38-BAE6-C61729479661}.Release|x86.ActiveCfg = Release|Any CPU {F243F38A-76D3-4C38-BAE6-C61729479661}.Release|x86.Build.0 = Release|Any CPU {F243F38A-76D3-4C38-BAE6-C61729479661}.Release|x86.Deploy.0 = Release|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Debug|x64.ActiveCfg = Debug|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Debug|x64.Build.0 = Debug|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Debug|x86.ActiveCfg = Debug|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Debug|x86.Build.0 = Debug|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Release|Any CPU.Build.0 = Release|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Release|x64.ActiveCfg = Release|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Release|x64.Build.0 = Release|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Release|x86.ActiveCfg = Release|Any CPU + {50F2D23F-C875-4006-A0B6-7F5A181BC944}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MewtocolNet/CpuInfo.cs b/MewtocolNet/CpuInfo.cs index 969226f..273e636 100644 --- a/MewtocolNet/CpuInfo.cs +++ b/MewtocolNet/CpuInfo.cs @@ -26,36 +26,6 @@ namespace MewtocolNet { CpuInfo retInf = new CpuInfo(); - switch (_cpuType) { - case "02": - retInf.Cputype = CpuType.FP5_16K; - break; - case "03": - retInf.Cputype = CpuType.FP3_C_10K; - break; - case "04": - retInf.Cputype = CpuType.FP1_M_0_9K; - break; - case "05": - retInf.Cputype = CpuType.FP0_FP1_2_7K; - break; - case "06": - retInf.Cputype = CpuType.FP0_FP1_5K_10K; - break; - case "12": - retInf.Cputype = CpuType.FP5_24K; - break; - case "13": - retInf.Cputype = CpuType.FP3_C_16K; - break; - case "20": - retInf.Cputype = CpuType.FP_Sigma_X_H_30K_60K_120K; - break; - case "50": - retInf.Cputype = CpuType.FP2_16K_32K; - break; - } - retInf.ProgramCapacity = Convert.ToInt32(_progCapacity); retInf.CpuVersion = _cpuVersion.Insert(1, "."); return retInf; diff --git a/MewtocolNet/DocAttributes/PlcCodeTestedAttribute.cs b/MewtocolNet/DocAttributes/PlcCodeTestedAttribute.cs new file mode 100644 index 0000000..3883f15 --- /dev/null +++ b/MewtocolNet/DocAttributes/PlcCodeTestedAttribute.cs @@ -0,0 +1,14 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Text; + +namespace MewtocolNet.DocAttributes { + + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] + internal class PlcCodeTestedAttribute : Attribute { + + public PlcCodeTestedAttribute() { } + + } + +} \ No newline at end of file diff --git a/MewtocolNet/DocAttributes/PlcEXRTAttribute.cs b/MewtocolNet/DocAttributes/PlcEXRTAttribute.cs new file mode 100644 index 0000000..1975a52 --- /dev/null +++ b/MewtocolNet/DocAttributes/PlcEXRTAttribute.cs @@ -0,0 +1,14 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Text; + +namespace MewtocolNet.DocAttributes { + + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] + internal class PlcEXRTAttribute : Attribute { + + public PlcEXRTAttribute() {} + + } + +} diff --git a/MewtocolNet/DocAttributes/PlcLegacyAttribute.cs b/MewtocolNet/DocAttributes/PlcLegacyAttribute.cs new file mode 100644 index 0000000..01367dc --- /dev/null +++ b/MewtocolNet/DocAttributes/PlcLegacyAttribute.cs @@ -0,0 +1,14 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Text; + +namespace MewtocolNet.DocAttributes { + + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] + internal class PlcLegacyAttribute : Attribute { + + public PlcLegacyAttribute() {} + + } + +} diff --git a/MewtocolNet/Helpers/MewtocolHelpers.cs b/MewtocolNet/Helpers/MewtocolHelpers.cs index 1b4f071..33e692e 100644 --- a/MewtocolNet/Helpers/MewtocolHelpers.cs +++ b/MewtocolNet/Helpers/MewtocolHelpers.cs @@ -1,4 +1,5 @@ -ο»Ώusing System; +ο»Ώusing MewtocolNet.DocAttributes; +using System; using System.Collections; using System.Collections.Generic; using System.Globalization; @@ -315,6 +316,77 @@ namespace MewtocolNet { #endregion + #region PLC Type Enum Parsing + + /// + /// Converts the enum to a plc name string + /// + public static string ToName(this PlcType plcT) { + + return string.Join(" or ", ParsedPlcName.LegacyPlcDeconstruct(plcT).Select(x => x.WholeName)); + + } + + /// + /// Converts the enum to a decomposed struct + /// + public static ParsedPlcName[] ToNameDecompose (this PlcType legacyT) { + + return ParsedPlcName.LegacyPlcDeconstruct(legacyT); + + } + + /// + /// Checks if the PLC type is discontinued + /// + public static bool IsDiscontinued (this PlcType plcT) { + + var memberInfos = plcT.GetType().GetMember(plcT.ToString()); + var enumValueMemberInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == plcT.GetType()); + var valueAttributes = enumValueMemberInfo?.GetCustomAttributes(typeof(PlcLegacyAttribute), false); + if (valueAttributes != null) { + var found = valueAttributes.FirstOrDefault(x => x.GetType() == typeof(PlcLegacyAttribute)); + if (found != null) return true; + } + + return false; + + } + + #if DEBUG + + internal static bool WasTestedLive (this PlcType plcT) { + + var memberInfos = plcT.GetType().GetMember(plcT.ToString()); + var enumValueMemberInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == plcT.GetType()); + var valueAttributes = enumValueMemberInfo?.GetCustomAttributes(typeof(PlcCodeTestedAttribute), false); + if (valueAttributes != null) { + var found = valueAttributes.FirstOrDefault(x => x.GetType() == typeof(PlcCodeTestedAttribute)); + if (found != null) return true; + } + + return false; + + } + + internal static bool IsEXRTPLC (this PlcType plcT) { + + var memberInfos = plcT.GetType().GetMember(plcT.ToString()); + var enumValueMemberInfo = memberInfos.FirstOrDefault(m => m.DeclaringType == plcT.GetType()); + var valueAttributes = enumValueMemberInfo?.GetCustomAttributes(typeof(PlcEXRTAttribute), false); + if (valueAttributes != null) { + var found = valueAttributes.FirstOrDefault(x => x.GetType() == typeof(PlcEXRTAttribute)); + if (found != null) return true; + } + + return false; + + } + + #endif + + #endregion + } } \ No newline at end of file diff --git a/MewtocolNet/Helpers/ParsedPlcName.cs b/MewtocolNet/Helpers/ParsedPlcName.cs new file mode 100644 index 0000000..d4d266c --- /dev/null +++ b/MewtocolNet/Helpers/ParsedPlcName.cs @@ -0,0 +1,95 @@ +ο»Ώusing System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace MewtocolNet { + + /// + /// A structure containing the PLC name parsed + /// + public struct ParsedPlcName { + + /// + /// Whole name of the PLC + /// + public string WholeName { get; internal set; } + + /// + /// The family group of the PLC + /// + public string Group { get; internal set; } + + /// + /// The Memory size of the PLC + /// + public float Size { get; internal set; } + + /// + /// The subtype strings of the plc + /// + public string[] SubTypes { get; internal set; } + + /// + public override string ToString() => WholeName; + + internal static ParsedPlcName[] LegacyPlcDeconstruct (T legacyT) { + + string wholeStr = legacyT.ToString(); + + var split = wholeStr.Replace("_OR_", "|").Split('|'); + var reg = new Regex(@"(?[A-Za-z0-9]*)_(?[A-Za-z0-9]*)(?:__)?(?.*)"); + + var retList = new List(); + + foreach (var item in split) { + + var match = reg.Match(item); + + if (match.Success) { + + string groupStr = SanitizePlcEncodedString(match.Groups["group"].Value); + string sizeStr = SanitizePlcEncodedString(match.Groups["size"].Value); + float sizeFl = float.Parse(sizeStr.Replace("k", ""), NumberStyles.Float, CultureInfo.InvariantCulture); + string additionalStr = match.Groups["additional"].Value; + string[] subTypes = additionalStr.Split('_').Select(x => SanitizePlcEncodedString(x)).ToArray(); + + string wholeName = $"{groupStr} {sizeFl:0.##}k{(subTypes.Length > 1 ? " " : "")}{string.Join(",", subTypes)}"; + + if (string.IsNullOrEmpty(subTypes[0])) + subTypes = Array.Empty(); + + retList.Add(new ParsedPlcName { + Group = groupStr, + Size = sizeFl, + SubTypes = subTypes, + WholeName = wholeName, + }); + + } else { + + throw new FormatException($"The plc enum was not formatted correctly: {item}"); + + } + + } + + return retList.ToArray(); + + } + + private static string SanitizePlcEncodedString(string input) { + + input = input.Replace("d", "-"); + input = input.Replace("c", "."); + input = input.Replace("s", "/"); + + return input; + + } + + } + +} diff --git a/MewtocolNet/MewtocolInterfaceRequests.cs b/MewtocolNet/MewtocolInterfaceRequests.cs index 75e8906..e9506fa 100644 --- a/MewtocolNet/MewtocolInterfaceRequests.cs +++ b/MewtocolNet/MewtocolInterfaceRequests.cs @@ -19,36 +19,36 @@ namespace MewtocolNet { /// Gets generic information about the PLC /// /// A PLCInfo class - public async Task GetPLCInfoAsync(int timeout = -1) { + public async Task GetPLCInfoAsync(int timeout = -1) { - var resu = await SendCommandAsync("%01#RT", true, timeout); - if (!resu.Success) return null; + //var resu = await SendCommandAsync("%01#RT", true, timeout); + //if (!resu.Success) return null; - var reg = new Regex(@"\%([0-9]{2})\$RT([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{4})..", RegexOptions.IgnoreCase); - Match m = reg.Match(resu.Response); + //var reg = new Regex(@"\%([0-9]{2})\$RT([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{4})..", RegexOptions.IgnoreCase); + //Match m = reg.Match(resu.Response); - if (m.Success) { + //if (m.Success) { - string station = m.Groups[1].Value; - string cpu = m.Groups[2].Value; - string version = m.Groups[3].Value; - string capacity = m.Groups[4].Value; - string operation = m.Groups[5].Value; + // string station = m.Groups[1].Value; + // string cpu = m.Groups[2].Value; + // string version = m.Groups[3].Value; + // string capacity = m.Groups[4].Value; + // string operation = m.Groups[5].Value; - string errorflag = m.Groups[7].Value; - string error = m.Groups[8].Value; + // string errorflag = m.Groups[7].Value; + // string error = m.Groups[8].Value; - PLCInfo retInfo = new PLCInfo { - CpuInformation = CpuInfo.BuildFromHexString(cpu, version, capacity), - OperationMode = PLCMode.BuildFromHex(operation), - ErrorCode = error, - StationNumber = int.Parse(station ?? "0"), - }; + // PLCInfo retInfo = new PLCInfo { + // CpuInformation = CpuInfo.BuildFromHexString(cpu, version, capacity), + // OperationMode = PLCMode.BuildFromHex(operation), + // ErrorCode = error, + // StationNumber = int.Parse(station ?? "0"), + // }; - PlcInfo = retInfo; - return retInfo; + // PlcInfo = retInfo; + // return retInfo; - } + //} return null; @@ -291,13 +291,6 @@ namespace MewtocolNet { #region Reading / Writing Plc program - public async Task ReadPLCProgramAsync () { - - var cmd = SendCommandAsync($""); - - - } - public async Task GetSystemRegister () { //the "." means CR or \r @@ -308,62 +301,7 @@ namespace MewtocolNet { // %EE#EX00RT00 await SendCommandAsync("%EE#EX00RT00"); - //fpx C14 r - //%EE$EX00 RT - //00 Extended mode - //32 Data item count - //70 Machine type - //00 Version (Fixed to 00) - //16 Prog capacity in K - //81 Operation mode / status - //00 Link unit - //60 Error flag - //0000 Self diag error - //50 Version - //02 Hardware information - //0 Number of programs - //4100 Program size BCD - //1600 Header size (no. of words) bcd - //1604 System register size - //96230000001480004 ?? - // - - // PLC TYPE | Machine Code | HW Information - // FPX C14 R | 70 | 02 - // FPX C30 T | 77 | 02 - - // FPX-H C14 R | A0 | 01 - // FPX-H C30 T | A5 | 01 - - - //then a sequence of these is sent - - // Specifiy register for monitoring - // %EE#MDFFFFFF - //await SendCommandAsync("%EE#MDFFFFFF"); - - // reset monitor registers - // %EE#MCFFFFF -> gets ackn - //await SendCommandAsync("%EE#MCFFFFF"); - - // maybe some special registers? - // %EE#MCR9029R0000R0000R0000R0000R0000R0000R0000 -> gets ackn - //await SendCommandAsync("%EE#MCR9029R0000R0000R0000R0000R0000R0000R0000"); - - // gets requested when opening plc status - // %EE#MG - // has a response like: - - //await SendCommandAsync("%EE#MG"); - - - //var res = cmd.Response.Replace("%01$RR", ""); - - //var parts = res.SplitInParts(4); - - //foreach (var part in parts) - // Console.WriteLine(part); } diff --git a/MewtocolNet/MewtocolInterfaceSerial.cs b/MewtocolNet/MewtocolInterfaceSerial.cs index 8d692a0..62abbc8 100644 --- a/MewtocolNet/MewtocolInterfaceSerial.cs +++ b/MewtocolNet/MewtocolInterfaceSerial.cs @@ -122,7 +122,7 @@ namespace MewtocolNet { try { - PLCInfo gotInfo = null; + PLCInfo? gotInfo = null; if(autoSerial) { @@ -138,7 +138,7 @@ namespace MewtocolNet { if(gotInfo != null) { - OnConnected(gotInfo); + OnConnected(gotInfo.Value); } else { @@ -159,7 +159,7 @@ namespace MewtocolNet { } - private async Task TryConnectAsyncMulti () { + private async Task TryConnectAsyncMulti () { var baudRates = Enum.GetValues(typeof(BaudRate)).Cast(); @@ -205,7 +205,7 @@ namespace MewtocolNet { } - private async Task TryConnectAsyncSingle (string port, int baud, int dbits, Parity par, StopBits sbits) { + private async Task TryConnectAsyncSingle (string port, int baud, int dbits, Parity par, StopBits sbits) { try { diff --git a/MewtocolNet/MewtocolInterfaceTcp.cs b/MewtocolNet/MewtocolInterfaceTcp.cs index 3d25c16..af5ffb2 100644 --- a/MewtocolNet/MewtocolInterfaceTcp.cs +++ b/MewtocolNet/MewtocolInterfaceTcp.cs @@ -132,7 +132,7 @@ namespace MewtocolNet { if (plcinf != null) { - OnConnected(plcinf); + OnConnected(plcinf.Value); } else { diff --git a/MewtocolNet/MewtocolNet.csproj b/MewtocolNet/MewtocolNet.csproj index a172606..2bb9118 100644 --- a/MewtocolNet/MewtocolNet.csproj +++ b/MewtocolNet/MewtocolNet.csproj @@ -18,12 +18,17 @@ ..\Builds\MewtocolNet.xml ..\Builds - - - <_Parameter1>MewtocolTests - - - - - + + + <_Parameter1>MewtocolTests + + + + + <_Parameter1>DocBuilder + + + + + diff --git a/MewtocolNet/PLCInfo.cs b/MewtocolNet/PLCInfo.cs index 4b1b46d..939bd59 100644 --- a/MewtocolNet/PLCInfo.cs +++ b/MewtocolNet/PLCInfo.cs @@ -1,8 +1,32 @@ ο»Ώnamespace MewtocolNet { + + + public enum CpuType { + + + + } + + public struct PLCInfo { + + /// + /// Current error code of the PLC + /// + public string ErrorCode { get; internal set; } + + /// + /// Current station number of the PLC + /// + public int StationNumber { get; internal set; } + + + } + /// /// Contains generic information about the plc /// - public class PLCInfo { + public class PLCInfoOld + { /// /// Contains information about the PLCs cpu @@ -12,6 +36,7 @@ /// Contains information about the PLCs operation modes /// public PLCMode OperationMode { get; set; } + /// /// Current error code of the PLC /// diff --git a/MewtocolNet/PublicEnums/CpuType.cs b/MewtocolNet/PublicEnums/CpuType.cs deleted file mode 100644 index 9312177..0000000 --- a/MewtocolNet/PublicEnums/CpuType.cs +++ /dev/null @@ -1,46 +0,0 @@ -ο»Ώnamespace MewtocolNet { - - /// - /// CPU type of the PLC - /// - public enum CpuType { - /// - /// FP 0 / FP 2.7K - /// - FP0_FP1_2_7K, - /// - /// FP0 / FP1, 5K / 10K - /// - FP0_FP1_5K_10K, - /// - /// FP1 M 0.9K - /// - FP1_M_0_9K, - /// - /// FP2 16k / 32k - /// - FP2_16K_32K, - /// - /// FP3 C 10K - /// - FP3_C_10K, - /// - /// FP3 C 16K - /// - FP3_C_16K, - /// - /// FP5 16K - /// - FP5_16K, - /// - /// FP 5 24K - /// - FP5_24K, - /// - /// Includes panasonic FPX, FPX-H, Sigma - /// - FP_Sigma_X_H_30K_60K_120K - - } - -} \ No newline at end of file diff --git a/MewtocolNet/PublicEnums/PlcType.cs b/MewtocolNet/PublicEnums/PlcType.cs new file mode 100644 index 0000000..66e01ca --- /dev/null +++ b/MewtocolNet/PublicEnums/PlcType.cs @@ -0,0 +1,323 @@ +ο»Ώusing MewtocolNet.DocAttributes; + +namespace MewtocolNet { + + //this overwrites the CPU code and only comes with EXRT + //special chars: (d = -) (c = .) (s = /) + + /// + /// The type of the PLC + /// + public enum PlcType { + + #region FP5 Family (Legacy) + + /// + /// FP5 16k + /// + [PlcLegacy] + FP5_16k = 0x02, + + /// + /// FP5 24k + /// + [PlcLegacy] + FP5_24k = 0x12, + + #endregion + + #region FP2 Family (Legacy) + + /// + /// FP2 16k OR FP2 32k + /// + [PlcLegacy] + FP2_16k_OR_FP2_32k = 0x50, + + //misses entry FP2 32k + + #endregion + + #region FP3/FP-C Family (Legacy) + + /// + /// FP3 10k + /// + [PlcLegacy] + FP3_10k = 0x03, + /// + /// FP3 or FP-C 16k + /// + [PlcLegacy] + FP3_16k_OR_FPdC_16k = 0x13, + + #endregion + + #region FP1 / FPM Family (Legacy) + + /// + /// FP1 0.9k C14,C16 or FP-M 0.9k C16T + /// + [PlcLegacy] + FP1_0c9k__C14_C16_OR_FPdM_0c9k__C16T = 0x04, + /// + /// FP1 2.7k C24,C40 or FP-M 2.7k C20R,C20T,C32T + /// + [PlcLegacy] + FP1_2c7k__C24_C40_OR_FPdM_2c7k__C20R_C20T_C32T = 0x05, + /// + /// FP1 5.0k C56,C72 + /// + [PlcLegacy] + FP1_5k__C56_C72 = 0x06, + + #endregion + + #region FP10 Family (Legacy) + + /// + /// FP10 OR FP10S 30k + /// + [PlcLegacy] + FP10_30k_OR_FP10S_30k = 0x20, + + //misses entry FP10 60k + + #endregion + + #region FP10SH Family (Legacy) + + /// + /// FP10SH 30k + /// + [PlcLegacy] + FP10SH_30k = 0x30, + + //misses entry FP10SH 60k + //misses entry FP10SH 120k + + #endregion + + #region FP0 Family (Legacy) + + /// + /// FP0 2.7k C10,C14,C16 + /// + [PlcLegacy] + FP0_2c7k__C10_C14_C16 = 0x40, + /// + /// FP0 5k + /// + [PlcLegacy] + FP0_5k__C32_SL1 = 0x41, + /// + /// FP0 10k + /// + [PlcLegacy] + FP0_10c0k__T32 = 0x42, + + #endregion + + #region FP-Sigma Family (Legacy) + + /// + /// FP-Sigma 12k + /// + [PlcLegacy, PlcEXRT] + FPdSIGMA_12k = 0x43, + /// + /// FP-Sigma 32k + /// + [PlcLegacy, PlcEXRT] + FPdSIGMA_32k = 0x44, + /// + /// FP-SIGMA 16k + /// + [PlcLegacy, PlcEXRT] + FPdSIGMA_16k = 0xE1, + + #endregion + + #region FP-e Family (Legacy) + + /// + /// FP-e 2.7k + /// + [PlcLegacy, PlcEXRT] + FPde_2c7k = 0x45, + + #endregion + + #region FP0R Family + + /// + /// FP0R 16k C10,C14,C16 + /// + [PlcEXRT] + FP0R_16k__C10_C14_C16 = 0x46, + /// + /// FP0R 32k C32 + /// + [PlcEXRT] + FP0R_32k__C32 = 0x47, + /// + /// FP0R 32k T32 + /// + [PlcEXRT] + FP0R_32k__T32 = 0x48, + /// + /// FP0R 32k F32 + /// + [PlcEXRT] + FP0R_32k__F32 = 0x49, + + #endregion + + #region FP2SH Family (Legacy) + + /// + /// FP2SH 60k + /// + [PlcLegacy, PlcEXRT] + FP2SH_60k = 0x60, + /// + /// FP2SH 32k + /// + [PlcLegacy, PlcEXRT] + FP2SH_32k = 0x62, + /// + /// FP2SH 120k + /// + [PlcLegacy, PlcEXRT] + FP2SH_120k = 0xE0, + + #endregion + + #region FP-X Family (Legacy) + + /// + /// FP-X 16k C14R + /// + [PlcLegacy, PlcEXRT, PlcCodeTested] + FPdX_16k__C14R = 0x70, + /// + /// FP-X 32k C30R,C60R + /// + [PlcLegacy, PlcEXRT] + FPdX_32k__C30R_C60R = 0x71, + /// + /// FP-X0 2.5k L14,L30 + /// + [PlcLegacy, PlcEXRT] + FPdX0_2c5k__L14_L30 = 0x72, + /// + /// FP-X 16k L14 + /// + [PlcLegacy, PlcEXRT] + FPdX_16k__L14 = 0x73, + /// + /// FP-X 32k L30,L60 + /// + [PlcLegacy, PlcEXRT] + FPdX_32k__L30_L60 = 0x74, + /// + /// FP-X0 8k L40,L60 + /// + [PlcLegacy, PlcEXRT] + FPdX0_8k__L40_L60 = 0x75, + /// + /// FP-X 16k C14T/P + /// + [PlcLegacy, PlcEXRT] + FPdX_16k__C14TsP = 0x76, + /// + /// FP-X 32k C30T/P,C60T/P,C38AT,C40T + /// + [PlcLegacy, PlcEXRT, PlcCodeTested] + FPdX_32k__C30TsP_C60TsP_C38AT_C40T = 0x77, + /// + /// FP-X 2.5k C40RT0A + /// + [PlcLegacy, PlcEXRT] + FPdX_2c5k__C40RT0A = 0x7A, + /// + /// FP-X0 16k L40,L60 + /// + [PlcLegacy, PlcEXRT] + FPdX0_16k__L40_L60 = 0x7F, + + #endregion + + #region FP-XH Family + + /// + /// FP-XH 16k C14R + /// + [PlcEXRT, PlcCodeTested] + FPdXH_16k__C14R = 0xA0, + /// + /// FP-XH 32k C30R,C40R,C60R + /// + [PlcEXRT] + FPdXH_32k__C30R_C40R_C60R = 0xA1, + /// + /// FP-XH 16k C14T/P + /// + [PlcEXRT] + FPdXH_16k__C14TsP = 0xA4, + /// + /// FP-XH 32k C30T/P,C40T,C60T/P + /// + [PlcEXRT, PlcCodeTested] + FPdXH_32k__C30TsP_C40T_C60TsP = 0xA5, + /// + /// FP-XH 32k C38AT + /// + [PlcEXRT] + FPdXH_32k__C38AT = 0xA7, + /// + /// FP-XH 32k M4T/L + /// + [PlcEXRT] + FPdXH_32k__M4TsL = 0xA8, + /// + /// FP-XH 32k M8N16T/P (RTEX) + /// + [PlcEXRT] + FPdXH_32k__M8N16TsP = 0xAC, + /// + /// FP-XH 32k M8N30T (RTEX) + /// + [PlcEXRT] + FPdXH_32k__M8N30T = 0xAD, + /// + /// FP-XH 32k C40ET,C60ET + /// + [PlcEXRT] + FPdXH_32k__C40ET_C60ET = 0xAE, + /// + /// FP-XH 32k C60ETF + /// + [PlcEXRT] + FPdXH_32k__C60ETF = 0xAF, + + #endregion + + #region FP0H Family + + /// + /// FP0H 32k C32T/P + /// + [PlcEXRT] + FP0H_32k__C32TsP = 0xB0, + /// + /// FP0H 32k C32ET/EP + /// + [PlcEXRT] + FP0H_32k__C32ETsEP = 0xB1, + + #endregion + + } + +} \ No newline at end of file diff --git a/MewtocolNet/ReverseEngineering.md b/MewtocolNet/ReverseEngineering.md new file mode 100644 index 0000000..0bb6a8c --- /dev/null +++ b/MewtocolNet/ReverseEngineering.md @@ -0,0 +1,97 @@ +# Open Questions + +- What is the HW information byte for? +- What are the last bytes of the EXRT message for? + +# Actual Readouts + +| PLC TYPE | CPU Code | Machine Code | HW Information| +|--------------|--------------|--------------|---------------| +| FPX C14 R | 20 | 70 | 02 | +| FPX C30 T | 20 | 77 | 02 | +| FPX-H C14 R | 20 | A0 | 01 | +| FPX-H C30 T | 20 | A5 | 01 | + +## FPX 16k C14R Actual Response Examples + +### %EE$RT + +|Reponse Byte|Description| +|------------|-----------| +| 20 | Model code | +| 25 | Version | +| 16 | Prog capacity | +| 80 | Op mode | +| 00 | Link unit | +| E1 | Error flag | +| 2D00 | Self diag error | + +### %EE$EX00RT Normal Operation + +|Reponse Byte|Description| +|------------|-----------| +| 00 | Extended mode +| 32 | Data item count +| 70 | Machine type +| 00 | Version (Fixed to 00) +| 16 | Prog capacity in K +| 80 | Operation mode / status +| 00 | Link unit +| E1 | Error flag +| 2D00 | Self diag error +| 50 | Version +| 02 | Hardware information +| 0 | Number of programs +| 4100 | Program size BCD +| 1600 | Header size (no. of words) bcd +| 1604 | System register size +| 96230000001480004 | ? + +### %EE$EX00RT with error + +|Reponse Byte|Description| +|------------|-----------| +| 00 | Extended mode +| 32 | Data item count +| 70 | Machine type +| 00 | Version (Fixed to 00) +| 16 | Prog capacity in K +| 81 | Operation mode / status +| 00 | Link unit +| 60 | Error flag +| 0000 | Self diag error +| 50 | Version +| 02 | Hardware information +| 0 | Number of programs +| 4100 | Program size BCD +| 1600 | Header size (no. of words) bcd +| 1604 | System register size +| 96230000001480004 | ? + +What are the last bytes? + +FP-X 16k C14R +96 23 00 00 00 14 80 00 4 + +FP-X 32k C30T/P +96 23 00 00 00 14 80 00 4 + +FP-XH 32k C30T/P +96 23 00 00 00 40 00 00 4 + +FP-XH 16k C14R +96 23 00 00 00 40 00 00 4 + +## FP-XH 16k C14R Actual Response Examples + +### %EE$RT + +|Reponse Byte|Description| +|------------|-----------| +| 20 | Model code | +| 16 | Version | +| 16 | Prog capacity | +| 81 | Op mode | +| 00 | Link unit | +| 60 | Error flag | +| 0000 | Self diag error | \ No newline at end of file