class_name Network extends Node const UDP_PROTO: = {'yau07tx': yau07.YaU07, 'json-capsrpb': capsrpb.CapsRpb} const TCP_PROTO: = {'5p28': tcp5p28.TCP5P28} const SERIAL_PROTO: = {'uart': spt25.SPT25} const MODBUS_PROTO: = {'mbcs': sch3.Sch3} const UDPRX_PROTO: = {'udprx': navi.NaviSource} var tick: int = 0 class Serial extends SerialPort: func send_to(data: PackedByteArray): return write_raw(data) func _to_string() -> String: return 'последовательный порт \"%s\" @ %d (%s)' % [self.port, self.baudrate, 'открыт' if is_open() else 'закрыт'] func try_open(parsing_proc: Callable): if is_open(): return Error.OK var rc = open(port) if rc == Error.OK: data_received.connect(parsing_proc) start_monitoring(timeout) return rc func try_close(): if not is_open(): return Error.FAILED stop_monitoring() close() var connections = data_received.get_connections() for conn in connections: data_received.disconnect(conn.callable) return Error.OK class Socket extends PacketPeerUDP: func send_to(addr, data): set_dest_address(addr[0], addr[1]) var rc: = put_packet(data) if rc != Error.OK: push_error('%s: %s', [error_string(rc), addr]) class SocketTCP extends TCPServer: const RX_TIMEOUT: int = 1000 ## Время сброса счётчика принятия части пакета. var peerstream: = PacketPeerStream.new() var unit_key: StringName ## Ключ юнита. var head_len: int = 8 ## Длина заголовка команды. var len_place: int = 4 ## Номер начального байта с длинной блока данных. var type_len: int = 4 ## Количество байт в размере длинны. var rx_tick: int ## Время приёма последнего пакета. var rx_all: bool = true ## Флаг, что пакет принят полностью. var rx_len: int ## Количество принятых байт. var rx_data: PackedByteArray ## Принятые данные. var data_len: int ## Размер ожидаемых данных. func send_to(data): var peer = peerstream.get_stream_peer() peer.put_data(data) var poll_sockets: Array[Socket] var tcp_sockets: Array var units: Dictionary[StringName, unit.Unit] var units_udp: Dictionary[StringName, unit.Unit] var units_udprx: Dictionary[StringName, unit.Unit] var units_tcp: Dictionary[StringName, unit.Unit] var units_serial: Dictionary[StringName, unit.Unit] var units_modbus: Dictionary[StringName, unit.Unit] var serials: Dictionary # Последовательные порты var mbcs: Dictionary # Клиенты modbus. var dst_ports: Dictionary[StringName, int] var dst_addrs: Dictionary[StringName, StringName] var unit_keys: Dictionary var sock_unicast: Socket var sock_capsrpb: Socket var logger_page: Node var send_sockets: Dictionary # Таблица <имяустройста>: <сокет> для отправки сообщений var addr_port_to_unit_name: Dictionary[StringName, StringName] func on_serial_data(data, unit): unit.parse(data, tick) func create_socket(nm) -> Socket: var addr = settings.UnitProfiles[nm][1] var port = settings.UnitProfiles[nm][2][0] var broad = settings.UnitProfiles[nm][3] var bind = settings.UnitProfiles[nm][4] var sock: = Socket.new() sock.set_broadcast_enabled(broad) var rc = Error.OK if not bind else sock.bind(port, addr) var errlevel = log.INFO if rc == Error.OK else log.ERROR log.message(errlevel, '\"%s\" привязан к %s:%d? - %s, результат: %s' % [nm, addr, port, ['нет', 'да'][int(bind)], error_string(rc)]) return sock func create_tcpsocket(unit_name: StringName) -> SocketTCP: var addr = settings.UnitProfiles[unit_name][1] var port = settings.UnitProfiles[unit_name][2][0] var sock = SocketTCP.new() sock.unit_key = unit_name var rc: = sock.listen(port, addr) if rc == Error.OK: log.message(log.INFO, '\"%s\" слушает на %s:%d' % [unit_name, addr, port]) else: log.message(log.ERROR, '\"%s\" %s:%d \"%s\"' % [unit_name, addr, port, error_string(rc)]) return sock func create_serial(nm) -> Serial: var port = settings.UnitProfiles[nm][1] var baud = settings.UnitProfiles[nm][2][0] var sp: = Serial.new() sp.port = port sp.baudrate = baud sp.timeout = 20000 return sp func create_modbus(nm) -> sch_3.Sch3: var unit_sch3: = sch_3.Sch3.new(nm) return unit_sch3 func _ready() -> void: poll_sockets.append(create_socket('уарэп-яу07-частный')) poll_sockets.append(create_socket('уарэп-яу07-общий')) poll_sockets.append(create_socket('уарэп-капсрпб')) poll_sockets.append(create_socket('навигация')) sock_unicast = poll_sockets[0] sock_capsrpb = poll_sockets[2] send_sockets['уарэп-яу07-частный'] = sock_unicast send_sockets['уарэп-яу07-общий'] = poll_sockets[1] send_sockets['уарэп-капсрпб'] = sock_capsrpb send_sockets['уарэп-эмс'] = sock_unicast send_sockets['уарэп-яу07-2в'] = sock_unicast send_sockets['уарэп-яу07-2н'] = sock_unicast send_sockets['уарэп-яу07-2к'] = sock_unicast send_sockets['уарэп-яу07-4в'] = sock_unicast send_sockets['уарэп-яу07-4н'] = sock_unicast send_sockets['уарэп-яу07-4к'] = sock_unicast send_sockets['уарэп-яу07-1в'] = sock_unicast send_sockets['уарэп-яу07-1н'] = sock_unicast send_sockets['уарэп-яу07-1к'] = sock_unicast send_sockets['уарэп-яу07-3в'] = sock_unicast send_sockets['уарэп-яу07-3н'] = sock_unicast send_sockets['уарэп-яу07-3к'] = sock_unicast var bind_serials: = [] var bind_modbuses: = [] for unit_name in settings.UnitProfiles: var st = settings.UnitProfiles[unit_name] var proto = st[0] if proto in UDPRX_PROTO: var new_unit = UDPRX_PROTO[proto].new(unit_name) units[unit_name] = new_unit units_udprx[unit_name] = new_unit dst_ports[unit_name] = st[2][0] if proto in UDP_PROTO: var new_unit = UDP_PROTO[proto].new(unit_name) units[unit_name] = new_unit units_udp[unit_name] = new_unit dst_ports[unit_name] = st[2][1] if len(st[2]) > 1 else st[2][0] dst_addrs[unit_name] = st[1] if proto in TCP_PROTO: var unit_tcp = TCP_PROTO[proto].new(unit_name) units[unit_name] = unit_tcp units_tcp[unit_name] = unit_tcp if proto in MODBUS_PROTO: var unit_modbus = MODBUS_PROTO[proto].new(unit_name) unit_modbus.port = settings.UnitProfiles[unit_name][1] # TODO: убрать это отсюда (обращение к глобальным данным из экземпляра) unit_modbus.params = settings.UnitProfiles[unit_name][2] # TODO: убрать это отсюда (обращение к глобальным данным из экземпляра) units[unit_name] = unit_modbus units_modbus[unit_name] = unit_modbus bind_modbuses.append([unit_modbus, unit_name]) if proto in SERIAL_PROTO: var unit_serial = SERIAL_PROTO[proto].new(unit_name) var serial = create_serial(unit_name) units_serial[unit_name] = unit_serial units[unit_name] = unit_serial serials[unit_name] = serial ProjectSettings.connect('settings_changed', Callable(self, '_on_settings_changed_serial').bind(bind_serials)) tcp_sockets.append([create_tcpsocket('уарэп-5п28'), units_tcp['уарэп-5п28']]) for key in dst_ports: unit_keys[dst_ports[key]] = key if logger_page: for key in units: var u = units[key] u.connect('line_changed', Callable(logger_page, 'on_line_changed').bind(key)) u.connect('command_fail', Callable(logger_page, 'on_command_fail').bind(key)) for key in settings.UnitProfiles: var item = settings.UnitProfiles[key] var addr_port: = StringName('%s:%d' % [item[1], item[2][0]]) addr_port_to_unit_name[addr_port] = StringName(key) func _on_settings_changed_modbus(bind_modbuses: Array): var external_ctl = ProjectSettings.get_setting('application/config/Внешнее управление', false) for bm in bind_modbuses: var unit_modbus = bm[0] var unit_name = bm[1] func _on_settings_changed_serial(bind_serials: Array): var external_ctl = ProjectSettings.get_setting('application/config/Внешнее управление', false) for bs in bind_serials: var serial = bs[0] var unit_serial = bs[1] var unit_name = bs[2] serial.try_close() if not external_ctl: var rc = serial.try_open(on_serial_data.bind(unit_serial)) if rc != Error.OK: log.message(log.ERROR, 'невозможно открыть %s для \"%s\"' % [serial, unit_name]) else: log.message(log.INFO, '%s для \"%s\"' % [serial, unit_name]) func poll_receive_udp(sock: Socket) -> bool: while sock.get_available_packet_count() > 0: var data: = sock.get_packet() var addr: = sock.get_packet_ip() var port: = sock.get_packet_port() var addr_port: = StringName('%s:%d' % [addr, port]) if addr_port_to_unit_name.has(addr_port): var unit_name: = addr_port_to_unit_name[addr_port] units[unit_name].parse(data, tick) continue if unit_keys.has(port): var key1 = unit_keys[port] if units.has(key1): units[key1].parse(data, tick) continue port = sock.get_local_port() var key = StringName('%s:%d' % ['*', port]) if units.has(key): var unit_udprx = units[key] unit_udprx.source_addr = [addr, port] unit_udprx.parse(data, tick) continue return false func poll_receive_tcp(sock: SocketTCP) -> bool: if sock.is_connection_available(): # Проверить, если кто то пытается подключиться var client: = sock.take_connection() # Принять соединение sock.peerstream.set_stream_peer(client) # Привязать поток к новому клиенту log.info('подключен: %s:%d к порту: %d' % [ client.get_connected_host(), client.get_connected_port(), client.get_local_port() ] ) var peer = sock.peerstream.get_stream_peer() if peer: var peer_len_data = peer.get_available_bytes() if peer_len_data > 0: get_client_data(sock, peer_len_data, peer) if sock.unit_key in units_tcp and sock.rx_all: units_tcp[sock.unit_key].parse(sock.rx_data, tick) return false func get_client_data(sock: SocketTCP, peer_len_data, peer): if tick - sock.rx_tick > sock.RX_TIMEOUT: sock.rx_all = true sock.rx_tick = tick if sock.rx_all: if peer_len_data >= sock.head_len: sock.rx_all = false sock.rx_len = sock.head_len var head = peer.get_data(sock.head_len) sock.data_len = head[1].decode_u32(sock.len_place) var len_data_in_buf = peer.get_available_bytes() if len_data_in_buf > 0: sock.rx_data = head[1] var len_rx = len_data_in_buf if len_data_in_buf >= sock.data_len: len_rx = sock.data_len get_tcp_data(sock, peer, len_rx) else: var len_rx = (sock.head_len + sock.data_len) - sock.rx_len if peer_len_data < len_rx: len_rx = peer_len_data get_tcp_data(sock, peer, len_rx) func get_tcp_data(sock: SocketTCP, peer, len_rx): var temp_data = peer.get_data(len_rx)[1] sock.rx_data.append_array(temp_data) sock.rx_len += len_rx if sock.rx_len >= sock.head_len + sock.data_len: sock.rx_all = true func _process(_delta: float) -> void: tick = Time.get_ticks_msec() RenderingServer.global_shader_parameter_set('tick_curent', tick) for key in units_udp: var unit_udp = units_udp[key] if Error.OK == unit_udp.process(tick): var sock = send_sockets[unit_udp.name] var tx_data = unit_udp.tx_data.slice(0, unit_udp.tx_len) var dst_port = dst_ports[key] var dst_addr = dst_addrs[key] sock.send_to([dst_addr, dst_port], tx_data) for key in units_udprx: var unit_udprx = units_udprx[key] unit_udprx.process(tick) for key in units_serial: var unit_serial = units_serial[key] var serial = serials[key] if Error.OK == unit_serial.process(tick): serial.send_to(unit_serial.tx_data) for key in units_modbus: var unit_modbus = units_modbus[key] unit_modbus.process(tick) for sock_unit in tcp_sockets: var sock = sock_unit[0] var unit_tcp = sock_unit[1] if Error.OK == unit_tcp.process(tick): sock.send_to(unit_tcp.tx_data) poll_receive_tcp(sock) poll_sockets.any(poll_receive_udp) func get_unit_instance(unit_name: StringName) -> unit.Unit: tools.allways(unit_name in units, 'нет такого устройства: \"%s\"' % unit_name) return units[unit_name]