#c# #ads #twincat #twincat-ads-.net
#c# #объявления #twincat #twincat-ads-.net
Вопрос:
Мы используем приложение на C # для чтения переменных из ПЛК Beckhoff через TwinCAT ADS v.3. Если мы попытаемся использовать тот же код для чтения свойств, код завершится ошибкой с исключением.
FUNCTION_BLOCK FB_Sample
VAR
SomeVariable : INT;
END_VAR
PROPERTY SomeProp : INT // declared in a separate file
// Code used to read variable (symbol)
var handle = client.CreateVariableHandle("sampleProgram.Source.SomeVariable");
var result = client.ReadAny(handle, typeof(int));
client.DeleteVariableHandle(handle);
// Adapted code used to read property (not a symbol)
var handle = client.CreateVariableHandle("sampleProgram.Source.SomeProp"); // This fails
var result = client.ReadAny(handle, typeof(int));
client.DeleteVariableHandle(handle);
При попытке создать дескриптор переменной, используя приведенный выше код, мы получаем TwinCAT.Ads.AdsErrorException: 'Ads-Error 0x710 : Symbol could not be found.'
.
Поскольку мы знали, что METHOD
это должно быть помечено {attribute 'TcRpcEnable'}
символом so, его можно вызвать с помощью этого кода:
client.InvokeRpcMethod("{symbolPath}", "{methodName}", {parameters} });
Мы также попытались использовать этот атрибут {attribute 'TcRpcEnable'}
для свойства. Используя TcAdsClient.CreateSymbolLoader
и перебирая все доступные символы, мы обнаружили, что получатель / установщик свойства затем были помечены как rpc-методы.
Console.WriteLine($"Name: {rpcMethod.Name}; Parameters.Count: {rpcMethod.Parameters.Count}; ReturnType: {rpcMethod.ReturnType};");
RpcMethods: 2
Name: __setSomeProp; Parameters.Count: 1; ReturnType: ;
Name: __getSomeProp; Parameters.Count: 0; ReturnType: INT;
Но, как бы мы ни старались, мы не можем вызвать метод rpc:
var propertyResult = client.InvokeRpcMethod("sampleProgram.Source", "__getSomeProp", Array.Empty<object>());
// Throws: TwinCAT.Ads.AdsErrorException: 'Ads-Error 0x710 : Symbol could not be found.'
var propertyResult = client.InvokeRpcMethod("sampleProgram.Source", "__get{SomeProp}", Array.Empty<object>());
// Throws: TwinCAT.Ads.RpcMethodNotSupportedException: 'The RPC method '__get{SomeProp}' is not supported on symbol 'sampleProgram.Source!'
var propertyResult = client.InvokeRpcMethod("sampleProgram.Source", "get{SomeProp}", Array.Empty<object>());
// Throws: TwinCAT.Ads.RpcMethodNotSupportedException: 'The RPC method 'get{SomeProp}' is not supported on symbol 'sampleProgram.Source!'
var propertyResult = client.InvokeRpcMethod("sampleProgram.Source.SomeProp", "get", Array.Empty<object>());
// Throws: System.ArgumentNullException: 'Value cannot be null.
// Parameter name: symbol'
Есть предложения о том, как мы можем читать / записывать переменные, определенные как свойства в функциональных блоках?
Ответ №1:
Когда вы определяете новое свойство, вы автоматически создаете get и set для этого свойства.
Обычно свойства используются для чтения или записи переменных, которые находятся в разделе VAR функционального блока.
Все переменные, находящиеся в разделе VAR, являются частными, поэтому для доступа к этим переменным из-за пределов функционального блока требуются свойства.
Теоретически свойства не должны выполнять никаких сложных вычислений или запускать какую-либо логику, в отличие от методов.
Я хочу подчеркнуть, что вам не нужно и не следует вызывать свойства через ОБЪЯВЛЕНИЯ. В любом случае у вас есть доступ ко всем частным переменным через ADS, поэтому в первую очередь нет необходимости вызывать свойства через ADS.
@Редактировать
Я по-прежнему придерживаюсь мнения, что свойства не должны содержать никакой логики, и поэтому нет необходимости вызывать их через ОБЪЯВЛЕНИЯ.
Тем не менее, всегда есть исключения.
Имейте в виду, что в соответствии с документацией Бекхоффа будут работать только простые типы данных и указатели, а не структуры. Кроме того, «Мониторинг функций невозможен в системе compact runtime».
Вот мой рабочий пример после экспериментов с атрибутом {attribute ‘monitoring’ := ‘call’}
В Twincat:
{attribute 'monitoring' := 'call'}
PROPERTY RemoteCall : INT
GET:
RemoteCall := buffer;
SET:
buffer := buffer RemoteCall;
В C#
class Program
{
static TcAdsClient tcClient;
static void Main(string[] args)
{
tcClient = new TcAdsClient();
tcClient.Connect(851);
AdsStream dataStream = new AdsStream(2);
int iHandle = tcClient.CreateVariableHandle("MAIN.fbTest.RemoteCall");
tcClient.Read(iHandle, dataStream);
Console.WriteLine("Remote Var before property call: " BitConverter.ToInt16(dataStream.ToArray(), 0));
tcClient.WriteAny(iHandle,Convert.ToInt16(2));
tcClient.Read(iHandle, dataStream);
Console.WriteLine("Remote Var after property call: " BitConverter.ToInt16(dataStream.ToArray(), 0));
Console.WriteLine();
Console.ReadLine();
}
}
Комментарии:
1. Мы надеялись упростить разработку нашего функционального блока с помощью интерфейсов. Таким образом, мы могли бы определять «переменные» в интерфейсе, используя свойства, которые необходимо будет реализовать в функциональном блоке. Но поскольку наше приложение на c # использует ADS для прямого доступа к внутренним переменным, и мы не можем использовать одно и то же имя для свойства и переменной, нам придется вернуться к конвейерам именования.
2. вы все равно можете реализовать методы получения и установки в качестве методов и вызывать их с помощью удаленного вызова процедуры, если хотите упростить разработку с помощью интерфейсов.
Ответ №2:
Согласно Стефану Хеннекену в его блоге, свойство должно быть украшено прагмой, чтобы включить это:
{attribute ‘monitoring’ := ‘call’}
PROPERTY PUBLIC nProp : BYTE
Затем его можно прочитать / записать с помощью этого примера кода:
using (AdsClient client = new AdsClient())
{
byte valuePlc;
client.Connect(AmsNetId.Local, 851);
valuePlc = (byte)client.ReadValue(“MAIN.fbFoo.nProp”, typeof(byte));
client.WriteValue(“MAIN.fbFoo.nProp”, valuePlc);
}
Комментарии:
1. Кстати, какую библиотеку ADS вы используете в этом примере? У AdsClient нет метода writeValue или readValue . Я протестировал его с помощью хорошо известного метода чтения / записи, и он не работает
2. Привет @FilippoBoido, кажется, вы правы. У меня не было возможности протестировать этот код, и я просто повторил то, что было прокомментировано в связанном блоге. У меня тоже такие же проблемы. Я повторно приму ваш ответ и посмотрю, смогу ли я продолжить это.