4diac-forte
Описание
исходный код программного ПЛК ForgeLogic
Релизы1
Все релизыЯзыки
- C++91,7%
- CMake4,2%
- C2,7%
- Shell0,8%
- HTML0,5%
- Остальные0,1%
Flogic OpenSoftPLC основан на Eclipse 4diac FORTE
Разработка управляющих приложений осуществляется в 4diac IDE,сборки для различных платформ с нашими доработками можно скачать тут:
4dac FORTE написан на языке C++ поэтому его легко портировать. 4diac FORTE может быть собран для различных архитектур и встраиваемых систем, таких как ПЛК.
Лицензия
Eclipse 4diac IDE и 4diac FORTE имеет лицензию EPL 2.0.
Contributing
We use contribution policy, which means we can only accept contributions under the terms of Eclipse Contributor Agreement.
Установка 4diac FORTE
Если не хочется самостоятельно собирать, файлы размещены тут
Предварительно установите инструмент для сборки cmake
sudo apt-get install build-essential git cmake g++ autoconf libtool libltdl-dev pkg-config rsync
Сборка Flogic POSIX для debian или ubuntu
Существует два варианта сборки среды исполнения:
- Сборка компилятором g++, установленным в текущую операционную систему (нативная сборка)
- Сборка кросс компилятором для x86 или arm64 (собираются статический forte и плагины без внешних зависимостей)
- Нативная сборка
- Скачивание и сборка библиотек (исходный код скачиваются и собираются в папке fl_ext_libs)
./prepare_libs.sh
- Сборка плагинов
./build_flogic_plugins.sh
- Сборка forte
./setup_flogic.sh
cd bin/posix
make
- Сборка кросс компилятором для x86
- Скачивание и сборка компилятора, библиотек (исходный код скачиваются и собираются в папке fl_ext_libs)
./prepare_libs.sh x86_64-linux-musl
- Сборка плагинов
./build_flogic_plugins.sh all x86_64-linux-musl
- Сборка forte
./setup_flogic.sh x86_64-linux-musl
cd bin/posix
make
- Сборка кросс компилятором для arm64
- Скачивание и сборка компилятора, библиотек (исходный код скачиваются и собираются в папке fl_ext_libs)
./prepare_libs.sh aarch64-linux-musl
- Сборка плагинов
./build_flogic_plugins.sh all aarch64-linux-musl
- Сборка forte
./setup_flogic.sh aarch64-linux-musl
cd bin/posix
make
- В результате должно получится следующее:
bin/posix/src/forte
bin/posix/opcua-client-plugin
bin/posix/modbus-master-plugin
bin/posix/opcua-server-plugin
bin/posix/modbus-slave-plugin
bin/posix/mqtt-plugin
bin/posix/fl-logger
bin/posix/fl-orchestrator
bin/posix/fl-ntp-client
bin/posix/fl-hash-util
Получившиеся файлы forte, opcua-client-plugin, modbus-master-plugin, opcua-server-plugin, modbus-slave-plugin, mqtt-plugin, fl-logger, fl-orchestrator, fl-ntp-client, fl-hash-util и plugins_cfg.xml необходимо пололжить в одну папку с названием 4diac-forte в директорию Home
-
Запустите среду разработки IDE, откройте любой из примеров
-
Откройте терминал и запустите среду исполнения FORTE с поддержкой плагин протоколов командой
./forte -ac plugins_cfg.xml
Сброс настроект CMake файлов
In case you ran CMake with invalid options it might help to reset the CMake state by deleting CMake intermediate files:
rm -Rf CMakeCache.txt CMakeFiles/
Использование дополнительных программных компонентов
Дополнительными компонентами являются:
- fl-hash-util - утилита для генерации хэша пароля
- fl-ntp-client - утилита для синхронизации системных часов с одним из источников точного времени (NTP серверов из списка)
- fl-logger - утилита для агрегирования логов, записываемых в UNIX-сокет
- fl-orchestrator - утилита, отвечаюзая за конфигурирование среды исполнения, управления жизненным циклом и обмен файлами с внешней средой. Примечание! Использование fl-ntp-client описано в файле README_extra.md
Использование fl-hash-util
Утилита генерирует хэш для пароля, переданного через аргументы исполняемого файла. Данная утилита необходима при заполнении конфигурации fl-orchestrator Пример использования:
user@my_pc:/etc/opt/flogic$ ./fl-hash-util top_secret --- Команда для генерации хэша
$2b$10$./XlG3QA0pxqLDN9F3T29e6QG7mxpIHhq6Cy.2ELVMEV8aiLuYche --- Результат выполнения команды
Описание fl-logger
Утилита для агрегации логов и их локального хранения и/или отправки на удалённый хост. Утилита осуществляет агрегацию логов, записываемых в UNIX сокет, который указывается при запуске.
Конфигурирование fl-logger
Пример конфигурации:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<logging>
<!-- Уровни фильтрации логов: DEBUG, INFO, WARNING, ERROR -->
<level>DEBUG</level>
</logging>
<!-- Настройка хранилища логов -->
<storage>
<!-- Локальная директория для хранения логов-->
<logPath>./testLogDir/</logPath>
<!-- Удалённое хост для сбора логов. -->
<!-- Передавать логи можно по TCP или UDP. Для смены протокола, измените префикс в конфигурационной строке-->
<remoteLogPath>tcp://127.0.0.1:9876</remoteLogPath>
<!-- Параметры локального хранилища логов-->
<maxFileSize>64KB</maxFileSize>
<maxDirSize>191KB</maxDirSize>
</storage>
</configuration>
Текущую конфигурацию можно сохранить в файл fl-logger-config.xml и воспользоваться ей.
Запуск fl-logger
Для запуска fl-ntp-client необходимо выполнить команду:
Аргументы запуска:
- Путь к конфигурационному файлу
- Путь к UNIX-сокету, из которого будут вычитываться сообщения
- Размер кольцевого буфера Внимание! В текущей реализации для агреции логов необходимо,чтобы был установлен syslog-ng, все исполняемые файлы запускались fl-orchestrator и fl-orchestrator был запущен в виде systemd сервиса.
Установка и настройка syslog-ng
Для установки необходимо выполнить команду:
Для настройки сервиса необходимо выполнить действия:
- Открыть конфигурацию сервиса syslog-ng в любом текстовом редакторе. (По умолчанию конфигурация находится тут /etc/syslog-ng/syslog-ng.conf)
- Добавить строки:
filter f_syslog3_and_modules {
filter(f_syslog3) and not filter(f_modules);
};
- Заменить строку
наfilter(f_syslog3)log { source(s_src); filter(f_syslog3_and_modules); destination(d_syslog); };
Содержимое файла syslog-ng.conf после изменений
@version: 3.38
@include "scl.conf"
# Syslog-ng configuration file, compatible with default Debian syslogd
# installation.
# First, set some global options.
options { chain_hostnames(off); flush_lines(0); use_dns(no); use_fqdn(no);
dns_cache(no); owner("root"); group("adm"); perm(0640);
stats_freq(0); bad_hostname("^gconfd$");
};
########################
# Sources
########################
# This is the default behavior of sysklogd package
# Logs may come from unix stream, but not from another machine.
#
source s_src {
system();
internal();
};
# If you wish to get logs from remote machine you should uncomment
# this and comment the above source line.
#
#source s_net { tcp(ip(127.0.0.1) port(1000)); };
########################
# Destinations
########################
# First some standard logfile
#
destination d_auth { file("/var/log/auth.log"); };
destination d_cron { file("/var/log/cron.log"); };
destination d_daemon { file("/var/log/daemon.log"); };
destination d_kern { file("/var/log/kern.log"); };
destination d_lpr { file("/var/log/lpr.log"); };
destination d_mail { file("/var/log/mail.log"); };
destination d_syslog { file("/var/log/syslog"); };
destination d_user { file("/var/log/user.log"); };
destination d_uucp { file("/var/log/uucp.log"); };
# This files are the log come from the mail subsystem.
#
destination d_mailinfo { file("/var/log/mail.info"); };
destination d_mailwarn { file("/var/log/mail.warn"); };
destination d_mailerr { file("/var/log/mail.err"); };
# Logging for INN news system
#
destination d_newscrit { file("/var/log/news/news.crit"); };
destination d_newserr { file("/var/log/news/news.err"); };
destination d_newsnotice { file("/var/log/news/news.notice"); };
# Some 'catch-all' logfiles.
#
destination d_debug { file("/var/log/debug"); };
destination d_error { file("/var/log/error"); };
destination d_messages { file("/var/log/messages"); };
# The root's console.
#
destination d_console { usertty("root"); };
# Virtual console.
#
destination d_console_all { getvirtconsole(); };
# The named pipe /dev/xconsole is for the nsole' utility. To use it,
# you must invoke nsole' with the -file' option:
#
# $ xconsole -file /dev/xconsole [...]
#
destination d_xconsole { pipe("/dev/xconsole"); };
# Send the messages to an other host
#
#destination d_net { tcp("127.0.0.1" port(1000) log_fifo_size(1000)); };
# Debian only
destination d_ppp { file("/var/log/ppp.log"); };
########################
# Filters
########################
# Here's come the filter options. With this rules, we can set which
# message go where.
filter f_dbg { level(debug); };
filter f_info { level(info); };
filter f_notice { level(notice); };
filter f_warn { level(warn); };
filter f_err { level(err); };
filter f_crit { level(crit .. emerg); };
filter f_debug { level(debug) and not facility(auth, authpriv, news, mail); };
filter f_error { level(err .. emerg) ; };
filter f_messages { level(info,notice,warn) and
not facility(auth,authpriv,cron,daemon,mail,news); };
filter f_auth { facility(auth, authpriv) and not filter(f_dbg); };
filter f_cron { facility(cron) and not filter(f_dbg); };
filter f_daemon { facility(daemon) and not filter(f_dbg); };
filter f_kern { facility(kern) and not filter(f_dbg); };
filter f_lpr { facility(lpr) and not filter(f_dbg); };
filter f_local { facility(local0, local1, local3, local4, local5,
local6, local7) and not filter(f_dbg); };
filter f_mail { facility(mail) and not filter(f_dbg); };
filter f_news { facility(news) and not filter(f_dbg); };
filter f_syslog3 { not facility(auth, authpriv, mail) and not filter(f_dbg); };
filter f_user { facility(user) and not filter(f_dbg); };
filter f_uucp { facility(uucp) and not filter(f_dbg); };
filter f_cnews { level(notice, err, crit) and facility(news); };
filter f_cother { level(debug, info, notice, warn) or facility(daemon, mail); };
filter f_ppp { facility(local2) and not filter(f_dbg); };
filter f_console { level(warn .. emerg); };
filter f_syslog3_and_modules {
filter(f_syslog3) and not filter(f_modules);
};
########################
# Log paths
########################
log { source(s_src); filter(f_auth); destination(d_auth); };
log { source(s_src); filter(f_cron); destination(d_cron); };
log { source(s_src); filter(f_daemon); destination(d_daemon); };
log { source(s_src); filter(f_kern); destination(d_kern); };
log { source(s_src); filter(f_lpr); destination(d_lpr); };
log { source(s_src); filter(f_syslog3_and_modules); destination(d_syslog); };
log { source(s_src); filter(f_user); destination(d_user); };
log { source(s_src); filter(f_uucp); destination(d_uucp); };
log { source(s_src); filter(f_mail); destination(d_mail); };
#log { source(s_src); filter(f_mail); filter(f_info); destination(d_mailinfo); };
#log { source(s_src); filter(f_mail); filter(f_warn); destination(d_mailwarn); };
#log { source(s_src); filter(f_mail); filter(f_err); destination(d_mailerr); };
log { source(s_src); filter(f_news); filter(f_crit); destination(d_newscrit); };
log { source(s_src); filter(f_news); filter(f_err); destination(d_newserr); };
log { source(s_src); filter(f_news); filter(f_notice); destination(d_newsnotice); };
#log { source(s_src); filter(f_cnews); destination(d_console_all); };
#log { source(s_src); filter(f_cother); destination(d_console_all); };
#log { source(s_src); filter(f_ppp); destination(d_ppp); };
log { source(s_src); filter(f_debug); destination(d_debug); };
log { source(s_src); filter(f_error); destination(d_error); };
log { source(s_src); filter(f_messages); destination(d_messages); };
log { source(s_src); filter(f_console); destination(d_console_all); destination(d_xconsole); };
log { source(s_src); filter(f_crit); destination(d_console); };
# All messages send to a remote site
#
#log { source(s_src); destination(d_net); };
###
# Include all config files in /etc/syslog-ng/conf.d/
###
@include "/etc/syslog-ng/conf.d/*.conf"
- Создать конфигурационный файл логера fl-loger.conf в директории /etc/syslog-ng/conf.d/ с следующим содержанием:
filter f_modules {
program("fl-orchestrator");
};
destination d_logger {
unix-dgram("/run/logger.sock"
log_fifo_size(1000)
time-reopen(10)
);
};
log {
source(s_src);
filter(f_modules);
if (match("CRITICAL" value("MESSAGE")) or match("critical" value("MESSAGE"))) {
rewrite { set-severity(crit); set-facility(local0); };
}
elif (match("ERROR" value("MESSAGE")) or match("error" value("MESSAGE"))) {
rewrite { set-severity(err); set-facility(local0); };
}
elif (match("WARNING" value("MESSAGE")) or match("warn" value("MESSAGE"))) {
rewrite { set-severity(warning); set-facility(local0); };
}
elif (match("INFO" value("MESSAGE")) or match("info" value("MESSAGE"))) {
rewrite { set-severity(info); set-facility(local0); };
}
elif (match("DEBUG" value("MESSAGE")) or match("debug" value("MESSAGE"))) {
rewrite { set-severity(debug); set-facility(local0); };
}
else{
rewrite { set-severity(info); set-facility(local0); };
};
destination(d_logger);
};
- Перезапустить сервис:
sudo systemctl restart syslog-ng
Запуск среды исполнения FORTE с помощью fl-orchestrator
fl-orchestrator - программный компонент, отвечающий за конфигурирование среды исполнения, управление жизненным циклом, обмен файлами с внешнейней средой. Для его работы необходимо:
- Собрать исполняемые файлы в одной директории, кроме fl-orchestrator
- Создать директории для хранения исполняемой конфигурации: conf, conf/a, conf/b
- Создать директории для обмена файлами: transfer, project
- Cоздать конфигурационных файл оркестратора orchestrator.xml c содержимым:
<?xml version="1.0"encoding="UTF-8"?>
<Configuration>
<FLTransfer>
<Port>8085</Port>
<DirA><Абсолютный путь до директории из п.2 conf>/a</DirA>
<DirB><Абсолютный путь до директории из п.2 conf>/b</DirB>
<TransferDir><Абсолютный путь до директории из п.3>/transfer</TransferDir>
<ActiveDirLink><Заменить на абсолютный путь до директории из п.2 conf>/active</ActiveDirLink>
<ConfigArchiveName>config.zip</ConfigArchiveName>
<ConfigDirArchiveName>.config.zip</ConfigDirArchiveName>
<ProjectStoreDir>Абсолютный путь до директории из п.3 project</ProjectStoreDir>
<ProjectArchiveName>project.zip</ProjectArchiveName>
<ProjectDirArchiveName>project.zip</ProjectDirArchiveName>
<UploadTimeoutMs>30000</UploadTimeoutMs>
<Auth>
<Username>Ввести желаемое имя пользователя</Username>
<Password>Сгенерировать с помощью fl-hash-util и вставить</Password>
</Auth>
</FLTransfer>
<RetainStoragePath><Заменить на абсолютный путь до директории из п.2 conf>/active/.retain_base</RetainStoragePath>
<BinaryDirPath>Абсолютный путь до директории из п.1 </BinaryDirPath>
<FortePluginConfigPath><Заменить на абсолютный путь до директории из п.2 conf>/active/plugin.xml</FortePluginConfigPath>
<ForteGenPluginConfig>true</ForteGenPluginConfig>
<StartupConfigName>startup.xml</StartupConfigName>
<WaitKillPidTimeMs>5000</WaitKillPidTimeMs>
<RestartPluginsOnForteDrop>true</RestartPluginsOnForteDrop>
<PluginBinaries>
<Plugin Id="fllogger"><Binary>fl-logger</Binary><StartArgs><Заменить на абсолютный путь до директории из п.2 conf>/active/fl-logger-config.xml</StartArgs></Plugin>
<Plugin Id="MBUS"><Binary>modbus-master-plugin</Binary></Plugin>
<Plugin Id="MSLAVE"><Binary>modbus-slave-plugin</Binary><Timeout>5s</Timeout></Plugin>
<Plugin Id="flmqtt"><Binary>mqtt-plugin</Binary><Timeout>100ms</Timeout></Plugin>
<Plugin Id="OPCUAC"><Binary>opcua-client-plugin</Binary></Plugin>
<Plugin Id="OPCUAS"><Binary>opcua-server-plugin</Binary></Plugin>
<Forte><Binary>forte</Binary></Forte>
</PluginBinaries>
<PluginDependencies>
<Plugin Id="OPCUAS"><File>config.json</File></Plugin>
<Plugin Id="OPCUAS"><File>server_config.json5</File></Plugin>
<Plugin Id="OPCUAS"><File>PKI/</File></Plugin>
<Plugin Id="flmqtt"><File>fl-mqtt-config.xml</File></Plugin>
</PluginDependencies>
</Configuration>
- В файле orchestrator.xml заменить пути, отмеченные вставками на русском языке.
- Создать стартовую конфигурацию startup.xml в директории conf/a с содержимым:
<?xml version="1.0"encoding="UTF-8"?>
<Configuration>
<PluginRestartDelayMs>500</PluginRestartDelayMs>
<PluginHealthCheckIntervalMs>300</PluginHealthCheckIntervalMs>
<LifeCycle>
<Startup>
<StartGroup>
<Plugin Id="fllogger" StartPolicy="NoWait" StartTimeoutMs="2000"/>
</StartGroup>
<StartGroup>
<Plugin Id="MBUS"
StartPolicy="WaitStart" StartTimeoutMs="5000" RetryAttempts="3"
StopOnStartPolicy="SigHupWaitKill" ForceStopOnStartTimeoutMs="500" />
<Plugin Id="MSLAVE" StartPolicy="WaitStart" StartTimeoutMs="5000" RetryAttempts="3"/>
</StartGroup>
<StartGroup NextGroupDelayMs="300">
<Plugin Id="flmqtt" StartPolicy="WaitStart" StartTimeoutMs="2000"/>
<Plugin Id="OPCUAC" StartPolicy="WaitStart" StartTimeoutMs="2000"/>
</StartGroup>
<Forte>
<Retain><Заменить на абсолютный путь до директории из п.2 conf>/active/.retain_base</Retain>
<FBoot>fboot.xml</FBoot>
</Forte>
</Startup>
<Stop>
<!--Forte has predefined StopPolicy="SigHupWaitKill" -->
<Forte ForceStopTimeoutMs="15000" />
<StopGroup>
<Plugin Id="MBUS" ForceStopTimeoutMs="3000" StopPolicy="SigHupWaitKill"/>
<Plugin Id="MSLAVE" ForceStopTimeoutMs="3000" StopPolicy="SigHupWaitKill"/>
<Plugin Id="flmqtt" StopPolicy="SigKillPidWait"/>
<Plugin Id="OPCUAC" ForceStopTimeoutMs="3000" StopPolicy="SigHupWaitKill"/>
</StopGroup>
<StopGroup>
<Plugin Id="fllogger" ForceStopTimeoutMs="3000" StopPolicy="SigHupWaitKill"/>
</StopGroup>
</Stop>
</LifeCycle>
</Configuration>
- Создать systemd файл для запуска оркестратора в /etc/systemd/system/ с именеем fl-orchestrator.service и содержимым:
[Unit]
Description=ForgeLogic orchestrator
[Service]
User=root
WorkingDirectory=<Заменить на путь к директории с fl-orchestrator>
ExecStart=<Заменить на путь к директории с fl-orchestrator>/fl-orchestrator <Абсолютный путь к файлу orchestrator.xml>
Restart=always
[Install]
WantedBy=multi-user.target
- Для запуска сервиса выполнить команды:
sudo systemctl daemon-reload
sudo systemctl enable fl-orchestrator.service
sudo systemctl start fl-orchestrator.service
ВНИМАНИЕ! Для корректного запуска и работы с fl-orchestrator дерево рабочей директории должно выглядеть следующим образом:
.
├── conf
│ ├── a
│ │ ├── fl-mqtt-config.xml
│ │ ├── retain_cfg.xml
│ │ └── startup.xml
│ ├── active -> /etc/opt/flogic/conf/a
│ └── b
├── config.json
├── ecal.ini
├── fl-hash-util
├── fl-logger
├── fl-logger-config.xml
├── fl-mqtt-config.xml
├── fl-ntp-client
├── fl-ntp-config.xml
├── fl-orchestrator
├── forte
├── logs
├── modbus-master-plugin
├── modbus-slave-plugin
├── mqtt-plugin
├── opcua-client-plugin
├── opcua-server-plugin
├── orchestrator.xml
├── plugins_cfg.xml
├── project
├── server_config.json5
└── transfer