'BackgroundThread.gd' extends Node var semaphore: Semaphore var mutex: Mutex var thread: Thread var exit_thread: bool = false var nodeWhoRequestedJob: Node var delta: float = 0.0 var address: String = "" var port: int = 0 var soc_brodcast: PacketPeerUDP var soc_unicast: PacketPeerUDP var unit: Object func _enter_tree(): semaphore = Semaphore.new() mutex = Mutex.new() exit_thread = false thread = Thread.new() thread.start(_thread_function) func _thread_function(): while true: semaphore.wait() # Wait until posted. mutex.lock() var should_exit = exit_thread # Protect with Mutex. mutex.unlock() if should_exit: break mutex.lock() var local_delta = delta var local_address = address var local_port = port var local_soc_brodcast = soc_brodcast var local_soc_unicast = soc_unicast var local_unit = unit mutex.unlock() # Выполнение задач local_unit.poll_receive(local_soc_brodcast) local_unit.poll_receive(local_soc_unicast) local_unit.state_machine() match local_unit.process(local_delta): Error.OK: nodeWhoRequestedJob.call_deferred('data_sent', local_address, local_port, local_unit.tx_data.slice(0, local_unit.tx_len)) Error.FAILED: nodeWhoRequestedJob.call_deferred('data_send_failed') func tellTheThreadToDoSomething(requester, delta, address, port, soc_brodcast, soc_unicast, unit): mutex.lock() nodeWhoRequestedJob = requester self.delta = delta self.address = address self.port = port self.soc_brodcast = soc_brodcast self.soc_unicast = soc_unicast self.unit = unit mutex.unlock() semaphore.post() func _exit_tree(): # Set exit condition to true. mutex.lock() exit_thread = true # Protect with Mutex. mutex.unlock() # Post to semaphore to wake up the thread. semaphore.post() # Wait until it exits. thread.wait_to_finish() 'Network.gd' extends Node var unit = Yau07.YaU07.new('ЯУ07') var soc_unicast: PacketPeerUDP var soc_brodcast: PacketPeerUDP var address: String = Constants.ADDRESSES[0][1] var port: int = Constants.ADDRESSES[0][2] var timeout: float = Yau07.ONLINE_TIMEOUT var last_update_time: float = 0.0 var broadcast_packet: PackedByteArray var state = Constants.STATE.WAIT var send_array: Array = [] signal yau_status_line(_status) ## Вызывается когда меняется состояние связи с ячейкой signal yau_receive(_data_from_yau) ## signal yau_read_isa(_unit_isa_ports) ## Класс для отправки данных в сокет class Socket extends PacketPeerUDP: func send_to(addr: String, port: int, data: PackedByteArray): self.set_dest_address(addr, port) self.put_packet(data) func poll_receive(sock: PacketPeerUDP) -> bool: ## Приёмник if timeout - last_update_time > 0: while sock.get_available_packet_count() > 0: broadcast_packet = sock.get_packet() var addr_receive = sock.get_packet_ip() var port_receive = sock.get_packet_port() if (address == addr_receive) and (port == port_receive): last_update_time = 0.0 unit.parse(broadcast_packet) var data_from_yau_07 = unit.status emit_signal('yau_receive', data_from_yau_07) else: if sock.get_available_packet_count(): last_update_time = 0.0 return false func _ready() -> void: # Привязка для принятия широковещательного канала soc_brodcast = Socket.new() var rc = soc_brodcast.bind(Constants.BROADCAST_PORT, '*') if rc != OK: print('Ошибка: Неудачная привязка широковещательного адреса') soc_unicast = Socket.new() rc = soc_unicast.bind(Constants.UNICAST_PORT, Constants.UNICAST_ADDRESS) if rc != OK: print('Ошибка: неудачная привязка адреса: ', address) unit.connect('line_changed', Callable(self, 'on_line_changed')) unit.connect('command_fail', Callable(self, 'on_command_fail')) # Создание и запуск фонового потока var background_thread_node = BackgroundThread.new() add_child(background_thread_node) background_thread_node.name = "BackgroundThreadNode" func _process(delta: float) -> void: last_update_time += delta background_thread_node.tellTheThreadToDoSomething(self, delta, address, port, soc_brodcast, soc_unicast, unit) func state_machine(): var fl_done = (unit.cmd_state == unit.CmdState.DONE) ## Режим ожидания if state == Constants.STATE.WAIT and fl_done: if send_array.size(): state = Constants.STATE.READ_ISA if send_array[0][0] == 'rd' else Constants.STATE.WRITE_ISA ## Режим чтения из ИСА elif state == Constants.STATE.READ_ISA and fl_done: var ports_read = send_array.pop_front() unit.send_isa(unit.CmdCode.READ_ISA, ports_read[1]) state = Constants.STATE.DONE ## Режим записи в ИСА elif state == Constants.STATE.WRITE_ISA and fl_done: var ports_write = send_array.pop_front() var key = ports_write[1].keys() unit.send_isa(unit.CmdCode.WRITE_ISA, [key[0], ports_write[1][key[0]]]) state = Constants.STATE.WAIT elif state == Constants.STATE.DONE and fl_done: emit_signal('yau_read_isa', unit.isa_ports) state = Constants.STATE.WAIT func on_line_changed(_unit) -> void: emit_signal('yau_status_line', unit.online) ## Если отсутствует подключение к ячейке ЯУ-07 func on_command_fail(_unit) -> void: print_debug('Command send fail') func data_sent(address, port, data): soc_unicast.send_to(address, port, data) func data_send_failed(): print('Ошибка отправки данных')