From a895683bb87dc64233b19ccece6b8733c8304a8f Mon Sep 17 00:00:00 2001 From: sasha80 Date: Thu, 29 Feb 2024 11:36:27 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B8=D0=BC=D0=B8=D1=82=D0=B0=D1=82=D0=BE=D1=80=20?= =?UTF-8?q?=D1=81=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D0=B0=20Modbus=20Serial=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=B1=D0=BE=D1=80=D0=B0=20=D0=A93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modbus/server-rtu.py | 76 ++++++++++++++++++++++++++++++++++++++++++ modbus/start-driver.sh | 8 ++++- 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 modbus/server-rtu.py diff --git a/modbus/server-rtu.py b/modbus/server-rtu.py new file mode 100644 index 00000000..a1f535bd --- /dev/null +++ b/modbus/server-rtu.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +""" +Имитатор сервера Modbus Serial прибора Щ3. +Использовать для отладки. +""" + +import logger +import os +import argparse +from pymodbus.server.sync import StartSerialServer +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext, ModbusSparseDataBlock +from pymodbus.transaction import ModbusRtuFramer + +DEF_SERIAL = 'COM2' if os.name == 'nt' else '/dev/tty3' +log_file_dir = os.path.join(os.path.expanduser('~')) +log = logger.get_logger(__file__, log_file_dir) + +FX_CODES = {2: 'di', 4: 'ir', 3: 'hr', 6: 'hr', 16: 'hr', 22: 'hr', 23: 'hr', 1: 'co', 5: 'co', 15: 'co'} +""" Кодировка регистров в pymodbus """ + + +class CallbackModbusSlaveContext(ModbusSlaveContext): + """ Блок данных, который сохраняет новое значение + в памяти и передаёт операцию в очередь сообщений + для дальнейшей процедуры обработки. """ + + def __init__(self): + """ """ + super(CallbackModbusSlaveContext, self).__init__() + + def setValues(self, fx, address, values): + """ Устанавливает требуемые значения хранилища данных. + :param fx: + :param address: Начальный адрес. + :param values: Новые значения, которые необходимо установить. + """ + super(CallbackModbusSlaveContext, self).setValues(fx, address, values) + fx = FX_CODES[fx] if fx in FX_CODES else '**error**' + log.debug(f'setValues() fx:{fx} address:{address} values:{values}') + + def getValues(self, fx, address, count=1): + """ Устанавливает требуемые значения хранилища данных. + :param fx: + :param address: Начальный адрес + :param count: + """ + values = super(CallbackModbusSlaveContext, self).getValues(fx, address, count) + fx = FX_CODES[fx] if fx in FX_CODES else '**error**' + log.debug(f'getValues() fx:{fx} address:{address} values:{values}') + return values + + +def main(): + parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument('-modbus-unit', default=1, type=int, help='Номер устройства Modbus') + parser.add_argument('-serial-baud', default=115200, type=int, help='Скорость последовательного порта, бод') + parser.add_argument('-serial-port', default=DEF_SERIAL, type=str, help='Последовательный порт для подключения клиента Modbus ') + opts, opts_unk = parser.parse_known_args() + print_opts_error(opts_unk) + run_server(opts.serial_port, opts.serial_baud) + + +def run_server(serial_port, serial_baud): + store = CallbackModbusSlaveContext() + context = ModbusServerContext(slaves=store, single=True) + # timeout=.005 - нужно обязательно указать, иначе не работает + StartSerialServer(context=context, framer=ModbusRtuFramer, port=serial_port, timeout=.005, baudrate=serial_baud) + + +def print_opts_error(opts: list) -> None: + for opt in opts: + log.debug('внимание: неизвестный аргумент: \"%s\"\n' % opt) + + +if __name__ == '__main__': + main() diff --git a/modbus/start-driver.sh b/modbus/start-driver.sh index c5496fa8..7c4bfb61 100644 --- a/modbus/start-driver.sh +++ b/modbus/start-driver.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash SERIAL_PORT2="/home/$(whoami)/tty2" # Порт для подключения драйвера клиента -SERIAL_PORT3="/home/$(whoami)/tty3" # Порт для подключения сервера Modbus +SERIAL_PORT3="/home/$(whoami)/tty3" # Порт для подключения сервера Modbus Serial (Прибор Щ3) UDP_ADDR="localhost" UDP_PORT_RX="44100" UDP_PORT_TX="48000" @@ -50,6 +50,12 @@ fi # \---------------------------------------------------------------------------------/ +# /---------------------------------------------------------------------------------\ +# Запустить сервер Modbus Serial (Прибор Щ3) +xterm -geometry 120x5 -fa Monospace -fs 12 -hold -T "Сервер Modbus Serial Щ3 \"${SERIAL_PORT3}\"" -e "python3 server-rtu.py -serial-port ${SERIAL_PORT3}" & +# \---------------------------------------------------------------------------------/ + + # /---------------------------------------------------------------------------------\ # Запустить драйвер клиента Modbus xterm -geometry 120x5 -fa Monospace -fs 12 -hold -T "Драйвер клиента Modbus Serial \"${SERIAL_PORT2} ${UDP_ADDR}:${UDP_PORT_RX}\"" -e "python3 client-serial-tcp.py -serial-port ${SERIAL_PORT2} -udp-addr ${UDP_ADDR} -udp-port-rx ${UDP_PORT_RX} -udp-port-tx ${UDP_PORT_TX}" &