Аварийные сообщения в WinCC

Обсуждение SCADA-систем и HMI SIEMENS: WinCC OA, WinCC, WinCC Flexible, ProTool
Fail
Сообщений в теме: 3
Сообщения: 5
Зарегистрирован: 22 янв 2015, 09:26

Аварийные сообщения в WinCC

#1

Сообщение Fail » 04 июн 2015, 14:05

Доброго времени суток, дорогие форумчане!
Есть огромное число байтовых тегов, содержащих коды аварийных сообщений (числа от 0 до 255) где каждое число есть определенная авария. И Вот эти аварии необходимо перенести в Alarm Logging. Но как это сделать более корректно? изначально начал копать в сторону глобальных скриптов которые с помощью функций ODK, будут формирвоать сообщения:
функция определяющая текст сообщения:

Код: Выделить всё

char* Alarm_ASPT(WORD dwMsgNum)
{


char* lpszTextMessage = NULL;

if (dwMsgNum == 1)        lpszTextMessage = "Восстановление сети 220 В";
else if (dwMsgNum == 2)   lpszTextMessage = "Авария сети 220 В";
else if (dwMsgNum == 3)   lpszTextMessage = "Тревога проникновения";
else if (dwMsgNum == 17)  lpszTextMessage = "Неудачное взятие";
else if (dwMsgNum == 19)  lpszTextMessage = "Тест";
else if (dwMsgNum == 20)  lpszTextMessage = "Включение режима тестирования";
else if (dwMsgNum == 21)  lpszTextMessage = "Выключение режима тестирования";
else if (dwMsgNum == 22)  lpszTextMessage = "Восстановление контроля";
else if (dwMsgNum == 23)  lpszTextMessage = "Задержка взятия";
else if (dwMsgNum == 24)  lpszTextMessage = "ШС взят";
else if (dwMsgNum == 34)  lpszTextMessage = "Идентификация";
else if (dwMsgNum == 35)  lpszTextMessage = "Востановление технологического ШС";
else if (dwMsgNum == 36)  lpszTextMessage = "Нарушение технологического ШС";
else if (dwMsgNum == 37)  lpszTextMessage = "Пожар";
else if (dwMsgNum == 38)  lpszTextMessage = "Нарушение 2 технологического ШС";
else if (dwMsgNum == 39)  lpszTextMessage = "Восстановление нормы пожарного оборудования";
else if (dwMsgNum == 41)  lpszTextMessage = "Неисправность пожарного оборудования";
else if (dwMsgNum == 42)  lpszTextMessage = "Неизвестное устройство";
else if (dwMsgNum == 44)  lpszTextMessage = "Внимание! Опасность пожара";
else if (dwMsgNum == 45)  lpszTextMessage = "Обрыв ШС";
else if (dwMsgNum == 47)  lpszTextMessage = "Востановление ДПЛС";
else if (dwMsgNum == 58)  lpszTextMessage = "Тихая тревога";
else if (dwMsgNum == 71)  lpszTextMessage = "Понижение уровня";
else if (dwMsgNum == 72)  lpszTextMessage = "Норма уровня";
else if (dwMsgNum == 74)  lpszTextMessage = "Повышение уровня";
else if (dwMsgNum == 75)  lpszTextMessage = "Аварийное повышение уровня";
else if (dwMsgNum == 76)  lpszTextMessage = "Повышение температуры";
else if (dwMsgNum == 77)  lpszTextMessage = "Аварийное понижение уровня";
else if (dwMsgNum == 78)  lpszTextMessage = "Температура в норме";
else if (dwMsgNum == 82)  lpszTextMessage = "Неисправность термометра";
else if (dwMsgNum == 83)  lpszTextMessage = "Восстановление термометра";
else if (dwMsgNum == 84)  lpszTextMessage = "Локальное программирование";
else if (dwMsgNum == 109) lpszTextMessage = "ШС снят";
else if (dwMsgNum == 110) lpszTextMessage = "Сброс тревоги ШС";
else if (dwMsgNum == 117) lpszTextMessage = "Восстановление ШС";
else if (dwMsgNum == 118) lpszTextMessage = "Тревога входа";
else if (dwMsgNum == 119) lpszTextMessage = "Нарушение ШС";
else if (dwMsgNum == 121) lpszTextMessage = "Обрыв выхода";
else if (dwMsgNum == 122) lpszTextMessage = "КЗ выхода";
else if (dwMsgNum == 123) lpszTextMessage = "Восстановление выхода";
else if (dwMsgNum == 126) lpszTextMessage = "Выход отключен";
else if (dwMsgNum == 127) lpszTextMessage = "Выход подключен";
else if (dwMsgNum == 128) lpszTextMessage = "Изменение состояния выхода";
else if (dwMsgNum == 130) lpszTextMessage = "Насос включен";
else if (dwMsgNum == 131) lpszTextMessage = "Насос выключен";
else if (dwMsgNum == 135) lpszTextMessage = "Ошибка при автоматическом тестировании";
else if (dwMsgNum == 137) lpszTextMessage = "Срабатывание цепи пуска";
else if (dwMsgNum == 139) lpszTextMessage = "Неудачный пуск пожаротушения";
else if (dwMsgNum == 140) lpszTextMessage = "Ручной тест";
else if (dwMsgNum == 141) lpszTextMessage = "Задержка автоматического пуска";
else if (dwMsgNum == 142) lpszTextMessage = "Автоматика выключена";
else if (dwMsgNum == 143) lpszTextMessage = "Отмена пуска АСПТ";
else if (dwMsgNum == 144) lpszTextMessage = "Тушение";
else if (dwMsgNum == 145) lpszTextMessage = "Аварийный пуск АСПТ";
else if (dwMsgNum == 146) lpszTextMessage = "Пуск АУП";
else if (dwMsgNum == 147) lpszTextMessage = "Блокировка пуска АУП";
else if (dwMsgNum == 148) lpszTextMessage = "Автоматика включена";
else if (dwMsgNum == 149) lpszTextMessage = "Открыт корпус прибора";
else if (dwMsgNum == 150) lpszTextMessage = "Пуск речевого оповещения";
else if (dwMsgNum == 151) lpszTextMessage = "Сброс пуска речевого оповещения";
else if (dwMsgNum == 152) lpszTextMessage = "Закрыт корпус прибора";
else if (dwMsgNum == 153) lpszTextMessage = "Срабатывание клапана";
else if (dwMsgNum == 154) lpszTextMessage = "Восстановление клапана";
else if (dwMsgNum == 155) lpszTextMessage = "Отказ клапана";
else if (dwMsgNum == 156) lpszTextMessage = "Ошибка клапана";
else if (dwMsgNum == 158) lpszTextMessage = "Внутренняя зона востановления";
else if (dwMsgNum == 165) lpszTextMessage = "Ошибка параметров ШС";
else if (dwMsgNum == 187) lpszTextMessage = "ШС отключен";
else if (dwMsgNum == 188) lpszTextMessage = "ШС подключен";
else if (dwMsgNum == 189) lpszTextMessage = "Нет связи ДПЛС1";
else if (dwMsgNum == 190) lpszTextMessage = "Нет связи ДПЛС2";
else if (dwMsgNum == 191) lpszTextMessage = "Восстановлена связь ДПЛС1";
else if (dwMsgNum == 192) lpszTextMessage = "Отключен РИП";
else if (dwMsgNum == 193) lpszTextMessage = "Включен РИП";
else if (dwMsgNum == 194) lpszTextMessage = "Перегрузка РИП";
else if (dwMsgNum == 195) lpszTextMessage = "Устранена перегрузка РИП";
else if (dwMsgNum == 196) lpszTextMessage = "Неисправность ЗУ РИП";
else if (dwMsgNum == 197) lpszTextMessage = "Восстановление ЗУ РИП";
else if (dwMsgNum == 198) lpszTextMessage = "Авария питания";
else if (dwMsgNum == 199) lpszTextMessage = "Восстановление питания";
else if (dwMsgNum == 200) lpszTextMessage = "Восстановление батареи";
else if (dwMsgNum == 201) lpszTextMessage = "Восстановлена связь ДПЛС2";
else if (dwMsgNum == 202) lpszTextMessage = "Неисправность батареи";
else if (dwMsgNum == 203) lpszTextMessage = "Сброс прибора";
else if (dwMsgNum == 204) lpszTextMessage = "Необходимо обслуживание";
else if (dwMsgNum == 205) lpszTextMessage = "Ошибка теста АКБ";
else if (dwMsgNum == 206) lpszTextMessage = "Пониженная температура";
else if (dwMsgNum == 211) lpszTextMessage = "АКБ разряжена";
else if (dwMsgNum == 214) lpszTextMessage = "Короткое замыкание ШС";
else if (dwMsgNum == 215) lpszTextMessage = "Короткое замыкание ДПЛС";
else if (dwMsgNum == 216) lpszTextMessage = "Сработка датчика";
else if (dwMsgNum == 217) lpszTextMessage = "Отключение ветви RS-485";
else if (dwMsgNum == 218) lpszTextMessage = "Восстановление ветви RS-485";
else if (dwMsgNum == 220) lpszTextMessage = "Срабатывание СДУ";
else if (dwMsgNum == 221) lpszTextMessage = "Отказ СДУ";
else if (dwMsgNum == 222) lpszTextMessage = "Авария ДПЛС";
else if (dwMsgNum == 223) lpszTextMessage = "Отметка наряда";
else if (dwMsgNum == 241) lpszTextMessage = "Раздел взят";
else if (dwMsgNum == 242) lpszTextMessage = "Раздел снят";
else if (dwMsgNum == 250) lpszTextMessage = "Потеряна связь с прибором";
else if (dwMsgNum == 251) lpszTextMessage = "Восстановлена связь с прибором";
else               lpszTextMessage = "---------------";

printf("lpszTextMessage = \r\n",lpszTextMessage);

return lpszTextMessage ;

Функция определяющая формирование сообщения в Alarm Logging

Код: Выделить всё

#pragma code ( "kernel32.dll" )
void GetLocalTime( LPSYSTEMTIME lpSystemTime );
#pragma code()

int CreateASPTMessage(DWORD dwMsgNum, char* lpszTextMessage, char* lpszPointText, char* lpszPosition, char* lpszAdressDevice, char* lpszNumberSHs )
{
MSG_RTDATA_INSTANCECOMMENT_STRUCT MsgCreateEx;
SYSTEMTIME time;
CMN_ERROR scError;

DWORD   dwServiceID = 0;
int iResult = FALSE;
BOOL bOK;

char*   szComputerName = NULL;
char*   szCurrentUser = NULL;
char*   pszServerPrefix = NULL;

printf("Start function CreateOperatorInputMessage\r\n");

//======================================
//  INIT_MESSAGE_STRUCT
//======================================
memset( &MsgCreateEx,0,sizeof( MsgCreateEx ) );// Обнуление структуры
memset( &scError,0,sizeof( scError ) );

GetLocalTime( &time );

MsgCreateEx.dwMsgState = MSG_STATE_COME;
MsgCreateEx.dwMsgNr = dwMsgNum;
MsgCreateEx.stMsgTime = time;
MsgCreateEx.dwFlags = MSG_FLAG_COMMENT | MSG_FLAG_TEXTVALUES;
MsgCreateEx.wPValueUsed = 0x0000;                     // no real process value used
MsgCreateEx.wTextValueUsed = 0x001F;                  // text values 1 .. 7 used for textblocks 1 .. 7

szCurrentUser = GetTagChar("@local::@CurrentUser");         
if ( !( strlen( szCurrentUser ) > 1 ) ) {
   szCurrentUser = "==no user=="; }
strncpy ( MsgCreateEx.szUser,  szCurrentUser , strlen( szCurrentUser ) );         // Current User Name

szComputerName = GetTagChar("@local::@LocalMachineName");
strncpy ( MsgCreateEx.szComputerName, szComputerName , strlen( szComputerName ) );      // Computer Name

//======================================
//  INITIALIZATION TEXT VALUE BLOCKS 1..10
//======================================
//strncpy ( MsgCreateEx.mtTextValue[0].szText, lpszClusterNum, sizeof ( MsgCreateEx.mtTextValue[0].szText ) - 1 );
//strncpy ( MsgCreateEx.mtTextValue[1].szText, lpszWellNum, sizeof ( MsgCreateEx.mtTextValue[1].szText ) - 1 );
strncpy ( MsgCreateEx.mtTextValue[0].szText, lpszTextMessage, sizeof ( MsgCreateEx.mtTextValue[0].szText ) - 1 );
strncpy ( MsgCreateEx.mtTextValue[1].szText, lpszPointText, sizeof ( MsgCreateEx.mtTextValue[1].szText ) - 1 );
strncpy ( MsgCreateEx.mtTextValue[2].szText, lpszPosition, sizeof ( MsgCreateEx.mtTextValue[2].szText ) - 1 );

strncpy ( MsgCreateEx.mtTextValue[3].szText, lpszAdressDevice, sizeof ( MsgCreateEx.mtTextValue[3].szText ) - 1 );
strncpy ( MsgCreateEx.mtTextValue[4].szText, lpszNumberSHs, sizeof ( MsgCreateEx.mtTextValue[4].szText ) - 1 );


strncpy ( MsgCreateEx.mtTextValue[5].szText, szCurrentUser, strlen( szCurrentUser ) );
strncpy ( MsgCreateEx.mtTextValue[6].szText, szComputerName, strlen( szComputerName ) );

//======================================
//  START_MESSAGE_SERVICE
//======================================
bOK = MSRTStartMsgService( &dwServiceID, NULL, NULL, ( DWORD ) 0, NULL, NULL );

if ( bOK == FALSE ) {
     printf( "#E101: ISALG_OperationLog() - Unable to start message service!" );
     return ( -101 ); }

//======================================
//  CREATE_MESSAGE_INSTANCE
//======================================
bOK = MSRTCreateMsgInstanceWithComment( dwServiceID, &MsgCreateEx, &scError ) ;     //Create Message

if ( bOK == FALSE ) {
     printf ( "#E301: ISALG_OperationLog()  - Error at MSRTCreateMsg()  szErrorText=\"%s\"\r\n", scError.szErrorText );
     iResult = -301; }

//======================================
//  STOP_MESSAGE_SERVICE
//======================================
bOK = MSRTStopMsgService( dwServiceID, &scError );

return ( iResult );
}

И собственно action которая будет все собирать

Код: Выделить всё

{
// WINCC:TAGNAME_SECTION_START
// syntax: #define TagNameInAction "DMTagName"
// next TagID : 1
// WINCC:TAGNAME_SECTION_END

// WINCC:PICNAME_SECTION_START
// syntax: #define PicNameInAction "PictureName"
// next PicID : 1
// WINCC:PICNAME_SECTION_END
#define  Tag_input_Bolid "KU1_C2_4_01_1_MZ_IPR_L"

int const dwMsgNum = 1001;
char* lpszTextMessage = NULL;
char* lpszPointText = "КУ1";
char* lpszPosition = "-";
char* lpszAdressDevice = "C2000-4:1";
char* lpszNumberSHs = "ШС№1";



BYTE Tag_1 = GetTagByte(Tag_input_Bolid);


if (Tag_1 != 0)
{
lpszTextMessage = Alarm_ASPT(Tag_1);   //Return-Type: char*
//CreateASPTMessage(1001,lpszTextMessage,"КУ1_МашЗал_ИПР","C2000-4:1","ШС№1");   //Return-Type: long int
CreateASPTMessage(dwMsgNum,lpszTextMessage,lpszPointText,lpszPosition, lpszAdressDevice,lpszNumberSHs);   //Return-Type: long int
}



return 0;
}


Но столкнулся с дилеммой: раз у меня огромное количество тегов - то и будет такое же количество Action что не совсем удобно -если вдруг я решу что т исправить... Может кто подскажет как реализовать такую задачу более простым путем?



Fail
Сообщений в теме: 3
Сообщения: 5
Зарегистрирован: 22 янв 2015, 09:26

Re: Аварийные сообщения в WinCC

#2

Сообщение Fail » 04 июн 2015, 14:18

с подсистемы Bolid приходят сообщения вот в таком виде - тобишь, состояние шлейфа два байта, в старшем одно число, в младшем другое (на случай если два сообщения появились одновременно - выставляются они по приоритетам). Что бы сделать битами надо тогда собирать на контроллере. Но опять же сколько выделять слов под эти аварии. С болида идет порядка 100 аварий - они просто сделали универсальную таблицу на все все все.... Оттуда конечно можно выбрать сообщения по шлейфам по приборам и прочее... но опять же сообщения могут варьироваться в зависимости от типа шлейфа... в итоге получаем, что проще передать на АРМ байты и уже там попытаться их разрулить..



Аватара пользователя
alex
Администратор
Сообщений в теме: 2
Сообщения: 1692
Зарегистрирован: 05 апр 2010, 21:58
Откуда: Москва
Благодарил (а): 43 раза
Поблагодарили: 91 раз
Контактная информация:

Re: Аварийные сообщения в WinCC

#3

Сообщение alex » 04 июн 2015, 14:47

Сколько в итоге получается тегов с болида в WinCC?



Fail
Сообщений в теме: 3
Сообщения: 5
Зарегистрирован: 22 янв 2015, 09:26

Re: Аварийные сообщения в WinCC

#4

Сообщение Fail » 04 июн 2015, 14:57

Более 200



Аватара пользователя
alex
Администратор
Сообщений в теме: 2
Сообщения: 1692
Зарегистрирован: 05 апр 2010, 21:58
Откуда: Москва
Благодарил (а): 43 раза
Поблагодарили: 91 раз
Контактная информация:

Re: Аварийные сообщения в WinCC

#5

Сообщение alex » 04 июн 2015, 15:16

Лучше конечно все это переложить на плечи контроллера, разложить все аварии по битам и затем штатно оформить это в WinCC в Alarm Loggining. Через скрипты можно все это сделать и даже через одну функцию, но здесь надо поработать над структурой данных и кодом и в этом случае вопрос может упереться в производительность скриптового движка WinCC, т.к. он не любит, когда скрипты выполняются долго. На мой взгляд, компромиссным может быть следующий подход: скрипт делает побитовый разбор тегов с болида во внутренние теги WinCC, к которым привязываются сообщения Alarm Loggining, которые в свою очередь можно создать/обновлять автоматически на стадии конфигурирования. В обоих частях можно продумать как это сделать просто и красиво.




Если эта тема может быть полезна другим, поделитесь ссылкой:

Вернуться в «SIMATIC: WinCC OA, WinCC, WinCC Flexible, ProTool»