193 lines
6.0 KiB
Plaintext
193 lines
6.0 KiB
Plaintext
'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('Ошибка отправки данных') |