Files
uarep-ctl/scripts/yau07.gd
2023-09-05 09:36:12 +03:00

203 lines
9.7 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
## Протокол ячейки ЯУ-07
const BUFFER_SIZE = 2048 ## Размер буфера для приёма датаграмм, байты
const ONLINE_TIMEOUT = 5000 ## Время ожидания пакета от ячейки, мс
const RESEND_TIMEOUT = 300 ## Задержка для повторной отправки команды, мс
const RETRY_COUNT = 5 ## Количество повторных отправок
## Ячейка ЯУ-07
class YaU07:
## Коды выполняемых команд
enum CmdCode {
READ_ISA = 0, ## Код команды "читать порт ISA" ячейки ЯУ-07
WRITE_ISA = 1 ## Код команды "записать порт ISA" ячейки ЯУ-07
}
## Состояние автомата выполнения команды
enum CmdState {
DONE, ## Команда выполнена
FAIL, ## Команда не выполнена
SEND, ## Буфер готов для отправки
UNCK, ## Номер команды не ининциирован
WAIT ## Ожидание выполнения
}
signal line_changed(unit: YaU07) ## Вызывается когда меняется состояние связи с ячейкой
signal command_done(unit: YaU07) ## Вызывается после выполнения команды
signal command_fail(unit: YaU07) ## Вызывается если возникла ошибка при выполнении команды и команда не выполнена
var cmd_data: = PackedByteArray() ## Данные команды. Устанавливается в ЯУ-07
var cmd_num_rx: = 0 ## Номер команды принятый
var cmd_num_tx: = 0 ## Номер команды переданный
var cmd_result: = 1 ## Результат выполнения команды. Устанавливается в ЯУ-07
var cmd_retry = 0 ## Счётчик оставшихся попыток выполнить команду
var cmd_state = CmdState.UNCK ## Состояние выполнения команды
var cmd_tick_rx = 0.0 ## Время последнего приёма команды
var cmd_tick_tx = 0.0 ## Время последней отправки команды
var isa_ports = {} ## Результат выполнения команды "читать порт"
var name: = String() ## Имя
var online = false ## Состояние связи с ячейкой
var status: = PackedByteArray() ## Поле "состояние прибора"
var tick = 0.0 ## Текущее тик-время в мс
var tx_data: = [] ## Буфер отправленный
var tx_len = 0 ## Длина последнего отправленного пакета
func _to_string() -> String: return String('яу07: %s %s' % [self.name, ['отключен', 'на связи'][int(online)]])
func _init(nm):
self.name = nm
tx_data.resize(BUFFER_SIZE)
tx_data.fill(0)
tick = 0.0
func process(t: int):
tick = t
if online and ((tick - cmd_tick_rx) > ONLINE_TIMEOUT):
online = false
emit_signal('line_changed', self)
var rc = Error.ERR_BUSY
if cmd_state == CmdState.SEND:
rc = Error.OK
cmd_tick_tx = tick
cmd_state = CmdState.WAIT
cmd_retry = RETRY_COUNT
elif cmd_state == CmdState.WAIT:
if cmd_retry:
if (tick - cmd_tick_tx) > RESEND_TIMEOUT:
rc = Error.OK
cmd_tick_tx = tick
cmd_retry -= 1
else:
cmd_state = CmdState.FAIL
emit_signal('command_fail', self)
rc = Error.FAILED
return rc
func send_isa(cmd_code: int, ports_data: PackedByteArray) -> bool:
if (cmd_state == CmdState.WAIT) \
or (cmd_state == CmdState.SEND) \
or (cmd_state == CmdState.UNCK):
return false
if not ((cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA)):
return false
cmd_num_tx = (cmd_num_rx + 1) % 0xffff
var ports_count = ports_data.size()
tx_len = ports_count * 2 + 8
tx_data.encode_u16(2, cmd_num_tx)
if cmd_code == CmdCode.WRITE_ISA:
ports_count /= 2
tx_data[6] = cmd_code
tx_data[7] = ports_count
var i: = 0
for word in ports_data:
Tools.set_wordi(tx_data, 8 + i, word)
i += 2
cmd_state = CmdState.SEND
return true
## Возвращает код команды ЯУ-07
## [param rx_data] - Принятые данные[br]
## Возвращает [b]null[/b] - Если код команды не найден[br]
## Возвращает [b]0...255[/b] - Код команды
func get_cmd_code(rx_data: PackedByteArray):
var rx_data_len = rx_data.size()
if rx_data_len < 7:
return null
var status_len = rx_data.decode_u16(6) # Длина массива байтового "состояние прибора"
if rx_data_len <= (status_len + 6): # Нет поля "ответ на команду", разбор пакета завершить
return null
var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "кода команды"
if rx_data_len <= cmd_code_pos:
return null
return rx_data[cmd_code_pos] # "код команды"
func parse_isa(rx_data, status_len) -> bool:
var ports_count_pos = status_len + 10 # Положение в приёмном буфере количества портов
if rx_data.size() < ports_count_pos:
return false
var ports_count = rx_data[ports_count_pos] # Количество портов
var counted_len = status_len + (ports_count * 4) + 11 # Вычисленная длина пакета
if rx_data.size() < counted_len:
return false
var addr_pos = status_len + 11 # Смещение положения адреса в приёмном буфере
var data_pos = status_len + 13 # Смещение положения данных в приёмном буфере
var i: = 0
while i < ports_count:
var shift: = i * 4
var isa_addr = Tools.ibytes_to_word(rx_data, addr_pos + shift) # Адрес порта ISA яу-07
var isa_data = Tools.ibytes_to_word(rx_data, data_pos + shift) # Данные порта ISA яу-07
isa_ports[isa_addr] = isa_data
i += 1
cmd_data = rx_data.subarray(addr_pos, (addr_pos + ports_count * 4) - 1)
return i > 0
## Заполняет состояние прибора данными прочитанными из портов ЯУ-07
## для команд "читать порты" или "записать порты"[br]
## [param rx_data] - Принятые данные[br]
## Возвращает [b]true[/b] - Данные обработаны успешно[br]
## Возвращает [b]false[/b] - Данные не обработаны из за ошибки[br]
func parse(rx_data: PackedByteArray) -> bool:
if not online:
online = true
emit_signal('line_changed', self)
var rx_data_len = rx_data.size()
if rx_data_len < 11:
return false
cmd_num_rx = Tools.ibytes_to_word(rx_data, 2)
if cmd_state == CmdState.UNCK:
cmd_state = CmdState.DONE
var status_len = Tools.ibytes_to_word(rx_data, 6) # Длина массива байтового "состояние прибора"
if rx_data_len < (status_len + 6):
return false
var i: = 0
var len_rx_data: = rx_data.size()
status.resize(status_len)
while i < status_len:
var byte_i = i + 8
if byte_i < len_rx_data:
status[i] = rx_data[byte_i] # Массив байтовый "состояние прибора"
i += 1
if rx_data_len == (status_len + 6):
return true # Нет поля "ответ на команду", разбор пакета завершить
var cmd_code_pos = status_len + 8 # Положение в приёмном буфере "код команды"
if rx_data_len <= cmd_code_pos:
return false
var cmd_status_pos = status_len + 9 # Положение в приёмном буфере "состояния выполнения команды"
if rx_data_len <= cmd_status_pos:
return false
cmd_result = rx_data[cmd_status_pos]
if cmd_result != 1: # Команда не выполнена
return false
var cmd_code: CmdCode = rx_data[cmd_code_pos] as CmdCode # "код команды"
if (cmd_code == CmdCode.READ_ISA) or (cmd_code == CmdCode.WRITE_ISA):
parse_isa(rx_data, status_len)
if (cmd_state == CmdState.WAIT) and (cmd_num_rx == cmd_num_tx):
cmd_state = CmdState.DONE
emit_signal('command_done', self)
return true