Показаны сообщения с ярлыком scripting. Показать все сообщения
Показаны сообщения с ярлыком scripting. Показать все сообщения

понедельник, 15 июля 2013 г.

ping скриптами System Platform

Собственно все очень просто :

периодический асинхронный скрипт

dim pingSender as System.Net.NetworkInformation.Ping;
pingSender = new System.Net.NetworkInformation.Ping();

dim reply as System.Net.NetworkInformation.PingReply;
reply = pingSender.Send( me.targIPorHostName, 2500 );

if reply.Status == System.Net.NetworkInformation.IPStatus.Success then
me.result = 0;
me.PingErr = False;
me.RoundtripTime = reply.RoundtripTime;
else 
me.result = me.result +1;
me.RoundtripTime = reply.RoundtripTime;  
endif;

и еще один скрипт который следит за количеством пропущенных пингов

WhileTrue по этому условию me.result > me.pingErrLimit

me.PingErr = True;

ну а дальше на me.PingErr вешаем все что нам нужно

P.S.: 2500 - таймаут для пинга ... если не поставить то скрипт будет ну очень долго ждать результата, а это в System Platform неприемлемо.

среда, 17 апреля 2013 г.

Преобразование строки в ДатуВремя

Столкнулся тут с "забавной" особенностью ... Особенность:
Если создать галактику на локализованной версии (например русской) Windows и потом перенести бекап на не локализованную (английскую), то тип UDA DateTime в нашей галактике будет инициализироваться в русском формате (т.е. 16.04.2013 14:28:06.951) а например в BTL он используется для выполнения задержки перед построением модели и там есть вот такая строка:

deployTime = System.DateTime.Parse(Me.BTL.Deploy.LastTime);

System.DateTime.Parse ждет на входе строку в формате en-US (4/16/2013 2:28:06 PM) а получает  в формате ru-RU, и вполне предсказуемо скрипт у нас вылетает с критической ошибкой :(
вот такой:
chAppEngineBase_001.testParse: Script performed an illegal operation.
chAppEngineBase_001.testParse: mscorlib: String was not recognized as a valid DateTime.

в BTL 2012R2 эту строку заменили на более сложный вариант:


If NOT System.DateTime.TryParse(Me.BTL.Deploy.LastTime, deployTime) THEN 
deployTime = System.DateTime.ParseExact(Me.BTL.Deploy.LastTime, "M/d/yyyy h:mm:ss.fff tt", System.Globalization.CultureInfo.InvariantCulture); 
EndIf;

Но он в моем случае тоже не работает .... пока что я пришел к такому варианту :


Dim deployTime as System.DateTime;
deployTime = System.DateTime.Parse(Me.BTL.Deploy.LastTime,System.Globalization.CultureInfo("ru-RU",true));



Но он к сожалению требует прямого указания входной локали .... зато работает :) 

вторник, 26 марта 2013 г.

Работа с большими числами в SP побайтно

Появилась задача получить из контролера и обработать в платформе параметр типа Double, но в ПЛК такого типа нет и сам ПЛК читает этот параметр со счетчика ....  ПЛК получает байты в обратном порядке, и нам нужно их развернуть. Сделал разборку double на 2 integer и разворот и сборку обратно ... работает но вот правильно или нет это вопрос ....
 Дальше скрипт разборки на 2 части


'массивы байт
dim bytes8 [8] as System.Byte;
dim bytes1 [4] as System.Byte;
dim bytes2 [4] as System.Byte;
'системные переменные для работы
dim sysdouble as System.Double;
dim sysint64 as System.int64;
dim sysint32 as System.int32;
'берем число типа double из атрибута и конвертируем в масив байт
sysdouble = System.Convert.ToDouble(me.inputDouble);
bytes8[] = System.BitConverter.GetBytes(sysdouble);

'заполняем массивы типа integer на 8 и 2 по 4 элемента
'нужны нам для удобства отладки в Object Viewer
me.int8byte[1] =bytes8[1]; me.int1byte[1] =bytes8[8];
me.int8byte[2] =bytes8[2]; me.int1byte[2] =bytes8[7];
me.int8byte[3] =bytes8[3]; me.int1byte[3] =bytes8[6];
me.int8byte[4] =bytes8[4]; me.int1byte[4] =bytes8[5];

me.int8byte[5] =bytes8[5]; me.int2byte[1] =bytes8[4];
me.int8byte[6] =bytes8[6]; me.int2byte[2] =bytes8[3];
me.int8byte[7] =bytes8[7]; me.int2byte[3] =bytes8[2];
me.int8byte[8] =bytes8[8]; me.int2byte[4] =bytes8[1];

'делим наш массив из 8 байт на 2 4х байтных
bytes1[1] =bytes8[8];
bytes1[2] =bytes8[7];
bytes1[3] =bytes8[6];
bytes1[4] =bytes8[5]; 

bytes2[1] =bytes8[4];
bytes2[2] =bytes8[3];
bytes2[3] =bytes8[2];
bytes2[4] =bytes8[1];

'конвертируем 1й массив в переменную типа int32 
sysint32 = System.BitConverter.Toint32(bytes1[], 0);
'и копируем ее в атрибут 
me.int1= sysint32 ;
'конвертируем результат в 16чную и 2ичную строки для удобства отладки
me.hexStrByte1 = System.Convert.ToString( sysint32 , 16 );
me.binStrByte1 = System.Convert.ToString( sysint32 , 2 );

'конвертируем 2й массив в переменную типа int32 
sysint32 = System.BitConverter.Toint32(bytes2[], 0);
'и копируем ее в атрибут 
me.int2= sysint32 ;
'конвертируем результат в 16чную и 2ичную строки для удобства отладки
me.hexStrByte2 = System.Convert.ToString( sysint32 , 16 );
me.binStrByte2 = System.Convert.ToString( sysint32 , 2 );



me.Int1 и me.Int2 - два входных параметра которые мы принимаем в тип Double т.к. Integer для развернутых по байтно чисел может не хватить.

И скрипт сборки обратно


'массивы байт
dim bytes1 [4] as System.Byte;
dim bytes2 [4] as System.Byte;
dim bytes3 [8] as System.Byte;
'системные переменные для работы
dim sysint64 as System.int64;
dim sysdouble as System.Double;
'при конвертировании в масив байт число разворачивается
sysint64= System.Convert.ToInt64(me.Int1);
bytes1[] = System.BitConverter.GetBytes(sysint64);

sysint64= System.Convert.ToInt64(me.Int2);
bytes2[] = System.BitConverter.GetBytes(sysint64);
'заполнение переменных для отладки
me.intFromByte1[1] =bytes2[4]; me.int1FromByte[1] =bytes1[1];
me.intFromByte1[2] =bytes2[3]; me.int1FromByte[2] =bytes1[2];
me.intFromByte1[3] =bytes2[2]; me.int1FromByte[3] =bytes1[3];
me.intFromByte1[4] =bytes2[1]; me.int1FromByte[4] =bytes1[4];

me.intFromByte1[5] =bytes1[4]; me.int2FromByte[1] =bytes2[1];
me.intFromByte1[6] =bytes1[3]; me.int2FromByte[2] =bytes2[2];
me.intFromByte1[7] =bytes1[2]; me.int2FromByte[3] =bytes2[3];
me.intFromByte1[8] =bytes1[1]; me.int2FromByte[4] =bytes2[4];
'копируем масивы байт в 1 и разворачиваем
bytes3[1] =bytes2[4];
bytes3[2] =bytes2[3];
bytes3[3] =bytes2[2];
bytes3[4] =bytes2[1]; 

bytes3[5] =bytes1[4];
bytes3[6] =bytes1[3];
bytes3[7] =bytes1[2];
bytes3[8] =bytes1[1];

sysdouble = System.BitConverter.ToDouble(bytes3[], 0);
'sysint64 = System.BitConverter.Toint64(bytes3[], 0);
me.strResult = sysdouble ;
me.doubleResult = sysdouble ;


И рисунок по которому возможно лучше понятно что происходит


вот только вопрос "Правильно ли это все работает?!" пока открыт :)
велика вероятность что у меня просто четное количество ошибок :( -  НОРМ. РАБОТАЕТ :)

пятница, 15 февраля 2013 г.

Комплексные данные в custom property ? можно даже так !

Вот очень интересный и полезный материал по работе с комплексными данными в системной платформе от "everdyn". Очень рекомендую. :)

  http://www.everdyn.com/storing-complex-datas-in-a-single-custom-property/

И в догонку скрипт как функция. Тоже может быть очень полезно.
http://www.everdyn.com/use-scripts-as-functions-in-archestra-graphics/

вторник, 5 февраля 2013 г.

case в quick script ? а если вот так ? :)


Скрипт в символе по DataChange переменной State

if isGood(State) then

dim TxtStTable as System.Collections.Hashtable;
TxtStTable = new System.Collections.Hashtable;

TxtStTable.Add(0,"Отключена");
TxtStTable.Add(10,"Открыта");
TxtStTable.Add(11,"Закрыта");
TxtStTable.Add(12,"Открытие");
TxtStTable.Add(13,"Закрытие");
TxtStTable.Add(20,"Заклинивание");
TxtStTable.Add(21,"Тепловая защита");

if TxtStTable.ContainsKey( state ) then
Text1.Text = TxtStTable[state];
else
Text1.Text = "Состояние не определено";
endif;

else
Text1.Text = "Quality = Bad";
endif;

среда, 8 декабря 2010 г.

XmlDocument и Wonderware Application Server Scripting

            В скриптах AS сейчас нет структуры  case, приходится заменять  ее кучей if. В некоторых задачах приходится в зависимости от значения одной величины менять значение другой или нескольких, и пока вариантов не много это еще выглядит нормально .... но вот если больше 10 то это уже 2 экрана if then elseif ..... некрасиво ... и менять это неудобно :) возникла идея заменить это все какой нибудь структурой но ничего подходящего скрипты в AS не могу :( . 
             
      Это была предыстория :)

      Решил эту проблему сейчас с помощью .NET  System.Xml.XmlDocument. Все получилось очень просто, но пока адаптировал к языку скриптов AS пришлось немного повозится.

Вот результат.

создание объекта и загрузка xml в объект

dim EngUnitDoc as System.Xml.XmlDocument;
EngUnitDoc = new System.Xml.XmlDocument;
EngUnitDoc.load(me.xmlPath);

выгрузка объекта в общее пространство приложения .... правильно называется оно не так но вроде понятно :)


System.AppDomain.CurrentDomain.SetData(Me.Tagname+"XMLDoc",EngUnitDoc);

Все файл прочитали и он доступен для всех объектов... вероятно на том же самом движке , но не уверен еще не проверял. 

Теперь получаем доступ к данным которые мы загрузили из скрипта 

dim EngUnitDoc as System.Xml.XmlDocument;
EngUnitDoc = System.AppDomain.CurrentDomain.GetData(MyContainer.Tagname+"XMLDoc");
if EngUnitDoc <> null then
dim collection as System.Xml.XmlAttributeCollection;
collection = EngUnitDoc.SelectSingleNode("EngUnits/unit[@id='"+Me.Measurment+"']").Attributes;
Me.EngUnits =collection.GetNamedItem("text").Value;
me.accuracy =StringToReal(collection.GetNamedItem("accuracy").Value);
me.ValueOutDesc =collection.GetNamedItem("Description").Value;
'setGood(me.accuracy);
else
Me.EngUnits ="error";
me.accuracy =0.0001;
me.ValueOutDesc = "ERROR: XMLDoc  ";
endif;


вот собственно и все :) 
xml файл использовал примерно такой (не знаю как сюда его вставить в связи с чем заменил < на *  )



*?xml version="1.0" encoding="utf-8"?*
*EngUnits*
  *unit id="1234567" Description="xxxxxxxx" text="emu" accuracy="0.0001"**/unit*
  *unit id="1137" Description="xxxxx" text="xxxx" accuracy="0.001"**/unit*
*/EngUnits*





P.S.: текст этот писал скорее для себя на будущее, в связи с чем все очень кратко. Подробности смотреть в msdn :)
EngUnits/unit[@id='"+Me.Measurment+"']" - XSLT в Гугле или msdn