Files
uarep-ctl/scenes/scripts/modbus.gd

132 lines
7.1 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends Node
const ONLINE_TIMEOUT = 5.0 ## Время ожидания пакета от ячейки, секунды
class ModbusClient:
## Состояние автомата выполнения команды
enum CmdState {
DONE, ## Команда выполнена
FAIL, ## Команда не выполнена
SEND, ## Буфер готов для отправки
WAIT ## Ожидание выполнения
}
var name: String
var unit: = 1 ## Адрес устройства Modbus
var cmd_state: = CmdState.DONE ## Код текущей команды
var tx_data: PackedByteArray ## Данные для отправки
var online: = false ## Флаг. Если установлен, устройство на связи. Активный уровень - [b]true[/b].
var tick_rx: = 0 ## Время приёма крайнего сообщения
var tick_tx: = 0 ## Время отправки крайнего сообщения
static var json_conv: = JSON.new()
signal command_done() ## Вызывается при успешном выполнении команды
signal command_fail() ## Вызывается при возникновении ошибки во время выполнения команды
signal line_changed() ## Вызывается при смене состояния связи с ячейкой
signal data_received() ## Вызывается при приёме сообщения, до его разбора
signal parse_failed(msg: String) ## Вызывается при возникновении ошибки во время разбора пакета. Передаёт сообщение об ошибке
signal holding_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров хранения
signal input_received(addr: int, data: Array) ## Вызывается при получении сообщения c данными из регистров входов
signal info_received(msg: String) ## Вызывается при получении информационного сообщения
signal except_received(msg: String) ## Вызывается при получении сообщения об исключительной ситуации
func _init(nm: String, u: int = 1):
unit = u
name = nm
## Изменяет состояние. Вызывать периодически[br]
## [param tick] - Текущщее время в мс[br]
func process(tick: int):
if online and ((tick - tick_rx) > ONLINE_TIMEOUT):
online = false
emit_signal('line_changed')
if (cmd_state == CmdState.WAIT) or (cmd_state == CmdState.SEND):
cmd_state = CmdState.FAIL
emit_signal('command_fail')
var rc = Error.ERR_BUSY
if cmd_state == CmdState.SEND:
rc = Error.OK
tick_tx = tick
cmd_state = CmdState.WAIT
return rc
## Производит разбор принятых данных. Вызывать при приёме данных на сокете[br]
## [param data] - Данные принятые на сокете[br]
## [param tick] - Текущщее время в мс[br]
func parse(data: PackedByteArray, tick: int) -> bool:
tick_rx = tick
if not online:
online = true
emit_signal('line_changed')
var utf8_data = data.get_string_from_utf8()
if Error.OK == json_conv.parse(utf8_data):
emit_signal('data_received')
var message: Dictionary = json_conv.get_data()
if message.has('code') and message.has('data'):
var rc: = true
var message_code = message['code']
var message_data = message['data']
match message_code:
'read_input':
var addr = message_data[0]
var regs = message_data.slice(1)
emit_signal('input_received', addr, regs)
'read_holding':
var addr = message_data[0]
var regs = message_data.slice(1)
emit_signal('holding_received', addr, regs)
'info':
var msg = message['data']
emit_signal('info_received', msg)
'exception':
var msg = message['data']
emit_signal('except_received', msg)
rc = false
_:
var msg: String = 'код команды \"%s\" - не распознан' % message_code
emit_signal('parse_failed', msg)
rc = false
if (cmd_state == CmdState.WAIT) and rc:
cmd_state = CmdState.DONE
emit_signal('command_done')
elif (cmd_state == CmdState.WAIT) and (not rc):
cmd_state = CmdState.FAIL
emit_signal('command_fail')
else:
var message = json_conv.get_error_message()
emit_signal('parse_failed', message)
return true
## Отправляет команду "записать в регистры".[br]
## [param addr] - Начальный адрес регистров.[br]
## [param count] - Данные для записи в регистры от начального адреса.[br]
func write(addr: int, data: Array) -> bool:
if cmd_state != CmdState.DONE: return false
var json_dict = {'code': 'write', 'data': [addr] + data}
tx_data = json_conv.stringify(json_dict).to_utf8_buffer()
cmd_state = CmdState.SEND
return true
## Отправляет команду "читать регистры хранения".[br]
## [param addr] - Начальный адрес регистров.[br]
## [param count] - Количество регистров от начального адреса.[br]
func read_holdind(addr: int, count: int = 1) -> bool:
if cmd_state != CmdState.DONE: return false
var json_dict = {'code': 'read_holding', 'data': [addr, count]}
tx_data = json_conv.stringify(json_dict).to_utf8_buffer()
cmd_state = CmdState.SEND
return true
## Отправляет команду "читать регистры входов".[br]
## [param addr] - Начальный адрес регистров.[br]
## [param count] - Количество регистров от начального адреса.[br]
func read_input(addr: int, count: int = 1) -> bool:
if cmd_state != CmdState.DONE: return false
var json_dict = {'code': 'read_input', 'data': [addr, count]}
tx_data = json_conv.stringify(json_dict).to_utf8_buffer()
cmd_state = CmdState.SEND
return true