Попробуем сделать сегодня что-нибудь полезное. Думаю, по заголовку многие уже поняли, что именно. А если нет - напомню про существование такого интерфейса под названием RS/TIA/EIA-485. Несмотря на возраст, до сих пор ставится в массу датчиков, приборов и прочего оборудования. И, судя по всему, ставиться будет ещё долго. В качестве протокола верхнего уровня здесь чаще всего используют MODBUS-RTU, несмотря на его недостатки и ограничения. Более подробно об этом можно почитать, например, здесь. В попытке осовременить этого динозавра протокол была придумана его модификация MODBUS TCP/IP, в которой, как не сложно догадаться, типовые MODBUS-пакеты пропихиваются по TCP/IP сетям. Это позволило скрестить ежа с ужом подключить к современным сетям всю эту гору оборудования, не переделывая её начинку. И организовать доступ к данным хоть на край света по удалёнке через Internet! Достаточно взять специальную коробку-конвертер и немного модифицировать софт верхнего уровня.
Что же это за коробка такая? С одной стороны у неё ethernet, wi-fi или даже какой-нибудь 5G модем. А с другой - старые добрые порты RS-232, RS-422, RS-485.
Путём нехитрых преобразований коробка перебрасывает MODBUS-пакеты туда-обратно. Делают их сейчас все, кому не лень! Начиная от брендов, вроде MOXA или ICP-DAS до неведомых кетайцев вроде HI-FLYING, USR IOT, тысячи их, разной степеникривизны качества. Внутри такой коробки, как правило, прячется типичная SoC для интернетовских точек доступа, несколько драйверов интерфейса, да какая-нибудь обвязка по питанию.
А раз так, быть может, и на основе неспециализированного компьютера можно поднять такой конвертер? Например, на...Репке?
И да, это возможно! Благодаря проекту MBUSD от Юрия Антоновича. Как несложно понять, это сервер под линуксовые (главным образом) машины. Несмотря на то, что проект, вроде как, ещё не выбрался из альфа-стадии, он вполне стабильный и универсальный. Достаточно, чтобы комп имел на борту необходимые порты (либо дооснастить его ими).
И универсальность его заключается, в том числе, вот в каком моменте:
Напомним, что RS-485 это полудуплексный интерфейс. В каждый момент времени он может либо принимать, либо передавать. И для чипов драйверов важно осуществлять своевременную коммутацию режима работы! Как же эту проблему решить?
Готовый вариант - взять кетайский переходник USB-RS485, вроде такого
В нём схема коммутации уже встроена, той или иной степени надёжности. Пользователю в линуксах, после того, как её подхватят драйвера, достаточно использовать появившийся порт вроде /dev/ttyUSB0
Другой вариант - аппаратная схема автоматической коммутации. Бывают готовые специальные чипы драйверы, которые сами выбирают, в каком режиме им работать (например, MAX13487), бывают отдельные решения (например, вот эта схема хорошо работает).
Но MBUSD в состоянии и сам выполнять коммутацию приём-передача, что в теории, наверно, должно работать стабильнее и более предсказуемо. Для чего автор заложил в него три метода:
В первом случае он может использовать возможности линукс-драйвера под какие-то аппаратные реализации RS-485 для встраиваемых систем, наверно...в жизни такие мне не попадались.
Может он для коммутации задействовать вывод RTS, который присутствует в стандартном RS-232. Либо он может быть выведен в миникомпьютерах на пины для подключения шилд. Но есть ли у Репы такой выход? Смотрим на схему и убеждаемся, что ни в одной из "распиновок" его нет.
Но не беда, есть ведь ещё и третий метод: MBUSD умеет дёргать GPIO-выходы через линксовую SysFS. В интернетах много бурлений о том, что, мол, SysFS - это жуткое легаси, хватит на нём сидеть, нормальные проггеры пользуют UAPI. Что тут скажешь, MODBUS сам по себе ещё то замшелое легаси. Для нас главное, что "Repka-OS" его поддерживает нормально. А также то, что на гребёнку выведены сигналы UART, хотя бы один GPIO и питание.
Именно по этому пути я и решил пойти, сделав свою "шилду". Здесь можно посмотреть схему данной поделки. Делал на том, что было под рукой, наверняка вы возьмёте другую элементную базу. По крайней мере, имеется гальваническая развязка и базовая защита выхода от статики. Подключаем плату к верхней части гребёнки (контакты 1...10) через шлейф. Разъём XP2 я сделал для себя, чтобы подключать ранее сделанную "шилду" с часами DS3232. XP3 и XP4 выводят питание, на всякий случай (например, к XP3 я подключаю корпусной вентилятор). Вот как это всё сейча выглядит:
Да, надо будет хоть какую-нибудь коробочку под плату пристроить...
А теперь установим MBUSD. В репозитарии его похоже что нет, так что компиляем из исходников:
устанавливаем CMAKE, если у вас его вдруг ещё нет
Дальше просто следуйте Installation instructions с Гитхаб. Установим, но запускать пока не будем.
Всё скомпилировалось быстро и в целом без ошибок. На всякий случай уточню, что у меня сейчас стоит ядро 5.19.16.
Если будете задействовать UART0, как у меня, то следует также отключить вывод отладочных сообщений в него: здесь смотрим пункт Отключение / включение отладочного терминала на UART0.
Настроим конфиг-файл. Для этого я в каталоге /etc/mbusd беру файл mbusd.conf.example и копирую его с именем mbusd-ttyS0.conf Как несложно заметить, его имя содержит название UART-а, который я собираюсь задействовать для своего переходника. Редактирую его следующим образом:
Обратите внимание на строку # Serial port speed, где задаётся скорость интерфейса.
Кроме того, задаём режим работы с SysFS trx_control = sysfs_1, а также путь к файлу, который будет в данном процессе задействован: trx_sysfile = /sys/class/gpio/gpio7/value. Как видно из схемы, я задействую GPIO7.
Теперь настало время подключить эту самую GPIO7 к SysFS, иначе чуда не произойдёт. Я решил сделать это по красоте, как некто предложил вот здесь:
В каталоге /etc/init.d/ создал скрипт под именем gpio_init:
Меняем ему владельца на root.root и ставим права 755.
В /usr/local/bin/ создал скрипт вод именем gpio-init такого содержания:
Ставим ему права 755.
Активируем запуск скрипта при загрузке
Перезагружаем Репку. Теперь при загрузке GPIO7 настроена выходом и по уполчанию выводит 0.
Осталось запустить MBUSD?
Вроде запустилось...да не тут-то было! Из локалки доступа к серверу как не было, так и нет. Вводим sudo systemctl status mbusd@ttyS0.service и убеждаемся, что MBUSD запустился. Вводим команду ss -tlp и убеждаемся, что 502 порт всё-таки наш сервер прослушивает. Ну конечно, порт зарезал фаервол, в качестве которого у меня стоит nftables, но у вас может быть что-то иное. Разрешим в nftables.conf доступ:
И вот, наконец, всё заработало. Теперь можно подключиться к Репе и считать данные, например, с регистров вольтметра
Что же это за коробка такая? С одной стороны у неё ethernet, wi-fi или даже какой-нибудь 5G модем. А с другой - старые добрые порты RS-232, RS-422, RS-485.
Путём нехитрых преобразований коробка перебрасывает MODBUS-пакеты туда-обратно. Делают их сейчас все, кому не лень! Начиная от брендов, вроде MOXA или ICP-DAS до неведомых кетайцев вроде HI-FLYING, USR IOT, тысячи их, разной степени
А раз так, быть может, и на основе неспециализированного компьютера можно поднять такой конвертер? Например, на...Репке?
И да, это возможно! Благодаря проекту MBUSD от Юрия Антоновича. Как несложно понять, это сервер под линуксовые (главным образом) машины. Несмотря на то, что проект, вроде как, ещё не выбрался из альфа-стадии, он вполне стабильный и универсальный. Достаточно, чтобы комп имел на борту необходимые порты (либо дооснастить его ими).
И универсальность его заключается, в том числе, вот в каком моменте:
Напомним, что RS-485 это полудуплексный интерфейс. В каждый момент времени он может либо принимать, либо передавать. И для чипов драйверов важно осуществлять своевременную коммутацию режима работы! Как же эту проблему решить?
Готовый вариант - взять кетайский переходник USB-RS485, вроде такого
Другой вариант - аппаратная схема автоматической коммутации. Бывают готовые специальные чипы драйверы, которые сами выбирают, в каком режиме им работать (например, MAX13487), бывают отдельные решения (например, вот эта схема хорошо работает).
Но MBUSD в состоянии и сам выполнять коммутацию приём-передача, что в теории, наверно, должно работать стабильнее и более предсказуемо. Для чего автор заложил в него три метода:
В первом случае он может использовать возможности линукс-драйвера под какие-то аппаратные реализации RS-485 для встраиваемых систем, наверно...в жизни такие мне не попадались.
Может он для коммутации задействовать вывод RTS, который присутствует в стандартном RS-232. Либо он может быть выведен в миникомпьютерах на пины для подключения шилд. Но есть ли у Репы такой выход? Смотрим на схему и убеждаемся, что ни в одной из "распиновок" его нет.
Но не беда, есть ведь ещё и третий метод: MBUSD умеет дёргать GPIO-выходы через линксовую SysFS. В интернетах много бурлений о том, что, мол, SysFS - это жуткое легаси, хватит на нём сидеть, нормальные проггеры пользуют UAPI. Что тут скажешь, MODBUS сам по себе ещё то замшелое легаси. Для нас главное, что "Repka-OS" его поддерживает нормально. А также то, что на гребёнку выведены сигналы UART, хотя бы один GPIO и питание.
Именно по этому пути я и решил пойти, сделав свою "шилду". Здесь можно посмотреть схему данной поделки. Делал на том, что было под рукой, наверняка вы возьмёте другую элементную базу. По крайней мере, имеется гальваническая развязка и базовая защита выхода от статики. Подключаем плату к верхней части гребёнки (контакты 1...10) через шлейф. Разъём XP2 я сделал для себя, чтобы подключать ранее сделанную "шилду" с часами DS3232. XP3 и XP4 выводят питание, на всякий случай (например, к XP3 я подключаю корпусной вентилятор). Вот как это всё сейча выглядит:
Да, надо будет хоть какую-нибудь коробочку под плату пристроить...
А теперь установим MBUSD. В репозитарии его похоже что нет, так что компиляем из исходников:
устанавливаем CMAKE, если у вас его вдруг ещё нет
Bash:
sudo apt-get install cmake
Всё скомпилировалось быстро и в целом без ошибок. На всякий случай уточню, что у меня сейчас стоит ядро 5.19.16.
Если будете задействовать UART0, как у меня, то следует также отключить вывод отладочных сообщений в него: здесь смотрим пункт Отключение / включение отладочного терминала на UART0.
Настроим конфиг-файл. Для этого я в каталоге /etc/mbusd беру файл mbusd.conf.example и копирую его с именем mbusd-ttyS0.conf Как несложно заметить, его имя содержит название UART-а, который я собираюсь задействовать для своего переходника. Редактирую его следующим образом:
Bash:
#############################################
# #
# Sample configuration file for mbusd #
# #
#############################################
########## Logging settings #############
# Logging verbosity level
loglevel = 1
# Logfile (fully-qualified path, or filename [stored at /var/log/] or - for STDOUT only)
logfile = /var/log/mbusd.log
########## Serial port settings #############
# Serial port device name
device = /dev/ttyS0
# Serial port speed
speed = 19200
# Serial port mode
mode = 8n1
# Enable RS-485 support for given serial port device (Linux only)
enable_rs485 = no
# RS-485 data direction control type (addc, rts_0, rts/rts_1, sysfs_0, sysfs_1)
trx_control = sysfs_1
# Sysfs file to use to control data direction
trx_sysfile = /sys/class/gpio/gpio7/value
############# TCP port settings #############
# TCP server address to bind
address = 0.0.0.0
# TCP server port number
port = 502
# Maximum number of simultaneous TCP connections
maxconn = 32
# Connection timeout value in seconds
timeout = 60
######### Request/response settings #########
# Maximum number of request retries
retries = 3
# Pause between requests in milliseconds
pause = 20
# Response wait time in milliseconds
wait = 200
# Reply on Broadcast
replyonbroadcast = no
Обратите внимание на строку # Serial port speed, где задаётся скорость интерфейса.
Кроме того, задаём режим работы с SysFS trx_control = sysfs_1, а также путь к файлу, который будет в данном процессе задействован: trx_sysfile = /sys/class/gpio/gpio7/value. Как видно из схемы, я задействую GPIO7.
Теперь настало время подключить эту самую GPIO7 к SysFS, иначе чуда не произойдёт. Я решил сделать это по красоте, как некто предложил вот здесь:
В каталоге /etc/init.d/ создал скрипт под именем gpio_init:
Bash:
#!/bin/sh
### BEGIN INIT INFO
# Provides: gpio_init
# Required-Start: $local_fs $network $named $time $syslog
# Required-Stop: $local_fs $network $named $time $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: Initialize GPIO pins for the project
### END INIT INFO
SCRIPT=/usr/local/bin/gpio-init
RUNAS=root
PIDFILE=/var/run/gpio_init.pid
LOGFILE=/var/log/gpio_init.log
start() {
if [ -f /var/run/$PIDNAME ] && kill -0 $(cat /var/run/$PIDNAME); then
echo 'Service already running' >&2
return 1
fi
echo 'Starting service…' >&2
local CMD="$SCRIPT &> \"$LOGFILE\" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"
echo 'Service started' >&2
}
stop() {
if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE"); then
echo 'Service not running' >&2
return 1
fi
echo 'Stopping service…' >&2
kill -15 $(cat "$PIDFILE") && rm -f "$PIDFILE"
echo 'Service stopped' >&2
}
uninstall() {
echo -n "Are you really sure you want to uninstall this service? That cannot be undone. [yes|No] "
local SURE
read SURE
if [ "$SURE" = "yes" ]; then
stop
rm -f "$PIDFILE"
echo "Notice: log file is not be removed: '$LOGFILE'" >&2
update-rc.d -f gpio_init remove
rm -fv "$0"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
uninstall)
uninstall
;;
retart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart|uninstall}"
esac
В /usr/local/bin/ создал скрипт вод именем gpio-init такого содержания:
Bash:
#! /bin/bash
function cleanup {
echo 7 > /sys/class/gpio/unexport
exit 0
}
# Clean up when exit
trap cleanup EXIT
trap cleanup SIGHUP
trap cleanup SIGQUIT
trap cleanup SIGINT
trap cleanup SIGTERM
echo 7 > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio7/direction
echo 0 > /sys/class/gpio/gpio7/value
sleep infinity
exit 0
Активируем запуск скрипта при загрузке
Bash:
sudo update-rc.d gpio-init defaults
Осталось запустить MBUSD?
Bash:
sudo systemctl enable mbusd@ttyS0.service
sudo systemctl start mbusd@ttyS0.service
Bash:
table inet filter {
chain input {
.
.
.
.
.
.
tcp dport 502 accept comment "Accept MODBUS TCP/IP Service"
}