Add socket timer for lost connections

This commit is contained in:
Ken Roberts 2014-10-16 19:28:51 -07:00
parent c1415bb891
commit dfcbaa8c28
2 changed files with 45 additions and 21 deletions

View File

@ -150,6 +150,7 @@ class PJLink1(QTcpSocket):
self.timer = None # Timer that calls the poll_loop self.timer = None # Timer that calls the poll_loop
self.send_queue = [] self.send_queue = []
self.send_busy = False self.send_busy = False
self.socket_timer = None # Test for send_busy and brain-dead projectors
# Map command returned to function # Map command returned to function
self.PJLINK1_FUNC = {'AVMT': self.process_avmt, self.PJLINK1_FUNC = {'AVMT': self.process_avmt,
'CLSS': self.process_clss, 'CLSS': self.process_clss,
@ -166,6 +167,7 @@ class PJLink1(QTcpSocket):
} }
def reset_information(self): def reset_information(self):
log.debug('(%s) reset_information() connect status is %s' % (self.ip, self.state()))
self.power = S_OFF self.power = S_OFF
self.pjlink_name = None self.pjlink_name = None
self.manufacturer = None self.manufacturer = None
@ -179,6 +181,10 @@ class PJLink1(QTcpSocket):
self.other_info = None self.other_info = None
if hasattr(self, 'timer'): if hasattr(self, 'timer'):
self.timer.stop() self.timer.stop()
if hasattr(self, 'socket_timer'):
self.socket_timer.stop()
self.send_queue = []
self.send_busy = False
def thread_started(self): def thread_started(self):
""" """
@ -215,6 +221,13 @@ class PJLink1(QTcpSocket):
self.deleteLater() self.deleteLater()
self.i_am_running = False self.i_am_running = False
def socket_abort(self):
"""
Aborts connection and closes socket in case of brain-dead projectors.
"""
log.debug('(%s) socket_abort() - Killing connection' % self.ip)
self.disconnect_from_host(abort=True)
def poll_loop(self): def poll_loop(self):
""" """
Called by QTimer in ProjectorManager.ProjectorItem. Called by QTimer in ProjectorManager.ProjectorItem.
@ -362,10 +375,6 @@ class PJLink1(QTcpSocket):
@pyqtSlot() @pyqtSlot()
def get_data(self): def get_data(self):
log.debug('(%s) get_data() Received readyRead signal' % self.ip)
return self._get_data()
def _get_data(self):
""" """
Socket interface to retrieve data. Socket interface to retrieve data.
""" """
@ -379,6 +388,7 @@ class PJLink1(QTcpSocket):
log.debug('(%s) get_data(): No data available (-1)' % self.ip) log.debug('(%s) get_data(): No data available (-1)' % self.ip)
self.projectorReceivedData.emit() self.projectorReceivedData.emit()
return return
self.socket_timer.stop()
self.projectorNetwork.emit(S_NETWORK_RECEIVED) self.projectorNetwork.emit(S_NETWORK_RECEIVED)
data_in = decode(read, 'ascii') data_in = decode(read, 'ascii')
data = data_in.strip() data = data_in.strip()
@ -432,6 +442,9 @@ class PJLink1(QTcpSocket):
else: else:
self.change_status(E_NETWORK, self.errorString()) self.change_status(E_NETWORK, self.errorString())
self.projectorUpdateIcons.emit() self.projectorUpdateIcons.emit()
if self.status_connect == E_NOT_CONNECTED:
self.abort()
self.reset_information()
return return
def send_command(self, cmd, opts='?', salt=None, queue=False): def send_command(self, cmd, opts='?', salt=None, queue=False):
@ -455,24 +468,18 @@ class PJLink1(QTcpSocket):
# Already there, so don't add # Already there, so don't add
log.debug('(%s) send_command(out="%s") Already in queue - skipping' % (self.ip, out.strip())) log.debug('(%s) send_command(out="%s") Already in queue - skipping' % (self.ip, out.strip()))
elif not queue and len(self.send_queue) == 0: elif not queue and len(self.send_queue) == 0:
return self._send_command(data=out)
return self._send_string(out)
else: else:
log.debug('(%s) send_command(out="%s") adding to queue' % (self.ip, out.strip())) log.debug('(%s) send_command(out="%s") adding to queue' % (self.ip, out.strip()))
self.send_queue.append(out) self.send_queue.append(out)
if not self.send_busy: self.projectorReceivedData.emit()
self.projectorReceivedData.emit()
log.debug('(%s) send_command(): send_busy is %s' % (self.ip, self.send_busy)) log.debug('(%s) send_command(): send_busy is %s' % (self.ip, self.send_busy))
if not self.send_busy: if not self.send_busy:
log.debug('(%s) send_command() calling _send_string()') log.debug('(%s) send_command() calling _send_string()')
self._send_string() self._send_command()
@pyqtSlot() @pyqtSlot()
def _send_command(self): def _send_command(self, data=None):
log.debug('Received projectorReceivedData signal')
return self._send_string()
def _send_string(self, data=None):
""" """
Socket interface to send data. If data=None, then check queue. Socket interface to send data. If data=None, then check queue.
@ -480,6 +487,7 @@ class PJLink1(QTcpSocket):
:returns: None :returns: None
""" """
log.debug('(%s) _send_string()' % self.ip) log.debug('(%s) _send_string()' % self.ip)
log.debug('(%s) _send_string(): Connection status: %s' % (self.ip, self.state()))
if self.state() != self.ConnectedState: if self.state() != self.ConnectedState:
log.debug('(%s) _send_string() Not connected - abort' % self.ip) log.debug('(%s) _send_string() Not connected - abort' % self.ip)
self.send_queue = [] self.send_queue = []
@ -502,6 +510,7 @@ class PJLink1(QTcpSocket):
self.send_busy = True self.send_busy = True
log.debug('(%s) _send_string(): Sending "%s"' % (self.ip, out.strip())) log.debug('(%s) _send_string(): Sending "%s"' % (self.ip, out.strip()))
log.debug('(%s) _send_string(): Queue = %s' % (self.ip, self.send_queue)) log.debug('(%s) _send_string(): Queue = %s' % (self.ip, self.send_queue))
self.socket_timer.start()
try: try:
self.projectorNetwork.emit(S_NETWORK_SENDING) self.projectorNetwork.emit(S_NETWORK_SENDING)
sent = self.write(out) sent = self.write(out)
@ -511,7 +520,7 @@ class PJLink1(QTcpSocket):
self.change_status(E_NETWORK, self.change_status(E_NETWORK,
translate('OpenLP.PJLink1', 'Error while sending data to projector')) translate('OpenLP.PJLink1', 'Error while sending data to projector'))
except SocketError as e: except SocketError as e:
self.disconnect_from_host() self.disconnect_from_host(abort=True)
self.changeStatus(E_NETWORK, '%s : %s' % (e.error(), e.errorString())) self.changeStatus(E_NETWORK, '%s : %s' % (e.error(), e.errorString()))
def process_command(self, cmd, data): def process_command(self, cmd, data):
@ -734,20 +743,25 @@ class PJLink1(QTcpSocket):
self.connectToHost(self.ip, self.port if type(self.port) is int else int(self.port)) self.connectToHost(self.ip, self.port if type(self.port) is int else int(self.port))
@pyqtSlot() @pyqtSlot()
def disconnect_from_host(self): def disconnect_from_host(self, abort=False):
""" """
Close socket and cleanup. Close socket and cleanup.
""" """
if self.state() != self.ConnectedState: if abort or self.state() != self.ConnectedState:
log.warn('(%s) disconnect_from_host(): Not connected - returning' % self.ip) if abort:
self.projectorUpdateIcons.emit() log.warn('(%s) disconnect_from_host(): Aborting connection' % self.ip)
return else:
log.warn('(%s) disconnect_from_host(): Not connected - returning' % self.ip)
self.reset_information()
self.disconnectFromHost() self.disconnectFromHost()
try: try:
self.readyRead.disconnect(self.get_data) self.readyRead.disconnect(self.get_data)
except TypeError: except TypeError:
pass pass
self.change_status(S_NOT_CONNECTED) if abort:
self.change_status(E_NOT_CONNECTED)
else:
self.change_status(S_NOT_CONNECTED)
self.reset_information() self.reset_information()
self.projectorUpdateIcons.emit() self.projectorUpdateIcons.emit()

View File

@ -487,6 +487,11 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ProjectorMa
projector.timer.timeout.disconnect(projector.link.poll_loop) projector.timer.timeout.disconnect(projector.link.poll_loop)
except (AttributeError, TypeError): except (AttributeError, TypeError):
pass pass
try:
projector.socket_timer.stop()
projector.socket_timer.timeout.disconnect(projector.link.socket_abort)
except (AttributeError, TypeError):
pass
projector.thread.quit() projector.thread.quit()
new_list = [] new_list = []
for item in self.projector_list: for item in self.projector_list:
@ -727,9 +732,14 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtGui.QWidget, Ui_ProjectorMa
timer.setInterval(self.poll_time) timer.setInterval(self.poll_time)
timer.timeout.connect(item.link.poll_loop) timer.timeout.connect(item.link.poll_loop)
item.timer = timer item.timer = timer
socket_timer = QtCore.QTimer(self)
socket_timer.setInterval(5000) # % second timer in case of brain-dead projectors
socket_timer.timeout.connect(item.link.socket_abort)
item.socket_timer = socket_timer
thread.start() thread.start()
item.thread = thread item.thread = thread
item.link.timer = timer item.link.timer = timer
item.link.socket_timer = socket_timer
item.link.widget = item.widget item.link.widget = item.widget
self.projector_list.append(item) self.projector_list.append(item)
if self.autostart: if self.autostart: