mirror of
https://github.com/OpenLogics/MewtocolNet.git
synced 2025-12-06 03:01:24 +00:00
F func params parser
This commit is contained in:
@@ -13,7 +13,7 @@ internal class Program {
|
||||
|
||||
Logger.LogLevel = LogLevel.Error;
|
||||
|
||||
using (var plc = Mewtocol.Ethernet("192.168.115.210").Build()) {
|
||||
using (var plc = Mewtocol.Ethernet("192.168.178.55").Build()) {
|
||||
|
||||
await plc.ConnectAsync();
|
||||
var prog = await plc.ReadProgramAsync();
|
||||
|
||||
@@ -116,6 +116,10 @@ namespace MewtocolNet {
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Program Read / Write
|
||||
|
||||
public async Task<PlcBinaryProgram> ReadProgramAsync () {
|
||||
|
||||
var steps = new List<byte[]>();
|
||||
@@ -136,7 +140,7 @@ namespace MewtocolNet {
|
||||
if (res.Success) {
|
||||
|
||||
var bytes = res.Response.ParseDTRawStringAsBytes();
|
||||
var foundEndPattern = bytes.SearchBytePattern(new byte[] { 0xFA, 0xF8, 0xFF, 0xFF });
|
||||
var foundEndPattern = bytes.SearchBytePattern(new byte[] { 0xF8, 0xFF, 0xFF });
|
||||
|
||||
for (int j = 0; j < bytes.Length; j += 2) {
|
||||
var split = bytes.Skip(j).Take(2).ToArray();
|
||||
|
||||
@@ -5,20 +5,27 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Globalization;
|
||||
using MewtocolNet.AutoGeneratedData;
|
||||
using static System.Collections.Specialized.BitVector32;
|
||||
|
||||
namespace MewtocolNet.ProgramParsing {
|
||||
|
||||
public enum ProgramSection {
|
||||
|
||||
CheckSumTest = 0, //check if the program was changed and overwrite self reliant registers with 0x00 if so
|
||||
InitGlobalVars = 1, //setup all global vars that are not 0x00
|
||||
Program = 2,
|
||||
Subroutine = 3,
|
||||
|
||||
}
|
||||
|
||||
public class PlcBinaryProgram {
|
||||
|
||||
static readonly Dictionary<ushort, string> stepCommands = new Dictionary<ushort, string> {
|
||||
{ 0x00FF, "SUB 0" },
|
||||
|
||||
{ 0xB0FF, "DF" },
|
||||
{ 0xFAF8, "ED" },
|
||||
{ 0xFDF8, "RET" }, //return
|
||||
{ 0xF6F8, "CALL" },
|
||||
{ 0xEEF8, "SET" },
|
||||
//routine entry flank conditions
|
||||
{ 0xB0FF, "DF (Rising flank condition)" },
|
||||
|
||||
{ 0xEEF8, "SET" }, //has parameter needs custom analyzer
|
||||
{ 0x21CC, "OT R501" },
|
||||
//{ 0x21AC, "ST R501" },
|
||||
//{ 0xF7FF, "ST R9010" },
|
||||
@@ -108,28 +115,45 @@ namespace MewtocolNet.ProgramParsing {
|
||||
|
||||
public void AnalyzeProgram () {
|
||||
|
||||
int sectionCounter = -1, programCounter = 0, subRoutineCounter = 0;
|
||||
var currentSection = ProgramSection.CheckSumTest;
|
||||
|
||||
for (int i = 0; i < rawSteps.Count; i++) {
|
||||
|
||||
//step data
|
||||
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} ");
|
||||
//step debug writing
|
||||
string stepHeader = null;
|
||||
var stepString = new StringBuilder();
|
||||
stepString.Append($"{i,3} => {stepBytesString} ");
|
||||
|
||||
var stepKey = BitConverter.ToUInt16(step.Reverse().ToArray(), 0);
|
||||
byte[] nextStep = null;
|
||||
|
||||
if(i + 1 < rawSteps.Count - 1)
|
||||
nextStep = rawSteps[i + 1];
|
||||
if(i + 1 < rawSteps.Count - 1) nextStep = rawSteps[i + 1];
|
||||
|
||||
if (stepCommands.ContainsKey(stepKey)) {
|
||||
|
||||
Console.Write($"{stepCommands[stepKey]}");
|
||||
stepString.Append($"{stepCommands[stepKey]}");
|
||||
|
||||
} else if (nextStep != null && step[0] != 0xF7 && step[1] == 0xFF && nextStep[1] != 0xA9) {
|
||||
|
||||
//SUB (Subroutine start) step
|
||||
|
||||
var callCode = step[0];
|
||||
stepString.Append($"SUB {callCode}");
|
||||
|
||||
sectionCounter++;
|
||||
subRoutineCounter++;
|
||||
|
||||
stepHeader = $"\n{ProgramSection.Subroutine} | {subRoutineCounter}\n";
|
||||
currentSection = ProgramSection.Subroutine;
|
||||
|
||||
} else if (nextStep != null && step[0] == 0xF7 && step[1] == 0xFF && nextStep[1] == 0xA9) {
|
||||
|
||||
//ST step
|
||||
//ST (Start normal program) step
|
||||
|
||||
var area = nextStep[0].ToString("X2").Substring(0, 1);
|
||||
var specialArea = nextStep[0].ToString("X2").Substring(1, 1);
|
||||
@@ -137,7 +161,31 @@ namespace MewtocolNet.ProgramParsing {
|
||||
var stepID = 896 + int.Parse(area, NumberStyles.HexNumber);
|
||||
var stCondition = $"R{stepID}{specialArea}";
|
||||
|
||||
Console.Write($"ST {GetSysRegisterName(stCondition)}");
|
||||
if(subRoutineCounter == 0) sectionCounter++;
|
||||
|
||||
if (sectionCounter > 1) {
|
||||
|
||||
if(subRoutineCounter == 0) {
|
||||
|
||||
programCounter++;
|
||||
|
||||
stepHeader = $"\n{ProgramSection.Program} | {programCounter}\n";
|
||||
currentSection = ProgramSection.Program;
|
||||
|
||||
}
|
||||
|
||||
} else if (sectionCounter > 0) {
|
||||
|
||||
stepHeader = $"\n{ProgramSection.InitGlobalVars}\n";
|
||||
currentSection = ProgramSection.InitGlobalVars;
|
||||
|
||||
} else {
|
||||
|
||||
stepHeader = $"\n{ProgramSection.CheckSumTest}\n";
|
||||
|
||||
}
|
||||
|
||||
stepString.Append($"ST {GetSysRegisterName(stCondition)}");
|
||||
|
||||
} else if (nextStep != null && step[0] == 0xF7 && step[1] == 0xFF && nextStep[1] == 0x49) {
|
||||
|
||||
@@ -149,64 +197,185 @@ namespace MewtocolNet.ProgramParsing {
|
||||
var stepID = 896 + int.Parse(area, NumberStyles.HexNumber);
|
||||
var stCondition = $"R{stepID}{specialArea}";
|
||||
|
||||
Console.Write($"AN/ {GetSysRegisterName(stCondition)}");
|
||||
stepString.Append($"AN/ {GetSysRegisterName(stCondition)}");
|
||||
|
||||
} else if (nextStep != null && step[0] == 0xF6 && step[1] == 0xF8 && nextStep[1] == 0xFA) {
|
||||
|
||||
//CALL step
|
||||
|
||||
var callCode = nextStep[0];
|
||||
stepString.Append($"CALL {callCode}");
|
||||
|
||||
} else if (step[1] == 0xCC) {
|
||||
|
||||
//OT step
|
||||
|
||||
var callCode = step[0];
|
||||
stepString.Append($"OT {callCode}");
|
||||
|
||||
} else if (step[0] == 0xFA && step[1] == 0xF8) {
|
||||
|
||||
//ED step
|
||||
stepString.Append($"ED (End of main prog loop)");
|
||||
|
||||
} else if (step[0] == 0xFD && step[1] == 0xF8) {
|
||||
|
||||
//RET step
|
||||
stepString.Append($"RET (End of subroutine {subRoutineCounter})");
|
||||
|
||||
} else if (step[1] == 0xF8) {
|
||||
|
||||
//standard lib F function
|
||||
|
||||
int functionID = 0;
|
||||
int paramsStartIndex = i + 1;
|
||||
|
||||
if (step[0] == 0xFF) {
|
||||
//custom function that goes over FF, the F instruction number is calced by
|
||||
//the next step first byte plus 190
|
||||
functionID = nextStep[0] + 190;
|
||||
paramsStartIndex = i + 2;
|
||||
} else {
|
||||
functionID = step[0];
|
||||
}
|
||||
|
||||
string funcName = GetFunctionName($"F{functionID}");
|
||||
Console.Write(funcName);
|
||||
string funcName = GetFunction($"F{functionID}", out var foundFunc);
|
||||
stepString.Append(funcName);
|
||||
|
||||
//get the params and outs of the function
|
||||
if(foundFunc != null) {
|
||||
|
||||
ParseFuncParams(paramsStartIndex, foundFunc, stepString);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//if (stepBytesString.StartsWith("F")) {
|
||||
// Console.Write(" STEP COMMAND");
|
||||
//}
|
||||
|
||||
Console.WriteLine();
|
||||
if (stepHeader != null) Console.WriteLine(stepHeader);
|
||||
Console.WriteLine(stepString.ToString());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
private void ParseFuncParams(int stepIndex, FPFunction func, StringBuilder sb) {
|
||||
|
||||
//get the params and outs of the function
|
||||
var allowedParamSuffixes = new byte[] {
|
||||
0xFA,
|
||||
0xFB,
|
||||
0xFD,
|
||||
};
|
||||
|
||||
//count words
|
||||
|
||||
int paramsWordCount = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (stepIndex + 1 >= rawSteps.Count) break;
|
||||
|
||||
var paramStepL = rawSteps[stepIndex];
|
||||
var paramStepH = rawSteps[stepIndex + 1];
|
||||
|
||||
if (!allowedParamSuffixes.Contains(paramStepL[1])) break;
|
||||
|
||||
stepIndex += 2;
|
||||
paramsWordCount++;
|
||||
|
||||
}
|
||||
|
||||
sb.Append($"Words: {paramsWordCount}");
|
||||
|
||||
//if (func.ParametersIn != null) {
|
||||
|
||||
// for (int i = 0; i < func.ParametersIn.Count; i++) {
|
||||
|
||||
// sb.Append($"PI_{i}:");
|
||||
|
||||
|
||||
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
int currentParam = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
if (stepIndex + 1 >= rawSteps.Count) break;
|
||||
|
||||
var paramStepL = rawSteps[stepIndex];
|
||||
var paramStepH = rawSteps[stepIndex + 1];
|
||||
|
||||
//as DT address
|
||||
if (paramStepL[1] == 0xFA && paramStepH[1] == 0xFB) {
|
||||
|
||||
var address = BitConverter.ToUInt16(new byte[] { paramStepL[0], paramStepH[0] }, 0);
|
||||
|
||||
sb.Append($"DT{address}, ");
|
||||
|
||||
currentParam++;
|
||||
stepIndex += 2;
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
//16 bit WORD/INT/UINT
|
||||
if (paramStepL[1] == 0xFA && paramStepH[1] == 0xFC) {
|
||||
|
||||
sb.Append($"K{paramStepH[0]:X2}{paramStepL[0]:X2}, ");
|
||||
|
||||
}
|
||||
|
||||
//32 bit REAL
|
||||
if (paramStepL[1] == 0xFD && paramStepH[1] == 0xFB) {
|
||||
|
||||
sb.Append($"F{paramStepH[0]:X2}{paramStepL[0]:X2}, ");
|
||||
|
||||
//skipFrames = 4;
|
||||
|
||||
}
|
||||
|
||||
//end / return?
|
||||
if (paramStepL[1] == 0xFD && paramStepH[1] == 0xFD) {
|
||||
|
||||
}
|
||||
|
||||
if (!allowedParamSuffixes.Contains(paramStepL[1])) break;
|
||||
|
||||
stepIndex += 2;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string GetFunctionName (string funcName) {
|
||||
private string GetFunction (string funcName, out FPFunction foundFunc) {
|
||||
|
||||
foundFunc = null;
|
||||
|
||||
var found = FPFunction.functions.FirstOrDefault(x => x.Key.StartsWith(funcName));
|
||||
|
||||
if (!found.Equals(default(KeyValuePair<string, FPFunction>))) {
|
||||
|
||||
foundFunc = found.Value;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
var splt = found.Key.Split('_');
|
||||
|
||||
sb.Append($"{splt[0]} (*{splt[1]}*)");
|
||||
|
||||
if(found.Value.ParametersIn.Count > 0) {
|
||||
//if(found.Value.ParametersIn.Count > 0) {
|
||||
|
||||
sb.Append($" IN: {found.Value.ParametersIn.Count}");
|
||||
// sb.Append($" IN: {found.Value.ParametersIn.Count}");
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
if (found.Value.ParametersOut.Count > 0) {
|
||||
//if (found.Value.ParametersOut.Count > 0) {
|
||||
|
||||
sb.Append($" OUT: {found.Value.ParametersOut.Count}");
|
||||
// sb.Append($" OUT: {found.Value.ParametersOut.Count}");
|
||||
|
||||
}
|
||||
//}
|
||||
|
||||
return sb.ToString();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user