Ejemplo n.º 1
0
class Executive:
	'''The main podplayer looping structure. '''
	def __init__(self):
		self.logger = logging.getLogger(__name__)
		self.logger.info("Starting executive class")
		#initialise the variables
		self.die = False
		self.next = False
		self.stop = False
		self.volup = False
		self.voldown = False
		self.chgvol_flag = False
		self.maxelapsed = 0
		self.error_string = ''

	def startup(self, verbosity):
		'''Initialisation for the objects that have variable startup behaviour'''
		self.myInfoDisplay = infodisplay.InfoDisplay()
#		self.myKey = keyboardpoller.KeyboardPoller()
#		self.myKey.start()
		try:
			if keys.board == 'emulator':
				import gpio_emulator
				import mpc_emulator
				self.myGpio = gpio_emulator.Gpio()
				self.myMpc = mpc_emulator.Mpc()
				host = 'dummy host'
				self.programmename = 'dummy prog\nTest\nSecond row'
			if keys.board == 'lcd':
				host = 'rotary host'
				import rotary
				self.myGpio = rotary.Rotary()
				self.myVol = rotary.Rotary(1)
				self.myMpc = mpc2.Mpc()
				print 'mpc has been setup'
#				count = self.myMpc.podcounter()
				self.mySystem = System()
				host = self.mySystem.return_hostname()
				print 'Hostname:', host
				self.programmename = self.myMpc.progname()
				print 'Prog:', self.programmename
#				remaining = self.myMpc.check_time_left()
			else:
				from mpc2 import Mpc
				import gpio
				self.myGpio = gpio.Gpio()
				self.myMpc = Mpc(False, True)		# Test mode, podmode
				count = self.myMpc.podcounter()
				self.mySystem = System()
				host = self.mySystem.return_hostname()
				self.programmename = self.myMpc.progname()
				remaining = self.myMpc.check_time_left()
		except:
			self.cleanup('Failed to start gpio')
#		self.myInfoDisplay.writerow(0,host)
#		self.myInfoDisplay.update_display()
		self.myInfoDisplay.prog = self.programmename
		self.myInfoDisplay.start()
		time.sleep(2)
		self.myInfoDisplay.prog = self.myMpc.progname()
		self.ending = False
		self.t = threading.Timer(AUDIOTIMEOUT, self.audiofunc)
		self.t.start()
		self.t.name = 'audiot'
		print threading.enumerate()		# helps debug
		print 'Thread count: ', threading.active_count()
#		self.check_threads()
		if False:								# set to true for testing
			self.cleanup('Forced cleanup')
		self.dt = threading.Timer(DEBUGTIMEOUT, self.debugfunc)
#		self.dt.start()
		self.dt.name = 'debugt'
		
	def check_threads(self):
		# a routine to check all the threads that should be started actually are.
		if myInfoDisplay.is_alive():
			print 'Infodisplay is alive'
		else:
			print 'Infodisplay is dead'
		for threadname in ('lcd', 'rotary'):
			if not threadname.is_alive():
				print 'Missing thread: ', threadname
		

	def audiofunc(self):
		'''Called by the audio timeout Timer. Implements the actual timeout function.'''
		print 'Timeout'
		self.logger.info('Audio timeout')
		self.myInfoDisplay.writerow(0,'Timeout              ')
		self.myMpc.stop()
		self.myInfoDisplay.prog = 'Timeout               '
		return(0)

	def reset_audio_timer(self):
		'''Resets the audio timeout Timer. Called by each button push.'''
		self.t.cancel()
		time.sleep(1)
		if not self.ending:
			self.t = threading.Timer(AUDIOTIMEOUT, self.audiofunc)
			self.t.start()
			self.t.name = 'audiot'

	def debugfunc(self):
		'''Implements the actual timeout function.'''
		print 'Debug info...'
		print threading.enumerate()
		self.logger.info('Debug info')
		if not self.ending:
			self.dt = threading.Timer(DEBUGTIMEOUT, self.debugfunc)
			self.dt.start()
			self.dt.name = 'debugt'
		return(0)

	def cleanup(self, string):
		self.ending = True
		print 'Cleaning up:', string
		self.logger.warning('Cleanup: '+string)
		try:
			self.t.cancel()					# stop the audio timer
		except:
			print 'Audio timer had not started'
		try:
			self.dt.cancel					# stop the debug timer
		except:
			print 'Debug timer had not started'
		self.myInfoDisplay.clear()
		self.myInfoDisplay.writerow(0,string)
		self.myInfoDisplay.writerow(1, self.error_string)
		time.sleep(2)
		self.myInfoDisplay.cleanup()	# needed to stop weather polling.
#		self.myKey.cleanup()
		self.logger.error(string)
		self.myMpc.cleanup()
		self.myGpio.cleanup()
		self.myVol.cleanup()
		time.sleep(2)
		print threading.enumerate()		# should just show the main thread
#		self.myInfoDisplay.writerow(2, '                    ')
		self.logger.warning('Finished exec cleanup')
		print 'All done'
		sys.exit(0)

	def chk_key(self):
		'''Act on keyboard presses.'''
		if self.myKey.command:
			self.myKey.command = False
			if self.myKey.exit:
				print 'Exit key'
				self.die = True
				self.myKey.exit = False
			if self.myKey.next:
				print 'Next key'
				self.myKey.next = False
				self.next = True
			if self.myKey.stop:
				print 'Stop key'
				self.myKey.stop = False
				self.stop = True
			if self.myKey.volup:
				print 'Volup key'
				self.myKey.volup = False
				self.volup = True
			if self.myKey.voldown:
				print 'Voldown key'
				self.myKey.voldown = False
				self.voldown = True
			return(True)
		else:
			return(False)

	def master_loop(self):
		'''Continuously cycle through all the possible events.'''
		self.lasttime = time.time()		# has to be here to avoid long initial delay showing.
		while True:
			time.sleep(.2)
#			self.chk_key()				# poll to see if there has been a key pressed
			if self.myMpc.chk_station_load():
				self.cleanup('Station load')
			try:
				if self.die == True:
					raise KeyboardInterrupt
				time.sleep(.2)			# keep this inside try so that ctrl-c works here.
				reboot = self.process_button_presses()
				if reboot == 1:
					self.cleanup('Reboot')		# need to add to this!
			except KeyboardInterrupt:
				self.cleanup('Keyboard interrupt')
			except:			# all other errors - should never get here
				print "Unexpected error:", sys.exc_info()
				self.cleanup('Master loop error')

	def _show_time_taken(self):
		now = time.time()
		elapsed = now - self.lasttime
		self.myInfoDisplay.show_timings(elapsed,self.maxelapsed)
		if elapsed > self.maxelapsed:
			self.maxelapsed = elapsed
		self.lasttime = now
		return(0)

	def _show_next_station(self):
		prog = self.myMpc.next_station()
		self.myInfoDisplay.show_next_station(prog)
		return(0)

	def get_station_value(self):
		NewCounter = self.myGpio.Rotary_counter         # get counter value
		self.myGpio.Rotary_counter = 0                  # RESET IT TO 0
		if (NewCounter > 0):               # Counter has CHANGED
			return(BUTTONNEXT)
		if (NewCounter < 0):               # Counter has CHANGED
			return(BUTTONPREV)
		return(0)
		
	def get_volume_value(self):
		NewCounter = self.myVol.Rotary_counter         # get counter value
		self.myVol.Rotary_counter = 0                  # RESET IT TO 0
		if (NewCounter > 0):               # Counter has CHANGED
			return(BUTTONVOLUP)
		if (NewCounter < 0):               # Counter has CHANGED
			return(BUTTONVOLDOWN)
		return(0)

	def process_button_presses(self):
		'''Poll for each of the button presses and return the new prog name.'''
#		try:
		if keys.board == 'lcd':						# this has the rotary encoder
			if self.myGpio.switch == True:
				button = BUTTONHALT
				return(1)
			button = self.get_station_value()
			if button == 0:
				button = self.get_volume_value()
		else:										# push buttons
			button = self._processbuttons()
		if button == 0:
			return(0)
		else:
			self.reset_audio_timer()				# reset audio timeout since button pressed
			if button == BUTTONMODE:
				self.myMpc.switchmode()
			elif button == BUTTONNEXT:
				if self.myMpc.next() == -1:
					return('No pods left!')
				self.myInfoDisplay.prog = self.myMpc.progname()	# displayed by background task
				self.myInfoDisplay.update_display()
			elif button == BUTTONPREV:
				if self.myMpc.prev() == -1:
					return('No pods left!')
				self.myInfoDisplay.prog = self.myMpc.progname()	# displayed by background task
				self.myInfoDisplay.update_display()
			elif button == BUTTONSTOP:
				self.myMpc.toggle()
				self.myInfoDisplay.show_prog_info(self.myMpc.progname())
			elif button == BUTTONREBOOT:
				print 'Rebooting...'
				self.myMpc.stop()
				self.myInfoDisplay.writerow(1, 'Rebooting...     ')
				time.sleep(2)
				p = subprocess.call(['reboot'])
				return(1)
			elif button == BUTTONHALT:
				print 'Halting...'
				self.myMpc.stop()
				self.myInfoDisplay.writerow(1, 'Halting...      ')
				time.sleep(2)
				p = subprocess.call(['halt'])
				return(1)
			elif button == BUTTONVOLUP:
				v = self.myMpc.chgvol(+1)
				self.create_vol_bar(v)
			elif button == BUTTONVOLDOWN:
				v = self.myMpc.chgvol(-1)
				self.create_vol_bar(v)
#		except:
#			self.logger.warning('Error in process_button_presses: Value='+str(button))
#			return(-1)
		button = 0
		return(0)

	def _processbuttons(self):
		'''Called by process_button_presses. Expects callback processes to have
			already set the Next and Stop states.
			This routine is relatively quick. Slower parts are in the parent.'''
		button=0
		if self.myGpio.next or self.next:
			self.logger.info("Button pressed next")
			self.myGpio.next = False
			self.next = False
			button = BUTTONNEXT
		if self.myGpio.stop or self.stop:
			self.logger.info("Button pressed stop")
			self.myGpio.stop = False
			self.stop = False
			button = BUTTONSTOP
		if (self.myGpio.vol == 1) or self.volup:
			self.logger.info("Button pressed vol up")
			self.myGpio.vol=0
			self.volup = False
			button = BUTTONVOLUP
		if (self.myGpio.vol == -1) or self.voldown:
			self.logger.info("Button pressed vol down")
			self.myGpio.vol=0
			self.voldown = False
			button = BUTTONVOLDOWN
#		self.logger.info("processbuttons: "+str(button))
		return(button)

	def clear_vol_flag(self):
		self.myInfoDisplay.chgvol_flag = False

	def create_vol_bar(self, volume):
		'''Draw the volume bar on the display.'''
		self.logger.info('Create vol bar '+str(volume))
		self.myInfoDisplay.chgvol_flag = True
		try:
#			self.myTimeout.setVolumeTimeout()
#			self.temp_progname = self.programmename
#			self.programmename = ''
			self.myInfoDisplay.vol_string = ''
			for i in range(0, int(volume), 5):		# add a char every 5%
				self.myInfoDisplay.vol_string += ">"
			self.myInfoDisplay.vol_string += "      "
#			self.myInfoDisplay.displayvol(self.programmename)
			if not self.ending:
				self.volt = threading.Timer(10, self.clear_vol_flag)	# clear display after 10s
				self.volt.start()
				self.volt.name = 'volflag'
		except:
			print ' trouble at t mill'
		return(0)

	def _show_vol_bar(self, volume):
		'''Draw the volume bar on the display.'''
		self.logger.info('vol bar '+str(volume))
		self.chgvol_flag = 1
		try:
			self.myTimeout.setVolumeTimeout()
			self.temp_progname = self.programmename
			self.programmename = ''
			for i in range(0, int(volume), 5):		# add a char every 5%
				self.programmename += ">"
			self.programmename += "      "
			self.myInfoDisplay.displayvol(self.programmename)
		except:
			print ' trouble at t mill'
		return(0)

	def self_test(self):
		print 'Self test not yet implemented'
		return(0)