Hallo fpf,
ich habe Deine Lib im Einsatz und finde sie super!
Ich nutze sie, um mit anderen .net/mono Programmen und auch per Ajax, auf Prozessvariablen zuzugreifen.
Ein paar kleine Anmerkungen habe ich:
1) bitte teste das Ganze einmal, in dem Du mehrere Geräte hinzufügst, u.a. auch die virtuellen Modbus Geräte.
- bei der Adressierung (aus dem VariableServer) muss die DeviceAddresse mit zu dem relativen Variablenoffset gerechnet werden.
2) In der VariablenInfo sollte der Value zBsp auf object gesetzt werden. Es gibt beim Modbus zBsp. auch IP Adressen, die nicht in ein "int64" gecastet werden können.
3) In der VariableInfo sollte der BitOffset mit eingelesen werden, um bei DO oder DI Geräte auch die Bits korrekt anzusprechen.
Für die Lib sieht meine VariableInfo so aus:
Code: Select all
using System.Collections.Generic;
using System.Diagnostics;
using Newtonsoft.Json.Linq;
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Local
namespace IctBaden.RevolutionPi.Model
{
[DebuggerDisplay("{" + nameof(Name) + "}")]
public class VariableInfo
{
public VariableType Type { get; private set; }
public int Index { get; private set; }
public string Name { get; set; }
public object DefaultValue { get; set; } //orginal: long; kann aber auch eine IP Adresse beinhalten....
public ushort Length { get; set; } // length of the variable in bits. Possible values are 1, 8, 16 and 32
public ushort Address { get; set; } // Address of the byte in the process image
public bool Export { get; set; }
public string Unknown { get; set; } //"0001"
public string Comment { get; set; }
public byte BitOffset { get; set; } // 0-7 bit position, >= 8 whole byte
public DeviceInfo Device { get; set; }
public string LengthText
{
get
{
switch (Length)
{
case 1: return "BIT";
case 8: return "BYTE";
case 16: return "WORD";
case 32: return "DWORD";
}
return $"[{Length} bits]";
}
}
public VariableInfo(DeviceInfo device, VariableType type, int index, IList<JToken> json)
{
Device = device;
Type = type;
Index = index;
Name = json[0].Value<string>();
DefaultValue = json[1].Value<object>(); //orginal: long
Length = json[2].Value<ushort>();
Address = json[3].Value<ushort>();
Export = json[4].Value<bool>();
Unknown = json[5].Value<string>();
Comment = json[6].Value<string>();
try { BitOffset = json[7].Value<byte>(); } catch { BitOffset = 0; };
}
}
}
In Startup.cs habe ich CORS mit aufgenommen, damit Edge und IE auch damit klar kommen
CORS hinzufügen + vor "app.Use....":
Aus der VariableController.cs sieht mein Code zum auslesen der Prozessvar aktuell so aus:
Code: Select all
[Route("variables/{varname}")]
[HttpGet]
public async Task<IHttpActionResult> ReadVariable(string varname)
{
var config = Request.GetOwinContext().Get<PiConfiguration>("PiConfig");
var control = Request.GetOwinContext().Get<PiControl>("PiControl");
HttpResponseMessage httpResponse;
try
{
IctBaden.RevolutionPi.Model.VariableInfo varInfo = null;
foreach (IctBaden.RevolutionPi.Model.DeviceInfo pItem in config.Devices)
{
try
{
foreach (var variable in pItem.Variables)
{
if (variable.Name == varname)
{
varInfo = variable;
break; //den Ersten gefunden -> Ende
}
}
}
catch { }
}
if (varInfo == null)
throw new Exception("varinfo ist leer -> Variable nicht vorhanden!!");
//Es muss noch die Adresse des Hauptgerätes (Katalog) dazugerechnet werden, da die Adresse hier nur die relative Adresse ist.
//
int iDeviceOffset = varInfo.Device.Offset;
int iByteLen = 0;
switch(varInfo.Length)
{
case 1: iByteLen = 0; break; //bit
case 8: iByteLen = 1; break;
case 16: iByteLen = 2; break;
case 32: iByteLen = 3; break;
default: iByteLen = -varInfo.Length / 8; break; //strings, zBsp. IP Adresse (124)
}
//Console.WriteLine("[preread] name: " + varInfo.Name + ";addr: " + (iDeviceOffset + varInfo.Address) + "(" + varInfo.BitOffset + ");len: " + iByteLen);
byte[] data = null;
if (iByteLen > 0)
{
data = control.Read(iDeviceOffset + varInfo.Address, iByteLen);
//Console.WriteLine("[readed] len: " + (data == null ? "null" : data.Length.ToString() + "; data: " + control.ConvertDataToValue(data, iByteLen)));
}
else if (iByteLen == 0)
{
data = new byte[1];
data[0] = control.GetBitValue((ushort)((ushort)iDeviceOffset + varInfo.Address), varInfo.BitOffset) ? (byte)1 : (byte)0;
//Console.WriteLine("[readed] bit: " + varInfo.BitOffset + "; data: " + data[0]);
}
else // iByteLen < 0
{
data = control.Read(iDeviceOffset + varInfo.Address, -iByteLen);
//Console.WriteLine("[readed] len: " + (data == null ? "null" : data.Length.ToString() + "; data: " + System.Text.Encoding.ASCII.GetString(data)));
}
if (data == null)
{
var error = new
{
error = "Could not read variable",
name = varname
};
httpResponse = new HttpResponseMessage(HttpStatusCode.OK) //ServiceUnavailable
{
Content = new StringContent(JsonConvert.SerializeObject(error, Formatting.Indented), Encoding.UTF8, "application/json")
};
}
else
{
var read = new
{
name = varname,
default_value = varInfo.DefaultValue,
comment = varInfo.Comment,
type = varInfo.Type.ToString(),
lengthText = varInfo.LengthText,
length = varInfo.Length,
device_offset = iDeviceOffset,
var_offset = varInfo.Address,
var_dev_name = varInfo.Device.Name,
var_dev_offset = varInfo.Device.Offset,
data = data,
value = control.ConvertDataToValue(data, iByteLen)
};
httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(JsonConvert.SerializeObject(read, Formatting.Indented), Encoding.UTF8, "application/json")
};
}
}
catch (Exception ex)
{
var error = new
{
error = "Variable not found",
name = varname,
errortext = ex.ToString()
};
httpResponse = new HttpResponseMessage(HttpStatusCode.OK) //NotFound
{
Content = new StringContent(JsonConvert.SerializeObject(error, Formatting.Indented), Encoding.UTF8, "application/json")
};
}
var result = new ResponseMessageResult(httpResponse);
return await Task.FromResult(result);
}
Hoffe Dir damit ein Stück geholfen zu haben.....
Gruß,
Heron