1. Общий шаблон обработки событий
# Программа демонстрирует общий шаблон обработки событий и часть возможностей языка программирования EXT.
# При отпускании кнопки вскрытия корпуса контроллера (тампера) будет происходить переключение реле 1.
proc main() # основная подпрограмма (точка входа)
{
var e = $get_event_id(); # получение обрабатываемого события
if e == $EVT_INIT { # обработка инициализации
$set_event_mask($EM_SYSTEM); # разрешение системных событий
} else if e == $EVT_CASE_OPEN { # обработка вскрытия корпуса контроллера
toggle(1); # переключение реле 1
}
}
proc toggle(n) # подпрограмма управления выходом
{ # n - номер выхода
var s = $get_output_state(n); # получение текущего состояния
$set_output_state(n, !s); # установка инверсного состояния
}
2. Одновременный контроль и управление по одному входу
# Пример программы для одновременного контроля и управления по одному входу.
#
# Управление осуществляется встроенной логикой входа.
#
# В примере предполагается, что ко входу 1 подключен термодатчик RTD.
# Необходимые настройки входа 1:
# - тип входа: RTD-03 или RTD-04
# - тревожный диапазон: низкий гистерезисный (заданы необходимые границы температуры для управления)
# - круглосуточный контроль: включен
# - все реле/выходы управляются: напрямую входом
# - задана реакция реле/выходов на изменение состояния входа
#
# Контроль осуществляется программируемой логикой.
#
# Диапазон тревожного оповещения задается константой DELTA_T в градусах относительно нижней и верхней границы управления (см. настройки входа 1).
# Для оповещения о выходе температуры за тревожные границы должно быть настроено соединение:
# - задан номер телефона
# - задан пароль (зависит от типа оповещения)
# - разрешен необходимый тип оповещения для In1
const INPUT_N = 1; # номер входа с термодатчиком
const EVT_ACTIVE = $EVT_INPUT1_ACTIVE; # идентификатор активного состояния входа
const EVT_PASSIVE = $EVT_INPUT1_PASSIVE; # идентификатор пассивного состояния входа
const POLL_PERIOD = 10; # период опроса входа (1 единица = 100 мс)
const FRACT = 8; # размер дробной части fixed-point в битах
const DELTA_T = 5 << FRACT; # диапазон тревожного оповещения в градусах (fixed-point)
const ST_NONE = -1;
const ST_PASSIVE = 0;
const ST_ACTIVE = 1;
var t, state = ST_NONE, self_event;
proc main()
{
var e = $get_event_id();
if e == $EVT_INIT {
init();
} else if e == $EVT_TIMER1 {
poll();
} else if e == EVT_ACTIVE {
cancel();
} else if e == EVT_PASSIVE {
cancel();
}
}
proc init()
{
$set_event_mask($EM_INPUT);
$set_timer(1, POLL_PERIOD);
t = get_temp();
}
proc poll()
{
var t_low = $get_sensor_low_limit(INPUT_N, FRACT) - DELTA_T;
var t_high = $get_sensor_high_limit(INPUT_N, FRACT) + DELTA_T;
t = get_temp();
if t <= t_low && state != ST_ACTIVE {
raise(EVT_ACTIVE);
state = ST_ACTIVE;
} else if t >= t_high && state != ST_ACTIVE {
raise(EVT_ACTIVE);
state = ST_ACTIVE;
} else if t > t_low && t < t_high && state != ST_PASSIVE {
raise(EVT_PASSIVE);
state = ST_PASSIVE;
}
}
fun get_temp()
{
return $get_sensor_value(INPUT_N, FRACT);
}
proc raise(e)
{
$raise_event(e);
self_event = 1;
}
proc cancel()
{
if self_event {
self_event = 0;
} else {
$cancel_event();
}
}
3. Контроль входа с двумя активными уровнями
# Пример программы для контроля входа с двумя активными уровнями.
# В примере предполагается, что ко входу 1 подключен термодатчик RTD.
# Необходимые настройки входа 1:
# - тип входа: RTD-03 или RTD-04
# - круглосуточный контроль: включен
# Уровни задаются константами T1 и T2 в градусах:
# t < T1 - пассивный
# T1 <= t < T2 - активный 1
# t >= T2 - активный 2
#
# Для оповещения о выходе температуры за тревожные границы должно быть настроено соединение:
# - задан номер телефона
# - задан пароль (зависит от типа оповещения)
# - разрешен необходимый тип оповещения для In1
const INPUT_N = 1; # номер входа с термодатчиком
const EVT_ACTIVE = $EVT_INPUT1_ACTIVE; # идентификатор активного состояния входа
const EVT_PASSIVE = $EVT_INPUT1_PASSIVE; # идентификатор пассивного состояния входа
const POLL_PERIOD = 10; # период опроса входа (1 единица = 100 мс)
const FRACT = 8; # размер дробной части fixed-point в битах
const T1 = 20 << FRACT; # первая граница в градусах (fixed-point)
const T2 = 30 << FRACT; # вторая граница в градусах (fixed-point)
const ST_NONE = -1;
const ST_PASSIVE = 0;
const ST_ACTIVE1 = 1;
const ST_ACTIVE2 = 2;
var t, state = ST_NONE, self_event;
proc main()
{
var e = $get_event_id();
if e == $EVT_INIT {
init();
} else if e == $EVT_TIMER1 {
poll();
} else if e == EVT_ACTIVE {
cancel();
} else if e == EVT_PASSIVE {
cancel();
}
}
proc init()
{
$set_event_mask($EM_INPUT);
$set_timer(1, POLL_PERIOD);
t = get_temp();
}
proc poll()
{
t = get_temp();
if t >= T1 && t < T2 && state != ST_ACTIVE1 {
raise(EVT_ACTIVE);
state = ST_ACTIVE1;
} else if t >= T2 && state != ST_ACTIVE2 {
raise(EVT_ACTIVE);
state = ST_ACTIVE2;
} else if t < T1 && state != ST_PASSIVE {
raise(EVT_PASSIVE);
state = ST_PASSIVE;
}
}
fun get_temp()
{
return $get_sensor_value(INPUT_N, FRACT);
}
proc raise(e)
{
$raise_event(e);
self_event = 1;
}
proc cancel()
{
if self_event {
self_event = 0;
} else {
$cancel_event();
}
}
4. Отмена оповещения при изменении состояния входов на время меньше заданного
# Пример программы для отмены оповещения при изменении состояния входов на время меньше заданного.
# Время задается константой INPUT_DELAY и может быть порядка минут или часов.
const POLL_PERIOD = 600; # период опроса входов (600 * 100 мс = 60 с = 1 мин)
const INPUT_DELAY = 120; # длительность задержки оповещения (120 мин = 2 ч)
const FALSE = 0;
const TRUE = 1;
var inputs_state;
var self_events;
var input1_time;
var input2_time;
var input3_time;
var input4_time;
var input5_time;
var input6_time;
var input7_time;
var input8_time;
proc main()
{
var e = $get_event_id();
if e == $EVT_INIT {
init();
} else if e == $EVT_TIMER1 {
poll();
} else if e >= $EVT_INPUT1_ACTIVE && e <= $EVT_INPUT8_ACTIVE {
var n = e - $EVT_INPUT1_ACTIVE + 1;
handle_input_event(n, 1);
} else if e >= $EVT_INPUT1_PASSIVE && e <= $EVT_INPUT8_PASSIVE {
var n = e - $EVT_INPUT1_PASSIVE + 1;
handle_input_event(n, -1);
}
}
proc init()
{
$set_event_mask($EM_INPUT);
$set_timer(1, POLL_PERIOD);
init_inputs();
poll();
}
proc init_inputs()
{
var n = 1;
while n <= 8 {
var s = $get_input_state(n);
var t;
if s {
t = INPUT_DELAY;
} else {
t = -INPUT_DELAY;
}
set_input_state(n, !s);
set_input_time(n, t);
n = n + 1;
}
}
proc handle_input_event(n, t)
{
if is_self_event(n) {
set_self_event(n, FALSE);
} else {
set_input_time(n, t);
$cancel_event();
}
}
proc set_input_time(n, t)
{
if n == 1 {
input1_time = t;
} else if n == 2 {
input2_time = t;
} else if n == 3 {
input3_time = t;
} else if n == 4 {
input4_time = t;
} else if n == 5 {
input5_time = t;
} else if n == 6 {
input6_time = t;
} else if n == 7 {
input7_time = t;
} else if n == 8 {
input8_time = t;
}
}
proc poll()
{
input1_time = handle_input_time(1, input1_time);
input2_time = handle_input_time(2, input2_time);
input3_time = handle_input_time(3, input3_time);
input4_time = handle_input_time(4, input4_time);
input5_time = handle_input_time(5, input5_time);
input6_time = handle_input_time(6, input6_time);
input7_time = handle_input_time(7, input7_time);
input8_time = handle_input_time(8, input8_time);
}
fun handle_input_time(n, t)
{
if abs(t) <= INPUT_DELAY {
t = tick(t);
var s = t > 0;
if abs(t) == INPUT_DELAY + 1 && is_state_switch(n, s) {
raise(n, s);
}
}
return t;
}
fun abs(x)
{
if x < 0 {
return -x;
} else {
return x;
}
}
fun tick(t)
{
if t < 0 {
return t - 1;
} else {
return t + 1;
}
}
fun is_state_switch(n, s)
{
return get_input_state(n) != s;
}
proc raise(n, s)
{
var e;
if s {
e = $EVT_INPUT1_ACTIVE;
set_input_state(n, TRUE);
} else {
e = $EVT_INPUT1_PASSIVE;
set_input_state(n, FALSE);
}
$raise_event(e + n - 1);
set_self_event(n, TRUE);
}
fun mask(n)
{
return 1 << (n - 1);
}
proc set_input_state(n, s)
{
if s {
inputs_state = inputs_state | mask(n);
} else {
inputs_state = inputs_state & ~mask(n);
}
}
fun get_input_state(n)
{
return (inputs_state & mask(n)) != 0;
}
proc set_self_event(n, s)
{
if s {
self_events = self_events | mask(n);
} else {
self_events = self_events & ~mask(n);
}
}
fun is_self_event(n)
{
return (self_events & mask(n)) != 0;
}