Commit fe8d7440 authored by Ivan Tyagov's avatar Ivan Tyagov

Add first example of a coupler with SVG HMI interface.

parent d1b74da6
<?xml version='1.0' encoding='utf-8'?>
<BeremizRoot xmlns:xsd="http://www.w3.org/2001/XMLSchema" URI_location="LOCAL://">
<TargetType/>
<Libraries Enable_SVGHMI_Library="true"/>
</BeremizRoot>
__LOCATED_VAR(DINT,__QD1_0,Q,D,1,0)
__LOCATED_VAR(DINT,__QD1_1,Q,D,1,1)
__LOCATED_VAR(DINT,__QD1_2,Q,D,1,2)
__LOCATED_VAR(DINT,__QD1_3,Q,D,1,3)
void LOGGER_init__(LOGGER *data__, BOOL retain) {
__INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->MSG,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->LEVEL,LOGLEVEL__INFO,retain)
__INIT_VAR(data__->TRIG0,__BOOL_LITERAL(FALSE),retain)
}
// Code part
void LOGGER_body__(LOGGER *data__) {
// Control execution
if (!__GET_VAR(data__->EN)) {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE));
return;
}
else {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE));
}
// Initialise TEMP variables
if ((__GET_VAR(data__->TRIG,) && !(__GET_VAR(data__->TRIG0,)))) {
#define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__)
#define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val)
LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len));
#undef GetFbVar
#undef SetFbVar
;
};
__SET_VAR(data__->,TRIG0,,__GET_VAR(data__->TRIG,));
goto __end;
__end:
return;
} // LOGGER_body__()
void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain) {
__INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->STATE,0,retain)
__INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain)
}
// Code part
void PYTHON_EVAL_body__(PYTHON_EVAL *data__) {
// Control execution
if (!__GET_VAR(data__->EN)) {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE));
return;
}
else {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE));
}
// Initialise TEMP variables
__IL_DEFVAR_T __IL_DEFVAR;
__IL_DEFVAR_T __IL_DEFVAR_BACK;
#define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__)
#define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val)
extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);
#undef GetFbVar
#undef SetFbVar
;
goto __end;
__end:
return;
} // PYTHON_EVAL_body__()
void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain) {
__INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->STATE,0,retain)
__INIT_VAR(data__->BUFFER,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->PREBUFFER,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->TRIGM1,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->TRIGGED,__BOOL_LITERAL(FALSE),retain)
}
// Code part
void PYTHON_POLL_body__(PYTHON_POLL *data__) {
// Control execution
if (!__GET_VAR(data__->EN)) {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE));
return;
}
else {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE));
}
// Initialise TEMP variables
__IL_DEFVAR_T __IL_DEFVAR;
__IL_DEFVAR_T __IL_DEFVAR_BACK;
#define GetFbVar(var,...) __GET_VAR(data__->var,__VA_ARGS__)
#define SetFbVar(var,val,...) __SET_VAR(data__->,var,__VA_ARGS__,val)
extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);
#undef GetFbVar
#undef SetFbVar
;
goto __end;
__end:
return;
} // PYTHON_POLL_body__()
void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain) {
__INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->N,0,retain)
__INIT_VAR(data__->TRIG,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->CODE,__STRING_LITERAL(0,""),retain)
__INIT_VAR(data__->ACK,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->RESULT,__STRING_LITERAL(0,""),retain)
PYTHON_EVAL_init__(&data__->PY_EVAL,retain);
__INIT_VAR(data__->COUNTER,0,retain)
__INIT_VAR(data__->_TMP_ADD10_OUT,0,retain)
__INIT_VAR(data__->_TMP_EQ13_OUT,__BOOL_LITERAL(FALSE),retain)
__INIT_VAR(data__->_TMP_SEL15_OUT,0,retain)
__INIT_VAR(data__->_TMP_AND7_OUT,__BOOL_LITERAL(FALSE),retain)
}
// Code part
void PYTHON_GEAR_body__(PYTHON_GEAR *data__) {
// Control execution
if (!__GET_VAR(data__->EN)) {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE));
return;
}
else {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE));
}
// Initialise TEMP variables
__SET_VAR(data__->,_TMP_ADD10_OUT,,ADD__UINT__UINT(
(BOOL)__BOOL_LITERAL(TRUE),
NULL,
(UINT)2,
(UINT)__GET_VAR(data__->COUNTER,),
(UINT)1));
__SET_VAR(data__->,_TMP_EQ13_OUT,,EQ__BOOL__UINT(
(BOOL)__BOOL_LITERAL(TRUE),
NULL,
(UINT)2,
(UINT)__GET_VAR(data__->N,),
(UINT)__GET_VAR(data__->_TMP_ADD10_OUT,)));
__SET_VAR(data__->,_TMP_SEL15_OUT,,SEL__UINT__BOOL__UINT__UINT(
(BOOL)__BOOL_LITERAL(TRUE),
NULL,
(BOOL)__GET_VAR(data__->_TMP_EQ13_OUT,),
(UINT)__GET_VAR(data__->_TMP_ADD10_OUT,),
(UINT)0));
__SET_VAR(data__->,COUNTER,,__GET_VAR(data__->_TMP_SEL15_OUT,));
__SET_VAR(data__->,_TMP_AND7_OUT,,AND__BOOL__BOOL(
(BOOL)__BOOL_LITERAL(TRUE),
NULL,
(UINT)2,
(BOOL)__GET_VAR(data__->_TMP_EQ13_OUT,),
(BOOL)__GET_VAR(data__->TRIG,)));
__SET_VAR(data__->PY_EVAL.,TRIG,,__GET_VAR(data__->_TMP_AND7_OUT,));
__SET_VAR(data__->PY_EVAL.,CODE,,__GET_VAR(data__->CODE,));
PYTHON_EVAL_body__(&data__->PY_EVAL);
__SET_VAR(data__->,ACK,,__GET_VAR(data__->PY_EVAL.ACK,));
__SET_VAR(data__->,RESULT,,__GET_VAR(data__->PY_EVAL.RESULT,));
goto __end;
__end:
return;
} // PYTHON_GEAR_body__()
void COUNTERST_init__(COUNTERST *data__, BOOL retain) {
__INIT_VAR(data__->EN,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->ENO,__BOOL_LITERAL(TRUE),retain)
__INIT_VAR(data__->CNT0,0,retain)
__INIT_EXTERNAL(DINT,RELAY0,data__->RELAY0,retain)
__INIT_EXTERNAL(DINT,RELAY1,data__->RELAY1,retain)
__INIT_EXTERNAL(DINT,RELAY2,data__->RELAY2,retain)
__INIT_EXTERNAL(DINT,RELAY3,data__->RELAY3,retain)
__INIT_EXTERNAL(HMI_INT,HMI_RELAY0,data__->HMI_RELAY0,retain)
__INIT_EXTERNAL(HMI_INT,HMI_RELAY1,data__->HMI_RELAY1,retain)
__INIT_EXTERNAL(HMI_INT,HMI_RELAY2,data__->HMI_RELAY2,retain)
__INIT_EXTERNAL(HMI_INT,HMI_RELAY3,data__->HMI_RELAY3,retain)
}
// Code part
void COUNTERST_body__(COUNTERST *data__) {
// Control execution
if (!__GET_VAR(data__->EN)) {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(FALSE));
return;
}
else {
__SET_VAR(data__->,ENO,,__BOOL_LITERAL(TRUE));
}
// Initialise TEMP variables
if ((__GET_EXTERNAL(data__->HMI_RELAY2,) >= 1)) {
__SET_EXTERNAL(data__->,RELAY2,,1);
} else {
__SET_EXTERNAL(data__->,RELAY2,,0);
};
if ((__GET_EXTERNAL(data__->HMI_RELAY3,) >= 1)) {
__SET_EXTERNAL(data__->,RELAY3,,1);
} else {
__SET_EXTERNAL(data__->,RELAY3,,0);
};
__SET_VAR(data__->,CNT0,,(__GET_VAR(data__->CNT0,) + 1));
if ((__GET_VAR(data__->CNT0,) == 50)) {
__SET_EXTERNAL(data__->,RELAY0,,1);
__SET_EXTERNAL(data__->,HMI_RELAY0,,1);
__SET_EXTERNAL(data__->,RELAY1,,1);
__SET_EXTERNAL(data__->,HMI_RELAY1,,1);
};
if ((__GET_VAR(data__->CNT0,) == 100)) {
__SET_EXTERNAL(data__->,RELAY0,,0);
__SET_EXTERNAL(data__->,HMI_RELAY0,,0);
__SET_EXTERNAL(data__->,RELAY1,,0);
__SET_EXTERNAL(data__->,HMI_RELAY1,,0);
__SET_VAR(data__->,CNT0,,0);
};
goto __end;
__end:
return;
} // COUNTERST_body__()
void PLC_PRG_init__(PLC_PRG *data__, BOOL retain) {
COUNTERST_init__(&data__->COUNTERST0,retain);
}
// Code part
void PLC_PRG_body__(PLC_PRG *data__) {
// Initialise TEMP variables
COUNTERST_body__(&data__->COUNTERST0);
goto __end;
__end:
return;
} // PLC_PRG_body__()
#include "beremiz.h"
#ifndef __POUS_H
#define __POUS_H
#include "accessor.h"
#include "iec_std_lib.h"
__DECLARE_ENUMERATED_TYPE(LOGLEVEL,
LOGLEVEL__CRITICAL,
LOGLEVEL__WARNING,
LOGLEVEL__INFO,
LOGLEVEL__DEBUG
)
__DECLARE_DERIVED_TYPE(HMI_REAL,REAL)
__DECLARE_DERIVED_TYPE(HMI_NODE,BOOL)
__DECLARE_DERIVED_TYPE(HMI_STRING,STRING)
__DECLARE_DERIVED_TYPE(HMI_BOOL,BOOL)
__DECLARE_DERIVED_TYPE(HMI_INT,INT)
// FUNCTION_BLOCK LOGGER
// Data part
typedef struct {
// FB Interface - IN, OUT, IN_OUT variables
__DECLARE_VAR(BOOL,EN)
__DECLARE_VAR(BOOL,ENO)
__DECLARE_VAR(BOOL,TRIG)
__DECLARE_VAR(STRING,MSG)
__DECLARE_VAR(LOGLEVEL,LEVEL)
// FB private variables - TEMP, private and located variables
__DECLARE_VAR(BOOL,TRIG0)
} LOGGER;
void LOGGER_init__(LOGGER *data__, BOOL retain);
// Code part
void LOGGER_body__(LOGGER *data__);
// FUNCTION_BLOCK PYTHON_EVAL
// Data part
typedef struct {
// FB Interface - IN, OUT, IN_OUT variables
__DECLARE_VAR(BOOL,EN)
__DECLARE_VAR(BOOL,ENO)
__DECLARE_VAR(BOOL,TRIG)
__DECLARE_VAR(STRING,CODE)
__DECLARE_VAR(BOOL,ACK)
__DECLARE_VAR(STRING,RESULT)
// FB private variables - TEMP, private and located variables
__DECLARE_VAR(DWORD,STATE)
__DECLARE_VAR(STRING,BUFFER)
__DECLARE_VAR(STRING,PREBUFFER)
__DECLARE_VAR(BOOL,TRIGM1)
__DECLARE_VAR(BOOL,TRIGGED)
} PYTHON_EVAL;
void PYTHON_EVAL_init__(PYTHON_EVAL *data__, BOOL retain);
// Code part
void PYTHON_EVAL_body__(PYTHON_EVAL *data__);
// FUNCTION_BLOCK PYTHON_POLL
// Data part
typedef struct {
// FB Interface - IN, OUT, IN_OUT variables
__DECLARE_VAR(BOOL,EN)
__DECLARE_VAR(BOOL,ENO)
__DECLARE_VAR(BOOL,TRIG)
__DECLARE_VAR(STRING,CODE)
__DECLARE_VAR(BOOL,ACK)
__DECLARE_VAR(STRING,RESULT)
// FB private variables - TEMP, private and located variables
__DECLARE_VAR(DWORD,STATE)
__DECLARE_VAR(STRING,BUFFER)
__DECLARE_VAR(STRING,PREBUFFER)
__DECLARE_VAR(BOOL,TRIGM1)
__DECLARE_VAR(BOOL,TRIGGED)
} PYTHON_POLL;
void PYTHON_POLL_init__(PYTHON_POLL *data__, BOOL retain);
// Code part
void PYTHON_POLL_body__(PYTHON_POLL *data__);
// FUNCTION_BLOCK PYTHON_GEAR
// Data part
typedef struct {
// FB Interface - IN, OUT, IN_OUT variables
__DECLARE_VAR(BOOL,EN)
__DECLARE_VAR(BOOL,ENO)
__DECLARE_VAR(UINT,N)
__DECLARE_VAR(BOOL,TRIG)
__DECLARE_VAR(STRING,CODE)
__DECLARE_VAR(BOOL,ACK)
__DECLARE_VAR(STRING,RESULT)
// FB private variables - TEMP, private and located variables
PYTHON_EVAL PY_EVAL;
__DECLARE_VAR(UINT,COUNTER)
__DECLARE_VAR(UINT,_TMP_ADD10_OUT)
__DECLARE_VAR(BOOL,_TMP_EQ13_OUT)
__DECLARE_VAR(UINT,_TMP_SEL15_OUT)
__DECLARE_VAR(BOOL,_TMP_AND7_OUT)
} PYTHON_GEAR;
void PYTHON_GEAR_init__(PYTHON_GEAR *data__, BOOL retain);
// Code part
void PYTHON_GEAR_body__(PYTHON_GEAR *data__);
// FUNCTION_BLOCK COUNTERST
// Data part
typedef struct {
// FB Interface - IN, OUT, IN_OUT variables
__DECLARE_VAR(BOOL,EN)
__DECLARE_VAR(BOOL,ENO)
// FB private variables - TEMP, private and located variables
__DECLARE_VAR(INT,CNT0)
__DECLARE_EXTERNAL(DINT,RELAY0)
__DECLARE_EXTERNAL(DINT,RELAY1)
__DECLARE_EXTERNAL(DINT,RELAY2)
__DECLARE_EXTERNAL(DINT,RELAY3)
__DECLARE_EXTERNAL(HMI_INT,HMI_RELAY0)
__DECLARE_EXTERNAL(HMI_INT,HMI_RELAY1)
__DECLARE_EXTERNAL(HMI_INT,HMI_RELAY2)
__DECLARE_EXTERNAL(HMI_INT,HMI_RELAY3)
} COUNTERST;
void COUNTERST_init__(COUNTERST *data__, BOOL retain);
// Code part
void COUNTERST_body__(COUNTERST *data__);
// PROGRAM PLC_PRG
// Data part
typedef struct {
// PROGRAM Interface - IN, OUT, IN_OUT variables
// PROGRAM private variables - TEMP, private and located variables
COUNTERST COUNTERST0;
} PLC_PRG;
void PLC_PRG_init__(PLC_PRG *data__, BOOL retain);
// Code part
void PLC_PRG_body__(PLC_PRG *data__);
#endif //__POUS_H
// Programs
0;CONFIG.RESOURCE1.INSTANCE0;PLC_PRG;
// Variables
0;OUT;CONFIG.RELAY0;CONFIG.RELAY0;DINT;DINT;
1;OUT;CONFIG.RELAY1;CONFIG.RELAY1;DINT;DINT;
2;OUT;CONFIG.RELAY2;CONFIG.RELAY2;DINT;DINT;
3;OUT;CONFIG.RELAY3;CONFIG.RELAY3;DINT;DINT;
4;VAR;CONFIG.HMI_RELAY0;CONFIG.HMI_RELAY0;INT;HMI_INT;
5;VAR;CONFIG.HMI_RELAY1;CONFIG.HMI_RELAY1;INT;HMI_INT;
6;VAR;CONFIG.HMI_RELAY2;CONFIG.HMI_RELAY2;INT;HMI_INT;
7;VAR;CONFIG.HMI_RELAY3;CONFIG.HMI_RELAY3;INT;HMI_INT;
8;VAR;CONFIG.HMI_ROOT;CONFIG.HMI_ROOT;BOOL;HMI_NODE;
9;VAR;CONFIG.HEARTBEAT;CONFIG.HEARTBEAT;INT;HMI_INT;
10;VAR;CONFIG.CURRENT_PAGE_0;CONFIG.CURRENT_PAGE_0;STRING;HMI_STRING;
11;FB;CONFIG.RESOURCE1.INSTANCE0;CONFIG.RESOURCE1.INSTANCE0;PLC_PRG;;
12;FB;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0;COUNTERST;;
13;VAR;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.EN;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.EN;BOOL;BOOL;
14;VAR;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.ENO;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.ENO;BOOL;BOOL;
15;VAR;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.CNT0;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.CNT0;INT;INT;
16;EXT;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.RELAY0;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.RELAY0;DINT;DINT;
17;EXT;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.RELAY1;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.RELAY1;DINT;DINT;
18;EXT;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.RELAY2;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.RELAY2;DINT;DINT;
19;EXT;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.RELAY3;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.RELAY3;DINT;DINT;
20;EXT;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.HMI_RELAY0;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.HMI_RELAY0;INT;HMI_INT;
21;EXT;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.HMI_RELAY1;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.HMI_RELAY1;INT;HMI_INT;
22;EXT;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.HMI_RELAY2;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.HMI_RELAY2;INT;HMI_INT;
23;EXT;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.HMI_RELAY3;CONFIG.RESOURCE1.INSTANCE0.COUNTERST0.HMI_RELAY3;INT;HMI_INT;
// Ticktime
20000000
#ifndef _BEREMIZ_H_
#define _BEREMIZ_H_
/* Beremiz' header file for use by extensions */
#include "iec_types.h"
#define LOG_LEVELS 4
#define LOG_CRITICAL 0
#define LOG_WARNING 1
#define LOG_INFO 2
#define LOG_DEBUG 3
extern unsigned long long common_ticktime__;
#ifdef TARGET_LOGGING_DISABLE
static inline int LogMessage(uint8_t level, char* buf, uint32_t size)
{
(void)level;
(void)buf;
(void)size;
return 0;
}
#else
int LogMessage(uint8_t level, char* buf, uint32_t size);
#endif
long AtomicCompareExchange(long* atomicvar,long compared, long exchange);
void *create_RT_to_nRT_signal(char* name);
void delete_RT_to_nRT_signal(void* handle);
int wait_RT_to_nRT_signal(void* handle);
int unblock_RT_to_nRT_signal(void* handle);
void nRT_reschedule(void);
#endif
/*******************************************/
/* FILE GENERATED BY iec2c */
/* Editing this file is not recommended... */
/*******************************************/
#include "iec_std_lib.h"
#include "accessor.h"
#include "POUS.h"
// CONFIGURATION CONFIG
__DECLARE_GLOBAL_LOCATION(DINT,__QD1_0)
__DECLARE_GLOBAL_LOCATED(DINT,CONFIG,RELAY0)
__DECLARE_GLOBAL_LOCATION(DINT,__QD1_1)
__DECLARE_GLOBAL_LOCATED(DINT,CONFIG,RELAY1)
__DECLARE_GLOBAL_LOCATION(DINT,__QD1_2)
__DECLARE_GLOBAL_LOCATED(DINT,CONFIG,RELAY2)
__DECLARE_GLOBAL_LOCATION(DINT,__QD1_3)
__DECLARE_GLOBAL_LOCATED(DINT,CONFIG,RELAY3)
__DECLARE_GLOBAL(HMI_INT,CONFIG,HMI_RELAY0)
__DECLARE_GLOBAL(HMI_INT,CONFIG,HMI_RELAY1)
__DECLARE_GLOBAL(HMI_INT,CONFIG,HMI_RELAY2)
__DECLARE_GLOBAL(HMI_INT,CONFIG,HMI_RELAY3)
__DECLARE_GLOBAL(HMI_NODE,CONFIG,HMI_ROOT)
__DECLARE_GLOBAL(HMI_INT,CONFIG,HEARTBEAT)
__DECLARE_GLOBAL(HMI_STRING,CONFIG,CURRENT_PAGE_0)
void RESOURCE1_init__(void);
void config_init__(void) {
BOOL retain;
retain = 0;
__INIT_GLOBAL_LOCATED(CONFIG,RELAY0,__QD1_0,retain)
__INIT_GLOBAL(DINT,RELAY0,__INITIAL_VALUE(0),retain)
__INIT_GLOBAL_LOCATED(CONFIG,RELAY1,__QD1_1,retain)
__INIT_GLOBAL(DINT,RELAY1,__INITIAL_VALUE(0),retain)
__INIT_GLOBAL_LOCATED(CONFIG,RELAY2,__QD1_2,retain)
__INIT_GLOBAL(DINT,RELAY2,__INITIAL_VALUE(0),retain)
__INIT_GLOBAL_LOCATED(CONFIG,RELAY3,__QD1_3,retain)
__INIT_GLOBAL(DINT,RELAY3,__INITIAL_VALUE(0),retain)
__INIT_GLOBAL(HMI_INT,HMI_RELAY0,__INITIAL_VALUE(0),retain)
__INIT_GLOBAL(HMI_INT,HMI_RELAY1,__INITIAL_VALUE(0),retain)
__INIT_GLOBAL(HMI_INT,HMI_RELAY2,__INITIAL_VALUE(0),retain)
__INIT_GLOBAL(HMI_INT,HMI_RELAY3,__INITIAL_VALUE(0),retain)
__INIT_GLOBAL(HMI_NODE,HMI_ROOT,__INITIAL_VALUE(__BOOL_LITERAL(FALSE)),retain)
__INIT_GLOBAL(HMI_INT,HEARTBEAT,__INITIAL_VALUE(0),retain)
__INIT_GLOBAL(HMI_STRING,CURRENT_PAGE_0,__INITIAL_VALUE(__STRING_LITERAL(0,"")),retain)
RESOURCE1_init__();
}
void RESOURCE1_run__(unsigned long tick);
void config_run__(unsigned long tick) {
RESOURCE1_run__(tick);
}
unsigned long long common_ticktime__ = 20000000ULL * 1ULL; /*ns*/
unsigned long greatest_tick_count__ = (unsigned long)0UL; /*tick*/
#include "beremiz.h"
__DECLARE_GLOBAL_PROTOTYPE(DINT,RELAY0)
__DECLARE_GLOBAL_PROTOTYPE(DINT,RELAY1)
__DECLARE_GLOBAL_PROTOTYPE(DINT,RELAY2)
__DECLARE_GLOBAL_PROTOTYPE(DINT,RELAY3)
__DECLARE_GLOBAL_PROTOTYPE(HMI_INT,HMI_RELAY0)
__DECLARE_GLOBAL_PROTOTYPE(HMI_INT,HMI_RELAY1)
__DECLARE_GLOBAL_PROTOTYPE(HMI_INT,HMI_RELAY2)
__DECLARE_GLOBAL_PROTOTYPE(HMI_INT,HMI_RELAY3)
__DECLARE_GLOBAL_PROTOTYPE(HMI_NODE,HMI_ROOT)
__DECLARE_GLOBAL_PROTOTYPE(HMI_INT,HEARTBEAT)
__DECLARE_GLOBAL_PROTOTYPE(HMI_STRING,CURRENT_PAGE_0)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of Beremiz
# Copyright (C) 2019: Edouard TISSERANT
# See COPYING file for copyrights details.
from __future__ import absolute_import
import errno
from threading import RLock, Timer
try:
from runtime.spawn_subprocess import Popen
except ImportError:
from subprocess import Popen
from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import reactor
from twisted.web.static import File
from autobahn.twisted.websocket import WebSocketServerFactory, WebSocketServerProtocol
from autobahn.websocket.protocol import WebSocketProtocol
from autobahn.twisted.resource import WebSocketResource
max_svghmi_sessions = None
svghmi_watchdog = None
svghmi_wait = PLCBinary.svghmi_wait
svghmi_wait.restype = ctypes.c_int # error or 0
svghmi_wait.argtypes = []
svghmi_continue_collect = ctypes.c_int.in_dll(PLCBinary, "svghmi_continue_collect")
svghmi_send_collect = PLCBinary.svghmi_send_collect
svghmi_send_collect.restype = ctypes.c_int # error or 0
svghmi_send_collect.argtypes = [
ctypes.c_uint32, # index
ctypes.POINTER(ctypes.c_uint32), # size
ctypes.POINTER(ctypes.c_void_p)] # data ptr
svghmi_reset = PLCBinary.svghmi_reset
svghmi_reset.restype = ctypes.c_int # error or 0
svghmi_reset.argtypes = [
ctypes.c_uint32] # index
svghmi_recv_dispatch = PLCBinary.svghmi_recv_dispatch
svghmi_recv_dispatch.restype = ctypes.c_int # error or 0
svghmi_recv_dispatch.argtypes = [
ctypes.c_uint32, # index
ctypes.c_uint32, # size
ctypes.c_char_p] # data ptr
class HMISessionMgr(object):
def __init__(self):
self.multiclient_sessions = set()
self.watchdog_session = None
self.session_count = 0
self.lock = RLock()
self.indexes = set()
def next_index(self):
if self.indexes:
greatest = max(self.indexes)
holes = set(range(greatest)) - self.indexes
index = min(holes) if holes else greatest+1
else:
index = 0
self.indexes.add(index)
return index
def free_index(self, index):
self.indexes.remove(index)
def register(self, session):
global max_svghmi_sessions
with self.lock:
if session.is_watchdog_session:
# Creating a new watchdog session closes pre-existing one
if self.watchdog_session is not None:
self.unregister(self.watchdog_session)
else:
assert(self.session_count < max_svghmi_sessions)
self.session_count += 1
self.watchdog_session = session
else:
assert(self.session_count < max_svghmi_sessions)
self.multiclient_sessions.add(session)
self.session_count += 1
session.session_index = self.next_index()
def unregister(self, session):
with self.lock:
if session.is_watchdog_session :
if self.watchdog_session != session:
return
self.watchdog_session = None
else:
try:
self.multiclient_sessions.remove(session)
except KeyError:
return
self.free_index(session.session_index)
self.session_count -= 1
session.kill()
def close_all(self):
for session in self.iter_sessions():
self.unregister(session)
def iter_sessions(self):
with self.lock:
lst = list(self.multiclient_sessions)
if self.watchdog_session is not None:
lst = [self.watchdog_session]+lst
for nxt_session in lst:
yield nxt_session
svghmi_session_manager = HMISessionMgr()
class HMISession(object):
def __init__(self, protocol_instance):
self.protocol_instance = protocol_instance
self._session_index = None
self.closed = False
@property
def is_watchdog_session(self):
return self.protocol_instance.has_watchdog
@property
def session_index(self):
return self._session_index
@session_index.setter
def session_index(self, value):
self._session_index = value
def reset(self):
return svghmi_reset(self.session_index)
def close(self):
if self.closed: return
self.protocol_instance.sendClose(WebSocketProtocol.CLOSE_STATUS_CODE_NORMAL)
def notify_closed(self):
self.closed = True
def kill(self):
self.close()
self.reset()
def onMessage(self, msg):
# pass message to the C side recieve_message()
if self.closed: return
return svghmi_recv_dispatch(self.session_index, len(msg), msg)
def sendMessage(self, msg):
if self.closed: return
self.protocol_instance.sendMessage(msg, True)
return 0
class Watchdog(object):
def __init__(self, initial_timeout, interval, callback):
self._callback = callback
self.lock = RLock()
self.initial_timeout = initial_timeout
self.interval = interval
self.callback = callback
with self.lock:
self._start()
def _start(self, rearm=False):
duration = self.interval if rearm else self.initial_timeout
if duration:
self.timer = Timer(duration, self.trigger)
self.timer.start()
else:
self.timer = None
def _stop(self):
if self.timer is not None:
self.timer.cancel()
self.timer = None
def cancel(self):
with self.lock:
self._stop()
def feed(self, rearm=True):
with self.lock:
self._stop()
self._start(rearm)
def trigger(self):
self._callback()
# Don't repeat trigger periodically
# # wait for initial timeout on re-start
# self.feed(rearm=False)
class HMIProtocol(WebSocketServerProtocol):
def __init__(self, *args, **kwargs):
self._hmi_session = None
self.has_watchdog = False
WebSocketServerProtocol.__init__(self, *args, **kwargs)
def onConnect(self, request):
self.has_watchdog = request.params.get("mode", [None])[0] == "watchdog"
return WebSocketServerProtocol.onConnect(self, request)
def onOpen(self):
global svghmi_session_manager
assert(self._hmi_session is None)
_hmi_session = HMISession(self)
registered = svghmi_session_manager.register(_hmi_session)
self._hmi_session = _hmi_session
def onClose(self, wasClean, code, reason):
global svghmi_session_manager
if self._hmi_session is None : return
self._hmi_session.notify_closed()
svghmi_session_manager.unregister(self._hmi_session)
self._hmi_session = None
def onMessage(self, msg, isBinary):
global svghmi_watchdog
if self._hmi_session is None : return
result = self._hmi_session.onMessage(msg)
if result == 1 and self.has_watchdog: # was heartbeat
if svghmi_watchdog is not None:
svghmi_watchdog.feed()
class HMIWebSocketServerFactory(WebSocketServerFactory):
protocol = HMIProtocol
svghmi_servers = {}
svghmi_send_thread = None
# python's errno on windows seems to have no ENODATA
ENODATA = errno.ENODATA if hasattr(errno,"ENODATA") else None
def SendThreadProc():
global svghmi_session_manager
size = ctypes.c_uint32()
ptr = ctypes.c_void_p()
res = 0
while svghmi_continue_collect:
svghmi_wait()
for svghmi_session in svghmi_session_manager.iter_sessions():
res = svghmi_send_collect(
svghmi_session.session_index,
ctypes.byref(size), ctypes.byref(ptr))
if res == 0:
svghmi_session.sendMessage(
ctypes.string_at(ptr.value,size.value))
elif res == ENODATA:
# this happens when there is no data after wakeup
# because of hmi data refresh period longer than
# PLC common ticktime
pass
else:
# this happens when finishing
break
def AddPathToSVGHMIServers(path, factory, *args, **kwargs):
for k,v in svghmi_servers.iteritems():
svghmi_root, svghmi_listener, path_list = v
svghmi_root.putChild(path, factory(*args, **kwargs))
# Called by PLCObject at start
def _runtime_00_svghmi_start():
global svghmi_send_thread
# start a thread that call the C part of SVGHMI
svghmi_send_thread = Thread(target=SendThreadProc, name="SVGHMI Send")
svghmi_send_thread.start()
# Called by PLCObject at stop
def _runtime_00_svghmi_stop():
global svghmi_send_thread, svghmi_session
svghmi_session_manager.close_all()
# plc cleanup calls svghmi_(locstring)_cleanup and unlocks send thread
svghmi_send_thread.join()
svghmi_send_thread = None
class NoCacheFile(File):
def render_GET(self, request):
request.setHeader(b"Cache-Control", b"no-cache, no-store")
return File.render_GET(self, request)
render_HEAD = render_GET
# TODO : multiple watchdog (one for each svghmi instance)
def svghmi_0_watchdog_trigger():
Popen(['echo', 'Watchdog', 'for', 'svghmi_0', '!'])
max_svghmi_sessions = 16
def _runtime_0_svghmi_start():
global svghmi_watchdog, svghmi_servers
srv = svghmi_servers.get("localhost:8008", None)
if srv is not None:
svghmi_root, svghmi_listener, path_list = srv
if 'svghmi_0' in path_list:
raise Exception("SVGHMI svghmi_0: path svghmi_0 already used on localhost:8008")
else:
svghmi_root = Resource()
factory = HMIWebSocketServerFactory()
factory.setProtocolOptions(maxConnections=16)
svghmi_root.putChild("ws", WebSocketResource(factory))
svghmi_listener = reactor.listenTCP(8008, Site(svghmi_root), interface='localhost')
path_list = []
svghmi_servers["localhost:8008"] = (svghmi_root, svghmi_listener, path_list)
svghmi_root.putChild(
'svghmi_0',
NoCacheFile('svghmi_0.xhtml',
defaultType='application/xhtml+xml'))
path_list.append("svghmi_0")
Popen(['chromium', 'http://localhost:8008/svghmi_0#watchdog'])
if True:
if svghmi_watchdog is None:
svghmi_watchdog = Watchdog(
30,
5,
svghmi_0_watchdog_trigger)
else:
raise Exception("SVGHMI svghmi_0: only one watchdog allowed")
def _runtime_0_svghmi_stop():
global svghmi_watchdog, svghmi_servers
if svghmi_watchdog is not None:
svghmi_watchdog.cancel()
svghmi_watchdog = None
svghmi_root, svghmi_listener, path_list = svghmi_servers["localhost:8008"]
svghmi_root.delEntity('svghmi_0')
path_list.remove('svghmi_0')
if len(path_list)==0:
svghmi_root.delEntity("ws")
svghmi_listener.stopListening()
svghmi_servers.pop("localhost:8008")
pass # no command given
\ No newline at end of file
FUNCTION_BLOCK CounterST
VAR
Cnt0 : INT;
END_VAR
VAR_EXTERNAL
Relay0 : DINT;
Relay1 : DINT;
Relay2 : DINT;
Relay3 : DINT;
HMI_RELAY0 : HMI_INT;
HMI_RELAY1 : HMI_INT;
HMI_RELAY2 : HMI_INT;
HMI_RELAY3 : HMI_INT;
END_VAR
IF HMI_RELAY2 >= 1 THEN
Relay2:=1;
ELSE
Relay2:=0;
END_IF;
IF HMI_RELAY3 >= 1 THEN
Relay3:=1;
ELSE
Relay3:=0;
END_IF;
Cnt0 := Cnt0 + 1;
IF Cnt0 = 50 THEN
Relay0 := 1;
HMI_RELAY0:= 1;
Relay1 := 1;
HMI_RELAY1:= 1;
END_IF;
IF Cnt0 = 100 THEN
Relay0 := 0;
HMI_RELAY0:= 0;
Relay1 := 0;
HMI_RELAY1:= 0;
Cnt0 := 0;
END_IF;
END_FUNCTION_BLOCK
PROGRAM plc_prg
VAR
CounterST0 : CounterST;
END_VAR
CounterST0();
END_PROGRAM
CONFIGURATION config
VAR_GLOBAL
Relay0 AT %QD1.0 : DINT := 0;
Relay1 AT %QD1.1 : DINT := 0;
Relay2 AT %QD1.2 : DINT := 0;
Relay3 AT %QD1.3 : DINT := 0;
HMI_RELAY0 : HMI_INT := 0;
HMI_RELAY1 : HMI_INT := 0;
HMI_RELAY2 : HMI_INT := 0;
HMI_RELAY3 : HMI_INT := 0;
HMI_ROOT : HMI_NODE;
heartbeat : HMI_INT;
CURRENT_PAGE_0 : HMI_STRING;
END_VAR
RESOURCE resource1 ON PLC
TASK task0(INTERVAL := T#20ms,PRIORITY := 0);
PROGRAM instance0 WITH task0 : plc_prg;
END_RESOURCE
END_CONFIGURATION
<HMI_NODE name="" path="CONFIG.HMI_ROOT"><HMI_INT name="HMI_RELAY0" path="CONFIG.HMI_RELAY0"/><HMI_INT name="HMI_RELAY1" path="CONFIG.HMI_RELAY1"/><HMI_INT name="HMI_RELAY2" path="CONFIG.HMI_RELAY2"/><HMI_INT name="HMI_RELAY3" path="CONFIG.HMI_RELAY3"/><HMI_INT name="HEARTBEAT" path="CONFIG.HEARTBEAT"/><HMI_STRING name="CURRENT_PAGE_0" path="CONFIG.CURRENT_PAGE_0"/></HMI_NODE>
\ No newline at end of file
0d60a23d82a69794d34cd693de3cac7f
\ No newline at end of file
/* code generated by beremiz OPC-UA extension */
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <open62541/plugin/log_stdout.h>
static UA_Client *client;
#define DECL_VAR(ua_type, C_type, c_loc_name) \
static UA_Variant c_loc_name##_variant; \
static C_type c_loc_name##_buf = 0; \
C_type *c_loc_name = &c_loc_name##_buf;
DECL_VAR(UA_Int32, uint32_t, __ID1_0)
DECL_VAR(UA_Int32, uint32_t, __ID1_1)
DECL_VAR(UA_Int32, uint32_t, __ID1_2)
DECL_VAR(UA_Int32, uint32_t, __ID1_3)
DECL_VAR(UA_Int32, uint32_t, __QD1_0)
DECL_VAR(UA_Int32, uint32_t, __QD1_1)
DECL_VAR(UA_Int32, uint32_t, __QD1_2)
DECL_VAR(UA_Int32, uint32_t, __QD1_3)
void __cleanup_1(void)
{
UA_Client_disconnect(client);
UA_Client_delete(client);
}
#define INIT_READ_VARIANT(ua_type, c_loc_name) \
UA_Variant_init(&c_loc_name##_variant);
#define INIT_WRITE_VARIANT(ua_type, ua_type_enum, c_loc_name) \
UA_Variant_setScalar(&c_loc_name##_variant, (ua_type*)c_loc_name, &UA_TYPES[ua_type_enum]);
int __init_1(int argc,char **argv)
{
UA_StatusCode retval;
client = UA_Client_new();
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
INIT_READ_VARIANT(UA_Int32, __ID1_0)
INIT_READ_VARIANT(UA_Int32, __ID1_1)
INIT_READ_VARIANT(UA_Int32, __ID1_2)
INIT_READ_VARIANT(UA_Int32, __ID1_3)
INIT_WRITE_VARIANT(UA_Int32, UA_TYPES_INT32, __QD1_0)
INIT_WRITE_VARIANT(UA_Int32, UA_TYPES_INT32, __QD1_1)
INIT_WRITE_VARIANT(UA_Int32, UA_TYPES_INT32, __QD1_2)
INIT_WRITE_VARIANT(UA_Int32, UA_TYPES_INT32, __QD1_3)
/* Connect to server */
retval = UA_Client_connect(client, "opc.tcp://192.168.0.44:4840");
if(retval != UA_STATUSCODE_GOOD) {
UA_Client_delete(client);
return EXIT_FAILURE;
}
}
#define READ_VALUE(ua_type, ua_type_enum, c_loc_name, ua_nodeid_type, ua_nsidx, ua_node_id) \
retval = UA_Client_readValueAttribute( \
client, ua_nodeid_type(ua_nsidx, ua_node_id), &c_loc_name##_variant); \
if(retval == UA_STATUSCODE_GOOD && UA_Variant_isScalar(&c_loc_name##_variant) && \
c_loc_name##_variant.type == &UA_TYPES[ua_type_enum]) { \
c_loc_name##_buf = *(ua_type*)c_loc_name##_variant.data; \
UA_Variant_clear(&c_loc_name##_variant); /* Unalloc requiered on each read ! */ \
}
void __retrieve_1(void)
{
UA_StatusCode retval;
READ_VALUE(UA_Int32, UA_TYPES_INT32, __ID1_0, UA_NODEID_STRING, 1, "i2c0.relay0")
READ_VALUE(UA_Int32, UA_TYPES_INT32, __ID1_1, UA_NODEID_STRING, 1, "i2c0.relay1")
READ_VALUE(UA_Int32, UA_TYPES_INT32, __ID1_2, UA_NODEID_STRING, 1, "i2c0.relay2")
READ_VALUE(UA_Int32, UA_TYPES_INT32, __ID1_3, UA_NODEID_STRING, 1, "i2c0.relay3")
}
#define WRITE_VALUE(ua_type, c_loc_name, ua_nodeid_type, ua_nsidx, ua_node_id) \
UA_Client_writeValueAttribute( \
client, ua_nodeid_type(ua_nsidx, ua_node_id), &c_loc_name##_variant);
void __publish_1(void)
{
WRITE_VALUE(UA_Int32, __QD1_0, UA_NODEID_STRING, 1, "i2c0.relay0")
WRITE_VALUE(UA_Int32, __QD1_1, UA_NODEID_STRING, 1, "i2c0.relay1")
WRITE_VALUE(UA_Int32, __QD1_2, UA_NODEID_STRING, 1, "i2c0.relay2")
WRITE_VALUE(UA_Int32, __QD1_3, UA_NODEID_STRING, 1, "i2c0.relay3")
}
TYPE
LOGLEVEL : (CRITICAL, WARNING, INFO, DEBUG) := INFO;
END_TYPE
FUNCTION_BLOCK LOGGER
VAR_INPUT
TRIG : BOOL;
MSG : STRING;
LEVEL : LOGLEVEL := INFO;
END_VAR
VAR
TRIG0 : BOOL;
END_VAR
IF TRIG AND NOT TRIG0 THEN
{{
LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len));
}}
END_IF;
TRIG0:=TRIG;
END_FUNCTION_BLOCK
FUNCTION_BLOCK python_eval
VAR_INPUT
TRIG : BOOL;
CODE : STRING;
END_VAR
VAR_OUTPUT
ACK : BOOL;
RESULT : STRING;
END_VAR
VAR
STATE : DWORD;
BUFFER : STRING;
PREBUFFER : STRING;
TRIGM1 : BOOL;
TRIGGED : BOOL;
END_VAR
{extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(0, data__);}
END_FUNCTION_BLOCK
FUNCTION_BLOCK python_poll
VAR_INPUT
TRIG : BOOL;
CODE : STRING;
END_VAR
VAR_OUTPUT
ACK : BOOL;
RESULT : STRING;
END_VAR
VAR
STATE : DWORD;
BUFFER : STRING;
PREBUFFER : STRING;
TRIGM1 : BOOL;
TRIGGED : BOOL;
END_VAR
{extern void __PythonEvalFB(int, PYTHON_EVAL*);__PythonEvalFB(1,(PYTHON_EVAL*)(void*)data__);}
END_FUNCTION_BLOCK
FUNCTION_BLOCK python_gear
VAR_INPUT
N : UINT;
TRIG : BOOL;
CODE : STRING;
END_VAR
VAR_OUTPUT
ACK : BOOL;
RESULT : STRING;
END_VAR
VAR
py_eval : python_eval;
COUNTER : UINT;
_TMP_ADD10_OUT : UINT;
_TMP_EQ13_OUT : BOOL;
_TMP_SEL15_OUT : UINT;
_TMP_AND7_OUT : BOOL;
END_VAR
_TMP_ADD10_OUT := ADD(COUNTER, 1);
_TMP_EQ13_OUT := EQ(N, _TMP_ADD10_OUT);
_TMP_SEL15_OUT := SEL(_TMP_EQ13_OUT, _TMP_ADD10_OUT, 0);
COUNTER := _TMP_SEL15_OUT;
_TMP_AND7_OUT := AND(_TMP_EQ13_OUT, TRIG);
py_eval(TRIG := _TMP_AND7_OUT, CODE := CODE);
ACK := py_eval.ACK;
RESULT := py_eval.RESULT;
END_FUNCTION_BLOCK
TYPE
HMI_REAL : REAL;
HMI_NODE : BOOL;
HMI_STRING : STRING;
HMI_BOOL : BOOL;
HMI_INT : INT;
END_TYPE
FUNCTION_BLOCK CounterST
VAR
Cnt0 : INT;
END_VAR
VAR_EXTERNAL
Relay0 : DINT;
Relay1 : DINT;
Relay2 : DINT;
Relay3 : DINT;
HMI_RELAY0 : HMI_INT;
HMI_RELAY1 : HMI_INT;
HMI_RELAY2 : HMI_INT;
HMI_RELAY3 : HMI_INT;
END_VAR
IF HMI_RELAY2 >= 1 THEN
Relay2:=1;
ELSE
Relay2:=0;
END_IF;
IF HMI_RELAY3 >= 1 THEN
Relay3:=1;
ELSE
Relay3:=0;
END_IF;
Cnt0 := Cnt0 + 1;
IF Cnt0 = 50 THEN
Relay0 := 1;
HMI_RELAY0:= 1;
Relay1 := 1;
HMI_RELAY1:= 1;
END_IF;
IF Cnt0 = 100 THEN
Relay0 := 0;
HMI_RELAY0:= 0;
Relay1 := 0;
HMI_RELAY1:= 0;
Cnt0 := 0;
END_IF;
END_FUNCTION_BLOCK
PROGRAM plc_prg
VAR
CounterST0 : CounterST;
END_VAR
CounterST0();
END_PROGRAM
CONFIGURATION config
VAR_GLOBAL
Relay0 AT %QD1.0 : DINT := 0;
Relay1 AT %QD1.1 : DINT := 0;
Relay2 AT %QD1.2 : DINT := 0;
Relay3 AT %QD1.3 : DINT := 0;
HMI_RELAY0 : HMI_INT := 0;
HMI_RELAY1 : HMI_INT := 0;
HMI_RELAY2 : HMI_INT := 0;
HMI_RELAY3 : HMI_INT := 0;
HMI_ROOT : HMI_NODE;
heartbeat : HMI_INT;
CURRENT_PAGE_0 : HMI_STRING;
END_VAR
RESOURCE resource1 ON PLC
TASK task0(INTERVAL := T#20ms,PRIORITY := 0);
PROGRAM instance0 WITH task0 : plc_prg;
END_RESOURCE
END_CONFIGURATION
This diff is collapsed.
This diff is collapsed.
/*
* Python Asynchronous execution code
*
* PLC put python commands in a fifo, respecting execution order
* with the help of C pragmas inserted in python_eval FB code
*
* Buffer content is read asynchronously, (from non real time part),
* commands are executed and result stored for later use by PLC.
*
* In this implementation, fifo is a list of pointer to python_eval
* function blocks structures. Some local variables have been added in
* python_eval interface. We use those local variables as buffer and state
* flags.
*
* */
#include "iec_types_all.h"
#include "POUS.h"
#include <string.h>
/* The fifo (fixed size, as number of FB is fixed) */
static PYTHON_EVAL* EvalFBs[1];
/* Producer and consumer cursors */
static int Current_PLC_EvalFB;
static int Current_Python_EvalFB;
/* A global IEC-Python gateway state, for use inside python_eval FBs*/
static int PythonState;
#define PYTHON_LOCKED_BY_PYTHON 0
#define PYTHON_LOCKED_BY_PLC 1
#define PYTHON_MUSTWAKEUP 2
#define PYTHON_FINISHED 4
/* Each python_eval FunctionBlock have it own state */
#define PYTHON_FB_FREE 0
#define PYTHON_FB_REQUESTED 1
#define PYTHON_FB_PROCESSING 2
#define PYTHON_FB_ANSWERED 3
int WaitPythonCommands(void);
void UnBlockPythonCommands(void);
int TryLockPython(void);
void UnLockPython(void);
void LockPython(void);
int __init_py_ext()
{
int i;
/* Initialize cursors */
Current_Python_EvalFB = 0;
Current_PLC_EvalFB = 0;
PythonState = PYTHON_LOCKED_BY_PYTHON;
for(i = 0; i < 1; i++)
EvalFBs[i] = NULL;
return 0;
}
void __cleanup_py_ext()
{
PythonState = PYTHON_FINISHED;
UnBlockPythonCommands();
}
void __retrieve_py_ext()
{
/* Check Python thread is not being
* modifying internal python_eval data */
PythonState = TryLockPython() ?
PYTHON_LOCKED_BY_PLC :
PYTHON_LOCKED_BY_PYTHON;
/* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON
* and python_eval will no do anything */
}
void __publish_py_ext()
{
if(PythonState & PYTHON_LOCKED_BY_PLC){
/* If runnig PLC did push something in the fifo*/
if(PythonState & PYTHON_MUSTWAKEUP){
/* WakeUp python thread */
UnBlockPythonCommands();
}
UnLockPython();
}
}
/**
* Called by the PLC, each time a python_eval
* FB instance is executed
*/
void __PythonEvalFB(int poll, PYTHON_EVAL* data__)
{
if(!__GET_VAR(data__->TRIG)){
/* ACK is False when TRIG is false, except a pulse when receiving result */
__SET_VAR(data__->, ACK,, 0);
}
/* detect rising edge on TRIG to trigger evaluation */
if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) ||
/* polling is equivalent to trig on value rather than on rising edge*/
(poll && __GET_VAR(data__->TRIG) )) &&
/* trig only if not already trigged */
__GET_VAR(data__->TRIGGED) == 0){
/* mark as trigged */
__SET_VAR(data__->, TRIGGED,, 1);
/* make a safe copy of the code */
__SET_VAR(data__->, PREBUFFER,, __GET_VAR(data__->CODE));
}
/* retain value for next rising edge detection */
__SET_VAR(data__->, TRIGM1,, __GET_VAR(data__->TRIG));
/* python thread is not in ? */
if( PythonState & PYTHON_LOCKED_BY_PLC){
/* if some answer are waiting, publish*/
if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){
/* Copy buffer content into result*/
__SET_VAR(data__->, RESULT,, __GET_VAR(data__->BUFFER));
/* signal result presence to PLC*/
__SET_VAR(data__->, ACK,, 1);
/* Mark as free */
__SET_VAR(data__->, STATE,, PYTHON_FB_FREE);
/* mark as not trigged */
if(!poll)
__SET_VAR(data__->, TRIGGED,, 0);
/*printf("__PythonEvalFB pop %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/
}else if(poll){
/* when in polling, no answer == ack down */
__SET_VAR(data__->, ACK,, 0);
}
/* got the order to act ?*/
if(__GET_VAR(data__->TRIGGED) == 1 &&
/* and not already being processed */
__GET_VAR(data__->STATE) == PYTHON_FB_FREE)
{
/* Enter the block in the fifo
* Don't have to check if fifo cell is free
* as fifo size == FB count, and a FB cannot
* be requested twice */
EvalFBs[Current_PLC_EvalFB] = data__;
/* copy into BUFFER local*/
__SET_VAR(data__->, BUFFER,, __GET_VAR(data__->PREBUFFER));
/* Set ACK pin to low so that we can set a rising edge on result */
if(!poll){
/* when not polling, a new answer imply reseting ack*/
__SET_VAR(data__->, ACK,, 0);
}else{
/* when in polling, acting reset trigger */
__SET_VAR(data__->, TRIGGED,, 0);
}
/* Mark FB busy */
__SET_VAR(data__->, STATE,, PYTHON_FB_REQUESTED);
/* Have to wakeup python thread in case he was asleep */
PythonState |= PYTHON_MUSTWAKEUP;
/*printf("__PythonEvalFB push %d - %*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/
/* Get a new line */
Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) % 1;
}
}
}
char* PythonIterator(char* result, void** id)
{
char* next_command;
PYTHON_EVAL* data__;
//printf("PythonIterator result %s\n", result);
/*emergency exit*/
if(PythonState & PYTHON_FINISHED) return NULL;
/* take python mutex to prevent changing PLC data while PLC running */
LockPython();
/* Get current FB */
data__ = EvalFBs[Current_Python_EvalFB];
if(data__ && /* may be null at first run */
__GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/
/* If result not None */
if(result){
/* Get results len */
__SET_VAR(data__->, BUFFER, .len, strlen(result));
/* prevent results overrun */
if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN)
{
__SET_VAR(data__->, BUFFER, .len, STR_MAX_LEN);
/* TODO : signal error */
}
/* Copy results to buffer */
strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len));
}else{
__SET_VAR(data__->, BUFFER, .len, 0);
}
/* remove block from fifo*/
EvalFBs[Current_Python_EvalFB] = NULL;
/* Mark block as answered */
__SET_VAR(data__->, STATE,, PYTHON_FB_ANSWERED);
/* Get a new line */
Current_Python_EvalFB = (Current_Python_EvalFB + 1) % 1;
//printf("PythonIterator ++ Current_Python_EvalFB %d\n", Current_Python_EvalFB);
}
/* while next slot is empty */
while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) ||
/* or doesn't contain command */
__GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED)
{
UnLockPython();
/* wait next FB to eval */
//printf("PythonIterator wait\n");
if(WaitPythonCommands()) return NULL;
/*emergency exit*/
if(PythonState & PYTHON_FINISHED) return NULL;
LockPython();
}
/* Mark block as processing */
__SET_VAR(data__->, STATE,, PYTHON_FB_PROCESSING);
//printf("PythonIterator\n");
/* make BUFFER a null terminated string */
__SET_VAR(data__->, BUFFER, .body[__GET_VAR(data__->BUFFER, .len)], 0);
/* next command is BUFFER */
next_command = (char*)__GET_VAR(data__->BUFFER, .body);
*id=data__;
/* free python mutex */
UnLockPython();
/* return the next command to eval */
return next_command;
}
/*******************************************/
/* FILE GENERATED BY iec2c */
/* Editing this file is not recommended... */
/*******************************************/
#include "iec_std_lib.h"
// RESOURCE RESOURCE1
extern unsigned long long common_ticktime__;
#include "accessor.h"
#include "POUS.h"
#include "config.h"
#include "POUS.c"
BOOL TASK0;
PLC_PRG RESOURCE1__INSTANCE0;
#define INSTANCE0 RESOURCE1__INSTANCE0
void RESOURCE1_init__(void) {
BOOL retain;
retain = 0;
TASK0 = __BOOL_LITERAL(FALSE);
PLC_PRG_init__(&INSTANCE0,retain);
}
void RESOURCE1_run__(unsigned long tick) {
TASK0 = !(tick % 1);
if (TASK0) {
PLC_PRG_body__(&INSTANCE0);
}
}
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of Beremiz
# Copyright (C) 2019: Edouard TISSERANT
# See COPYING file for copyrights details.
from __future__ import absolute_import
import errno
from threading import RLock, Timer
try:
from runtime.spawn_subprocess import Popen
except ImportError:
from subprocess import Popen
from twisted.web.server import Site
from twisted.web.resource import Resource
from twisted.internet import reactor
from twisted.web.static import File
from autobahn.twisted.websocket import WebSocketServerFactory, WebSocketServerProtocol
from autobahn.websocket.protocol import WebSocketProtocol
from autobahn.twisted.resource import WebSocketResource
max_svghmi_sessions = None
svghmi_watchdog = None
svghmi_wait = PLCBinary.svghmi_wait
svghmi_wait.restype = ctypes.c_int # error or 0
svghmi_wait.argtypes = []
svghmi_continue_collect = ctypes.c_int.in_dll(PLCBinary, "svghmi_continue_collect")
svghmi_send_collect = PLCBinary.svghmi_send_collect
svghmi_send_collect.restype = ctypes.c_int # error or 0
svghmi_send_collect.argtypes = [
ctypes.c_uint32, # index
ctypes.POINTER(ctypes.c_uint32), # size
ctypes.POINTER(ctypes.c_void_p)] # data ptr
svghmi_reset = PLCBinary.svghmi_reset
svghmi_reset.restype = ctypes.c_int # error or 0
svghmi_reset.argtypes = [
ctypes.c_uint32] # index
svghmi_recv_dispatch = PLCBinary.svghmi_recv_dispatch
svghmi_recv_dispatch.restype = ctypes.c_int # error or 0
svghmi_recv_dispatch.argtypes = [
ctypes.c_uint32, # index
ctypes.c_uint32, # size
ctypes.c_char_p] # data ptr
class HMISessionMgr(object):
def __init__(self):
self.multiclient_sessions = set()
self.watchdog_session = None
self.session_count = 0
self.lock = RLock()
self.indexes = set()
def next_index(self):
if self.indexes:
greatest = max(self.indexes)
holes = set(range(greatest)) - self.indexes
index = min(holes) if holes else greatest+1
else:
index = 0
self.indexes.add(index)
return index
def free_index(self, index):
self.indexes.remove(index)
def register(self, session):
global max_svghmi_sessions
with self.lock:
if session.is_watchdog_session:
# Creating a new watchdog session closes pre-existing one
if self.watchdog_session is not None:
self.unregister(self.watchdog_session)
else:
assert(self.session_count < max_svghmi_sessions)
self.session_count += 1
self.watchdog_session = session
else:
assert(self.session_count < max_svghmi_sessions)
self.multiclient_sessions.add(session)
self.session_count += 1
session.session_index = self.next_index()
def unregister(self, session):
with self.lock:
if session.is_watchdog_session :
if self.watchdog_session != session:
return
self.watchdog_session = None
else:
try:
self.multiclient_sessions.remove(session)
except KeyError:
return
self.free_index(session.session_index)
self.session_count -= 1
session.kill()
def close_all(self):
for session in self.iter_sessions():
self.unregister(session)
def iter_sessions(self):
with self.lock:
lst = list(self.multiclient_sessions)
if self.watchdog_session is not None:
lst = [self.watchdog_session]+lst
for nxt_session in lst:
yield nxt_session
svghmi_session_manager = HMISessionMgr()
class HMISession(object):
def __init__(self, protocol_instance):
self.protocol_instance = protocol_instance
self._session_index = None
self.closed = False
@property
def is_watchdog_session(self):
return self.protocol_instance.has_watchdog
@property
def session_index(self):
return self._session_index
@session_index.setter
def session_index(self, value):
self._session_index = value
def reset(self):
return svghmi_reset(self.session_index)
def close(self):
if self.closed: return
self.protocol_instance.sendClose(WebSocketProtocol.CLOSE_STATUS_CODE_NORMAL)
def notify_closed(self):
self.closed = True
def kill(self):
self.close()
self.reset()
def onMessage(self, msg):
# pass message to the C side recieve_message()
if self.closed: return
return svghmi_recv_dispatch(self.session_index, len(msg), msg)
def sendMessage(self, msg):
if self.closed: return
self.protocol_instance.sendMessage(msg, True)
return 0
class Watchdog(object):
def __init__(self, initial_timeout, interval, callback):
self._callback = callback
self.lock = RLock()
self.initial_timeout = initial_timeout
self.interval = interval
self.callback = callback
with self.lock:
self._start()
def _start(self, rearm=False):
duration = self.interval if rearm else self.initial_timeout
if duration:
self.timer = Timer(duration, self.trigger)
self.timer.start()
else:
self.timer = None
def _stop(self):
if self.timer is not None:
self.timer.cancel()
self.timer = None
def cancel(self):
with self.lock:
self._stop()
def feed(self, rearm=True):
with self.lock:
self._stop()
self._start(rearm)
def trigger(self):
self._callback()
# Don't repeat trigger periodically
# # wait for initial timeout on re-start
# self.feed(rearm=False)
class HMIProtocol(WebSocketServerProtocol):
def __init__(self, *args, **kwargs):
self._hmi_session = None
self.has_watchdog = False
WebSocketServerProtocol.__init__(self, *args, **kwargs)
def onConnect(self, request):
self.has_watchdog = request.params.get("mode", [None])[0] == "watchdog"
return WebSocketServerProtocol.onConnect(self, request)
def onOpen(self):
global svghmi_session_manager
assert(self._hmi_session is None)
_hmi_session = HMISession(self)
registered = svghmi_session_manager.register(_hmi_session)
self._hmi_session = _hmi_session
def onClose(self, wasClean, code, reason):
global svghmi_session_manager
if self._hmi_session is None : return
self._hmi_session.notify_closed()
svghmi_session_manager.unregister(self._hmi_session)
self._hmi_session = None
def onMessage(self, msg, isBinary):
global svghmi_watchdog
if self._hmi_session is None : return
result = self._hmi_session.onMessage(msg)
if result == 1 and self.has_watchdog: # was heartbeat
if svghmi_watchdog is not None:
svghmi_watchdog.feed()
class HMIWebSocketServerFactory(WebSocketServerFactory):
protocol = HMIProtocol
svghmi_servers = {}
svghmi_send_thread = None
# python's errno on windows seems to have no ENODATA
ENODATA = errno.ENODATA if hasattr(errno,"ENODATA") else None
def SendThreadProc():
global svghmi_session_manager
size = ctypes.c_uint32()
ptr = ctypes.c_void_p()
res = 0
while svghmi_continue_collect:
svghmi_wait()
for svghmi_session in svghmi_session_manager.iter_sessions():
res = svghmi_send_collect(
svghmi_session.session_index,
ctypes.byref(size), ctypes.byref(ptr))
if res == 0:
svghmi_session.sendMessage(
ctypes.string_at(ptr.value,size.value))
elif res == ENODATA:
# this happens when there is no data after wakeup
# because of hmi data refresh period longer than
# PLC common ticktime
pass
else:
# this happens when finishing
break
def AddPathToSVGHMIServers(path, factory, *args, **kwargs):
for k,v in svghmi_servers.iteritems():
svghmi_root, svghmi_listener, path_list = v
svghmi_root.putChild(path, factory(*args, **kwargs))
# Called by PLCObject at start
def _runtime_00_svghmi_start():
global svghmi_send_thread
# start a thread that call the C part of SVGHMI
svghmi_send_thread = Thread(target=SendThreadProc, name="SVGHMI Send")
svghmi_send_thread.start()
# Called by PLCObject at stop
def _runtime_00_svghmi_stop():
global svghmi_send_thread, svghmi_session
svghmi_session_manager.close_all()
# plc cleanup calls svghmi_(locstring)_cleanup and unlocks send thread
svghmi_send_thread.join()
svghmi_send_thread = None
class NoCacheFile(File):
def render_GET(self, request):
request.setHeader(b"Cache-Control", b"no-cache, no-store")
return File.render_GET(self, request)
render_HEAD = render_GET
# TODO : multiple watchdog (one for each svghmi instance)
def svghmi_0_watchdog_trigger():
Popen(['echo', 'Watchdog', 'for', 'svghmi_0', '!'])
max_svghmi_sessions = 16
def _runtime_0_svghmi_start():
global svghmi_watchdog, svghmi_servers
srv = svghmi_servers.get("localhost:8008", None)
if srv is not None:
svghmi_root, svghmi_listener, path_list = srv
if 'svghmi_0' in path_list:
raise Exception("SVGHMI svghmi_0: path svghmi_0 already used on localhost:8008")
else:
svghmi_root = Resource()
factory = HMIWebSocketServerFactory()
factory.setProtocolOptions(maxConnections=16)
svghmi_root.putChild("ws", WebSocketResource(factory))
svghmi_listener = reactor.listenTCP(8008, Site(svghmi_root), interface='localhost')
path_list = []
svghmi_servers["localhost:8008"] = (svghmi_root, svghmi_listener, path_list)
svghmi_root.putChild(
'svghmi_0',
NoCacheFile('svghmi_0.xhtml',
defaultType='application/xhtml+xml'))
path_list.append("svghmi_0")
Popen(['chromium', 'http://localhost:8008/svghmi_0#watchdog'])
if True:
if svghmi_watchdog is None:
svghmi_watchdog = Watchdog(
30,
5,
svghmi_0_watchdog_trigger)
else:
raise Exception("SVGHMI svghmi_0: only one watchdog allowed")
def _runtime_0_svghmi_stop():
global svghmi_watchdog, svghmi_servers
if svghmi_watchdog is not None:
svghmi_watchdog.cancel()
svghmi_watchdog = None
svghmi_root, svghmi_listener, path_list = svghmi_servers["localhost:8008"]
svghmi_root.delEntity('svghmi_0')
path_list.remove('svghmi_0')
if len(path_list)==0:
svghmi_root.delEntity("ws")
svghmi_listener.stopListening()
svghmi_servers.pop("localhost:8008")
pass # no command given
\ No newline at end of file
This diff is collapsed.
1e07dadd9175d71c49bda502ce3d71b8
\ No newline at end of file
This diff is collapsed.
<?xml version='1.0' encoding='utf-8'?>
<BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="1" Name="opcua_0"/>
<?xml version='1.0' encoding='utf-8'?>
<OPCUAClient xmlns:xsd="http://www.w3.org/2001/XMLSchema" Server_URI="opc.tcp://192.168.0.44:4840"/>
input,"LocalizedText(Encoding:3, Locale:en-US, Text:Relay 0)",1,str,i2c0.relay0,Int32,0
input,"LocalizedText(Encoding:3, Locale:en-US, Text:Relay 1)",1,str,i2c0.relay1,Int32,1
input,"LocalizedText(Encoding:3, Locale:en-US, Text:Relay 2)",1,str,i2c0.relay2,Int32,2
input,"LocalizedText(Encoding:3, Locale:en-US, Text:Relay 3)",1,str,i2c0.relay3,Int32,3
output,"LocalizedText(Encoding:3, Locale:en-US, Text:Relay 0)",1,str,i2c0.relay0,Int32,0
output,"LocalizedText(Encoding:3, Locale:en-US, Text:Relay 1)",1,str,i2c0.relay1,Int32,1
output,"LocalizedText(Encoding:3, Locale:en-US, Text:Relay 2)",1,str,i2c0.relay2,Int32,2
output,"LocalizedText(Encoding:3, Locale:en-US, Text:Relay 3)",1,str,i2c0.relay3,Int32,3
This diff is collapsed.
<?xml version='1.0' encoding='utf-8'?>
<BaseParams xmlns:xsd="http://www.w3.org/2001/XMLSchema" IEC_Channel="0" Name="svghmi_0"/>
<?xml version='1.0' encoding='utf-8'?>
<SVGHMI xmlns:xsd="http://www.w3.org/2001/XMLSchema" EnableWatchdog="true"/>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment