Added new PLC types and auto documentation

This commit is contained in:
Felix Weiß
2023-07-06 00:14:40 +02:00
parent f338acfe8a
commit ab7f5ca302
19 changed files with 1466 additions and 176 deletions

View File

@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MewtocolNet\MewtocolNet.csproj" />
</ItemGroup>
</Project>

509
DocBuilder/Docs/plctypes.md Normal file
View File

@@ -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
> <b>Discontinued PLCs</b><br>
> These are PLCs that are no longer sold by Panasonic. Marked with ⚠️
> <b>EXRT PLCs</b><br>
> 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.
<table>
<tr>
<th>Type</th>
<th>Capacity</th>
<th>Code</th>
<th>Enum</th>
<th>DCNT</th>
<th>EXRT</th>
<th>Tested</th>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP0</b> </td>
</tr>
<tr>
<td> C10, C14, C16 </td>
<td> 2.7k </td>
<td><code>0x40</code></td>
<td><i>FP0_2c7k__C10_C14_C16</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C32, SL1 </td>
<td> 5k </td>
<td><code>0x41</code></td>
<td><i>FP0_5k__C32_SL1</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> T32 </td>
<td> 10k </td>
<td><code>0x42</code></td>
<td><i>FP0_10c0k__T32</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP0H</b> </td>
</tr>
<tr>
<td> C32T/P </td>
<td> 32k </td>
<td><code>0xB0</code></td>
<td colspan="2"><i>FP0H_32k__C32TsP</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C32ET/EP </td>
<td> 32k </td>
<td><code>0xB1</code></td>
<td colspan="2"><i>FP0H_32k__C32ETsEP</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP0R</b> </td>
</tr>
<tr>
<td> C10, C14, C16 </td>
<td> 16k </td>
<td><code>0x46</code></td>
<td colspan="2"><i>FP0R_16k__C10_C14_C16</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C32 </td>
<td> 32k </td>
<td><code>0x47</code></td>
<td colspan="2"><i>FP0R_32k__C32</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> T32 </td>
<td> 32k </td>
<td><code>0x48</code></td>
<td colspan="2"><i>FP0R_32k__T32</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> F32 </td>
<td> 32k </td>
<td><code>0x49</code></td>
<td colspan="2"><i>FP0R_32k__F32</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP1</b> </td>
</tr>
<tr>
<td> C14, C16 </td>
<td> 0.9k </td>
<td><code>0x04</code></td>
<td><i>FP1_0c9k__C14_C16_OR_FPdM_0c9k__C16T</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C16T </td>
<td> 0.9k </td>
<td><code>0x04</code></td>
<td><i>FP1_0c9k__C14_C16_OR_FPdM_0c9k__C16T</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C24, C40 </td>
<td> 2.7k </td>
<td><code>0x05</code></td>
<td><i>FP1_2c7k__C24_C40_OR_FPdM_2c7k__C20R_C20T_C32T</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C20R, C20T, C32T </td>
<td> 2.7k </td>
<td><code>0x05</code></td>
<td><i>FP1_2c7k__C24_C40_OR_FPdM_2c7k__C20R_C20T_C32T</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C56, C72 </td>
<td> 5k </td>
<td><code>0x06</code></td>
<td><i>FP1_5k__C56_C72</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP10</b> </td>
</tr>
<tr>
<td> - </td>
<td> 30k </td>
<td><code>0x20</code></td>
<td><i>FP10_30k_OR_FP10S_30k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> - </td>
<td> 30k </td>
<td><code>0x20</code></td>
<td><i>FP10_30k_OR_FP10S_30k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP10SH</b> </td>
</tr>
<tr>
<td> - </td>
<td> 30k </td>
<td><code>0x30</code></td>
<td><i>FP10SH_30k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP2</b> </td>
</tr>
<tr>
<td> - </td>
<td> 16k </td>
<td><code>0x50</code></td>
<td><i>FP2_16k_OR_FP2_32k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> - </td>
<td> 32k </td>
<td><code>0x50</code></td>
<td><i>FP2_16k_OR_FP2_32k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP2SH</b> </td>
</tr>
<tr>
<td> - </td>
<td> 60k </td>
<td><code>0x60</code></td>
<td><i>FP2SH_60k</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> - </td>
<td> 32k </td>
<td><code>0x62</code></td>
<td><i>FP2SH_32k</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> - </td>
<td> 120k </td>
<td><code>0xE0</code></td>
<td><i>FP2SH_120k</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP3</b> </td>
</tr>
<tr>
<td> - </td>
<td> 10k </td>
<td><code>0x03</code></td>
<td><i>FP3_10k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> - </td>
<td> 16k </td>
<td><code>0x13</code></td>
<td><i>FP3_16k_OR_FPdC_16k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> - </td>
<td> 16k </td>
<td><code>0x13</code></td>
<td><i>FP3_16k_OR_FPdC_16k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP5</b> </td>
</tr>
<tr>
<td> - </td>
<td> 16k </td>
<td><code>0x02</code></td>
<td><i>FP5_16k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> - </td>
<td> 24k </td>
<td><code>0x12</code></td>
<td><i>FP5_24k</i></td>
<td align=center>⚠️</td>
<td align=center> ❌ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP-e</b> </td>
</tr>
<tr>
<td> - </td>
<td> 2.7k </td>
<td><code>0x45</code></td>
<td><i>FPde_2c7k</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP-SIGMA</b> </td>
</tr>
<tr>
<td> - </td>
<td> 12k </td>
<td><code>0x43</code></td>
<td><i>FPdSIGMA_12k</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> - </td>
<td> 32k </td>
<td><code>0x44</code></td>
<td><i>FPdSIGMA_32k</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> - </td>
<td> 16k </td>
<td><code>0xE1</code></td>
<td><i>FPdSIGMA_16k</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP-X</b> </td>
</tr>
<tr>
<td> C14R </td>
<td> 16k </td>
<td><code>0x70</code></td>
<td><i>FPdX_16k__C14R</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ✅ </td>
</tr>
<tr>
<td> C30R, C60R </td>
<td> 32k </td>
<td><code>0x71</code></td>
<td><i>FPdX_32k__C30R_C60R</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> L14 </td>
<td> 16k </td>
<td><code>0x73</code></td>
<td><i>FPdX_16k__L14</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> L30, L60 </td>
<td> 32k </td>
<td><code>0x74</code></td>
<td><i>FPdX_32k__L30_L60</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C14T/P </td>
<td> 16k </td>
<td><code>0x76</code></td>
<td><i>FPdX_16k__C14TsP</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C30T/P, C60T/P, C38AT, C40T </td>
<td> 32k </td>
<td><code>0x77</code></td>
<td><i>FPdX_32k__C30TsP_C60TsP_C38AT_C40T</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ✅ </td>
</tr>
<tr>
<td> C40RT0A </td>
<td> 2.5k </td>
<td><code>0x7A</code></td>
<td><i>FPdX_2c5k__C40RT0A</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP-X0</b> </td>
</tr>
<tr>
<td> L14, L30 </td>
<td> 2.5k </td>
<td><code>0x72</code></td>
<td><i>FPdX0_2c5k__L14_L30</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> L40, L60 </td>
<td> 8k </td>
<td><code>0x75</code></td>
<td><i>FPdX0_8k__L40_L60</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> L40, L60 </td>
<td> 16k </td>
<td><code>0x7F</code></td>
<td><i>FPdX0_16k__L40_L60</i></td>
<td align=center>⚠️</td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td colspan="7" height=50>📟 <b>FP-XH</b> </td>
</tr>
<tr>
<td> C14R </td>
<td> 16k </td>
<td><code>0xA0</code></td>
<td colspan="2"><i>FPdXH_16k__C14R</i></td>
<td align=center> ✅ </td>
<td align=center> ✅ </td>
</tr>
<tr>
<td> C30R, C40R, C60R </td>
<td> 32k </td>
<td><code>0xA1</code></td>
<td colspan="2"><i>FPdXH_32k__C30R_C40R_C60R</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C14T/P </td>
<td> 16k </td>
<td><code>0xA4</code></td>
<td colspan="2"><i>FPdXH_16k__C14TsP</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C30T/P, C40T, C60T/P </td>
<td> 32k </td>
<td><code>0xA5</code></td>
<td colspan="2"><i>FPdXH_32k__C30TsP_C40T_C60TsP</i></td>
<td align=center> ✅ </td>
<td align=center> ✅ </td>
</tr>
<tr>
<td> C38AT </td>
<td> 32k </td>
<td><code>0xA7</code></td>
<td colspan="2"><i>FPdXH_32k__C38AT</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> M4T/L </td>
<td> 32k </td>
<td><code>0xA8</code></td>
<td colspan="2"><i>FPdXH_32k__M4TsL</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> M8N16T/P </td>
<td> 32k </td>
<td><code>0xAC</code></td>
<td colspan="2"><i>FPdXH_32k__M8N16TsP</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> M8N30T </td>
<td> 32k </td>
<td><code>0xAD</code></td>
<td colspan="2"><i>FPdXH_32k__M8N30T</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C40ET, C60ET </td>
<td> 32k </td>
<td><code>0xAE</code></td>
<td colspan="2"><i>FPdXH_32k__C40ET_C60ET</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
<tr>
<td> C60ETF </td>
<td> 32k </td>
<td><code>0xAF</code></td>
<td colspan="2"><i>FPdXH_32k__C60ETF</i></td>
<td align=center> ✅ </td>
<td align=center> ❌ </td>
</tr>
</table>

View File

@@ -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 |

135
DocBuilder/Program.cs Normal file
View File

@@ -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<PlcType>().OrderBy(x => x.ToString());
void WritePlcTypeTable(IEnumerable<PlcType> 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("<table>");
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("<tr>");
markdownBuilder.AppendLine($"<th>Type</th>");
markdownBuilder.AppendLine($"<th>Capacity</th>");
markdownBuilder.AppendLine($"<th>Code</th>");
markdownBuilder.AppendLine($"<th>Enum</th>");
markdownBuilder.AppendLine($"<th>DCNT</th>");
markdownBuilder.AppendLine($"<th>EXRT</th>");
markdownBuilder.AppendLine($"<th>Tested</th>");
markdownBuilder.AppendLine("</tr>");
isFirstIt = false;
}
if(isFirstGroup) {
markdownBuilder.AppendLine("<tr>");
markdownBuilder.AppendLine($"<td colspan=\"7\" height=50>📟 <b>{group.Key}</b> </td>");
markdownBuilder.AppendLine("</tr>");
isFirstGroup = false;
}
foreach (var decomp in decomposed) {
markdownBuilder.AppendLine("<tr>");
markdownBuilder.AppendLine($"<td> {(decomp.SubTypes.Length == 0 ? "-" : string.Join(", ", decomp.SubTypes))} </td>");
markdownBuilder.AppendLine($"<td> {decomp.Size}k </td>");
markdownBuilder.AppendLine($"<td><code>0x{cpuOrMachCode}</code></td>");
if(enu.IsDiscontinued()) {
markdownBuilder.AppendLine($"<td><i>{enu.ToString()}</i></td>");
markdownBuilder.AppendLine($"<td align=center>⚠️</td>");
} else {
markdownBuilder.AppendLine($"<td colspan=\"2\"><i>{enu.ToString()}</i></td>");
}
markdownBuilder.AppendLine($"<td align=center> {(enu.IsEXRTPLC() ? "" : "")} </td>");
markdownBuilder.AppendLine($"<td align=center> {(enu.WasTestedLive() ? "" : "")} </td>");
markdownBuilder.AppendLine("</tr>");
}
}
isFirstIt = false;
}
markdownBuilder.AppendLine("</table>");
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($"> <b>Discontinued PLCs</b><br>");
markdownBuilder.AppendLine($"> These are PLCs that are no longer sold by Panasonic. Marked with ⚠️\n");
markdownBuilder.AppendLine($"> <b>EXRT PLCs</b><br>");
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());

View File

@@ -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

View File

@@ -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;

View File

@@ -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() { }
}
}

View File

@@ -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() {}
}
}

View File

@@ -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() {}
}
}

View File

@@ -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
/// <summary>
/// Converts the enum to a plc name string
/// </summary>
public static string ToName(this PlcType plcT) {
return string.Join(" or ", ParsedPlcName.LegacyPlcDeconstruct(plcT).Select(x => x.WholeName));
}
/// <summary>
/// Converts the enum to a decomposed <see cref="ParsedPlcName"/> struct
/// </summary>
public static ParsedPlcName[] ToNameDecompose (this PlcType legacyT) {
return ParsedPlcName.LegacyPlcDeconstruct(legacyT);
}
/// <summary>
/// Checks if the PLC type is discontinued
/// </summary>
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
}
}

View File

@@ -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 {
/// <summary>
/// A structure containing the PLC name parsed
/// </summary>
public struct ParsedPlcName {
/// <summary>
/// Whole name of the PLC
/// </summary>
public string WholeName { get; internal set; }
/// <summary>
/// The family group of the PLC
/// </summary>
public string Group { get; internal set; }
/// <summary>
/// The Memory size of the PLC
/// </summary>
public float Size { get; internal set; }
/// <summary>
/// The subtype strings of the plc
/// </summary>
public string[] SubTypes { get; internal set; }
/// <inheritdoc/>
public override string ToString() => WholeName;
internal static ParsedPlcName[] LegacyPlcDeconstruct<T> (T legacyT) {
string wholeStr = legacyT.ToString();
var split = wholeStr.Replace("_OR_", "|").Split('|');
var reg = new Regex(@"(?<group>[A-Za-z0-9]*)_(?<size>[A-Za-z0-9]*)(?:__)?(?<additional>.*)");
var retList = new List<ParsedPlcName>();
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<string>();
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;
}
}
}

View File

@@ -19,36 +19,36 @@ namespace MewtocolNet {
/// Gets generic information about the PLC
/// </summary>
/// <returns>A PLCInfo class</returns>
public async Task<PLCInfo> GetPLCInfoAsync(int timeout = -1) {
public async Task<PLCInfo?> 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);
}

View File

@@ -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<PLCInfo> TryConnectAsyncMulti () {
private async Task<PLCInfo?> TryConnectAsyncMulti () {
var baudRates = Enum.GetValues(typeof(BaudRate)).Cast<BaudRate>();
@@ -205,7 +205,7 @@ namespace MewtocolNet {
}
private async Task<PLCInfo> TryConnectAsyncSingle (string port, int baud, int dbits, Parity par, StopBits sbits) {
private async Task<PLCInfo?> TryConnectAsyncSingle (string port, int baud, int dbits, Parity par, StopBits sbits) {
try {

View File

@@ -132,7 +132,7 @@ namespace MewtocolNet {
if (plcinf != null) {
OnConnected(plcinf);
OnConnected(plcinf.Value);
} else {

View File

@@ -23,6 +23,11 @@
<_Parameter1>MewtocolTests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>DocBuilder</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.IO.Ports" Version="7.0.0" />
</ItemGroup>

View File

@@ -1,8 +1,32 @@
namespace MewtocolNet {
public enum CpuType {
}
public struct PLCInfo {
/// <summary>
/// Current error code of the PLC
/// </summary>
public string ErrorCode { get; internal set; }
/// <summary>
/// Current station number of the PLC
/// </summary>
public int StationNumber { get; internal set; }
}
/// <summary>
/// Contains generic information about the plc
/// </summary>
public class PLCInfo {
public class PLCInfoOld
{
/// <summary>
/// Contains information about the PLCs cpu
@@ -12,6 +36,7 @@
/// Contains information about the PLCs operation modes
/// </summary>
public PLCMode OperationMode { get; set; }
/// <summary>
/// Current error code of the PLC
/// </summary>

View File

@@ -1,46 +0,0 @@
namespace MewtocolNet {
/// <summary>
/// CPU type of the PLC
/// </summary>
public enum CpuType {
/// <summary>
/// FP 0 / FP 2.7K
/// </summary>
FP0_FP1_2_7K,
/// <summary>
/// FP0 / FP1, 5K / 10K
/// </summary>
FP0_FP1_5K_10K,
/// <summary>
/// FP1 M 0.9K
/// </summary>
FP1_M_0_9K,
/// <summary>
/// FP2 16k / 32k
/// </summary>
FP2_16K_32K,
/// <summary>
/// FP3 C 10K
/// </summary>
FP3_C_10K,
/// <summary>
/// FP3 C 16K
/// </summary>
FP3_C_16K,
/// <summary>
/// FP5 16K
/// </summary>
FP5_16K,
/// <summary>
/// FP 5 24K
/// </summary>
FP5_24K,
/// <summary>
/// Includes panasonic FPX, FPX-H, Sigma
/// </summary>
FP_Sigma_X_H_30K_60K_120K
}
}

View File

@@ -0,0 +1,323 @@
using MewtocolNet.DocAttributes;
namespace MewtocolNet {
//this overwrites the CPU code and only comes with EXRT
//special chars: (d = -) (c = .) (s = /)
/// <summary>
/// The type of the PLC
/// </summary>
public enum PlcType {
#region FP5 Family (Legacy)
/// <summary>
/// FP5 16k
/// </summary>
[PlcLegacy]
FP5_16k = 0x02,
/// <summary>
/// FP5 24k
/// </summary>
[PlcLegacy]
FP5_24k = 0x12,
#endregion
#region FP2 Family (Legacy)
/// <summary>
/// FP2 16k OR FP2 32k
/// </summary>
[PlcLegacy]
FP2_16k_OR_FP2_32k = 0x50,
//misses entry FP2 32k
#endregion
#region FP3/FP-C Family (Legacy)
/// <summary>
/// FP3 10k
/// </summary>
[PlcLegacy]
FP3_10k = 0x03,
/// <summary>
/// FP3 or FP-C 16k
/// </summary>
[PlcLegacy]
FP3_16k_OR_FPdC_16k = 0x13,
#endregion
#region FP1 / FPM Family (Legacy)
/// <summary>
/// FP1 0.9k C14,C16 or FP-M 0.9k C16T
/// </summary>
[PlcLegacy]
FP1_0c9k__C14_C16_OR_FPdM_0c9k__C16T = 0x04,
/// <summary>
/// FP1 2.7k C24,C40 or FP-M 2.7k C20R,C20T,C32T
/// </summary>
[PlcLegacy]
FP1_2c7k__C24_C40_OR_FPdM_2c7k__C20R_C20T_C32T = 0x05,
/// <summary>
/// FP1 5.0k C56,C72
/// </summary>
[PlcLegacy]
FP1_5k__C56_C72 = 0x06,
#endregion
#region FP10 Family (Legacy)
/// <summary>
/// FP10 OR FP10S 30k
/// </summary>
[PlcLegacy]
FP10_30k_OR_FP10S_30k = 0x20,
//misses entry FP10 60k
#endregion
#region FP10SH Family (Legacy)
/// <summary>
/// FP10SH 30k
/// </summary>
[PlcLegacy]
FP10SH_30k = 0x30,
//misses entry FP10SH 60k
//misses entry FP10SH 120k
#endregion
#region FP0 Family (Legacy)
/// <summary>
/// FP0 2.7k C10,C14,C16
/// </summary>
[PlcLegacy]
FP0_2c7k__C10_C14_C16 = 0x40,
/// <summary>
/// FP0 5k
/// </summary>
[PlcLegacy]
FP0_5k__C32_SL1 = 0x41,
/// <summary>
/// FP0 10k
/// </summary>
[PlcLegacy]
FP0_10c0k__T32 = 0x42,
#endregion
#region FP-Sigma Family (Legacy)
/// <summary>
/// FP-Sigma 12k
/// </summary>
[PlcLegacy, PlcEXRT]
FPdSIGMA_12k = 0x43,
/// <summary>
/// FP-Sigma 32k
/// </summary>
[PlcLegacy, PlcEXRT]
FPdSIGMA_32k = 0x44,
/// <summary>
/// FP-SIGMA 16k
/// </summary>
[PlcLegacy, PlcEXRT]
FPdSIGMA_16k = 0xE1,
#endregion
#region FP-e Family (Legacy)
/// <summary>
/// FP-e 2.7k
/// </summary>
[PlcLegacy, PlcEXRT]
FPde_2c7k = 0x45,
#endregion
#region FP0R Family
/// <summary>
/// FP0R 16k C10,C14,C16
/// </summary>
[PlcEXRT]
FP0R_16k__C10_C14_C16 = 0x46,
/// <summary>
/// FP0R 32k C32
/// </summary>
[PlcEXRT]
FP0R_32k__C32 = 0x47,
/// <summary>
/// FP0R 32k T32
/// </summary>
[PlcEXRT]
FP0R_32k__T32 = 0x48,
/// <summary>
/// FP0R 32k F32
/// </summary>
[PlcEXRT]
FP0R_32k__F32 = 0x49,
#endregion
#region FP2SH Family (Legacy)
/// <summary>
/// FP2SH 60k
/// </summary>
[PlcLegacy, PlcEXRT]
FP2SH_60k = 0x60,
/// <summary>
/// FP2SH 32k
/// </summary>
[PlcLegacy, PlcEXRT]
FP2SH_32k = 0x62,
/// <summary>
/// FP2SH 120k
/// </summary>
[PlcLegacy, PlcEXRT]
FP2SH_120k = 0xE0,
#endregion
#region FP-X Family (Legacy)
/// <summary>
/// FP-X 16k C14R
/// </summary>
[PlcLegacy, PlcEXRT, PlcCodeTested]
FPdX_16k__C14R = 0x70,
/// <summary>
/// FP-X 32k C30R,C60R
/// </summary>
[PlcLegacy, PlcEXRT]
FPdX_32k__C30R_C60R = 0x71,
/// <summary>
/// FP-X0 2.5k L14,L30
/// </summary>
[PlcLegacy, PlcEXRT]
FPdX0_2c5k__L14_L30 = 0x72,
/// <summary>
/// FP-X 16k L14
/// </summary>
[PlcLegacy, PlcEXRT]
FPdX_16k__L14 = 0x73,
/// <summary>
/// FP-X 32k L30,L60
/// </summary>
[PlcLegacy, PlcEXRT]
FPdX_32k__L30_L60 = 0x74,
/// <summary>
/// FP-X0 8k L40,L60
/// </summary>
[PlcLegacy, PlcEXRT]
FPdX0_8k__L40_L60 = 0x75,
/// <summary>
/// FP-X 16k C14T/P
/// </summary>
[PlcLegacy, PlcEXRT]
FPdX_16k__C14TsP = 0x76,
/// <summary>
/// FP-X 32k C30T/P,C60T/P,C38AT,C40T
/// </summary>
[PlcLegacy, PlcEXRT, PlcCodeTested]
FPdX_32k__C30TsP_C60TsP_C38AT_C40T = 0x77,
/// <summary>
/// FP-X 2.5k C40RT0A
/// </summary>
[PlcLegacy, PlcEXRT]
FPdX_2c5k__C40RT0A = 0x7A,
/// <summary>
/// FP-X0 16k L40,L60
/// </summary>
[PlcLegacy, PlcEXRT]
FPdX0_16k__L40_L60 = 0x7F,
#endregion
#region FP-XH Family
/// <summary>
/// FP-XH 16k C14R
/// </summary>
[PlcEXRT, PlcCodeTested]
FPdXH_16k__C14R = 0xA0,
/// <summary>
/// FP-XH 32k C30R,C40R,C60R
/// </summary>
[PlcEXRT]
FPdXH_32k__C30R_C40R_C60R = 0xA1,
/// <summary>
/// FP-XH 16k C14T/P
/// </summary>
[PlcEXRT]
FPdXH_16k__C14TsP = 0xA4,
/// <summary>
/// FP-XH 32k C30T/P,C40T,C60T/P
/// </summary>
[PlcEXRT, PlcCodeTested]
FPdXH_32k__C30TsP_C40T_C60TsP = 0xA5,
/// <summary>
/// FP-XH 32k C38AT
/// </summary>
[PlcEXRT]
FPdXH_32k__C38AT = 0xA7,
/// <summary>
/// FP-XH 32k M4T/L
/// </summary>
[PlcEXRT]
FPdXH_32k__M4TsL = 0xA8,
/// <summary>
/// FP-XH 32k M8N16T/P (RTEX)
/// </summary>
[PlcEXRT]
FPdXH_32k__M8N16TsP = 0xAC,
/// <summary>
/// FP-XH 32k M8N30T (RTEX)
/// </summary>
[PlcEXRT]
FPdXH_32k__M8N30T = 0xAD,
/// <summary>
/// FP-XH 32k C40ET,C60ET
/// </summary>
[PlcEXRT]
FPdXH_32k__C40ET_C60ET = 0xAE,
/// <summary>
/// FP-XH 32k C60ETF
/// </summary>
[PlcEXRT]
FPdXH_32k__C60ETF = 0xAF,
#endregion
#region FP0H Family
/// <summary>
/// FP0H 32k C32T/P
/// </summary>
[PlcEXRT]
FP0H_32k__C32TsP = 0xB0,
/// <summary>
/// FP0H 32k C32ET/EP
/// </summary>
[PlcEXRT]
FP0H_32k__C32ETsEP = 0xB1,
#endregion
}
}

View File

@@ -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 |