class HWTest: def __init__(self): test_mode = False self.e = Events(( 'Platform', 'CtrlTurn', 'CtrlPress', 'VolKnob', 'Audio', 'RemotePress', 'Streamer')) """ Setup the event callbacks """ self.e.VolKnob += self.VolumeChange # when the volume knob, remote or switch is changed self.e.CtrlTurn += self.SourceChange # when the control knob, remote or switch is pressed self.e.CtrlPress += self.defaultAction # when when the control knob is pressed start the menu options self.e.Platform += self.PlatformAction # when the system detects a change to be acted on , eg Shutdown self.e.RemotePress += self.RemoteAction # when the remote controller is pressed self.e.Audio += self.AudioAction # respond to a new sample, or audio silence self.e.Streamer += self.StreamerAction # respond to a new sample, or audio silence self.platform = Platform(self.e) if test_mode: self.display = self.platform.internaldisplay # this is used in test modes else: self.display = self.platform.frontdisplay self.platform.powerAudio('on') def defaultAction(self,e): print("HWTest.defaultAction> event", e) def VolumeChange(self, e='startVol'): print("VolumeChange> event", e) if e == 'vol_change': self.platform.detectVolChange() elif e =='mute': self.platform.mute() #mute the audio board elif e =='unmute': self.platform.unmute() #unmute the audio board def RemoteAction(self, e): print("RemoteAction: received event<%s>" % e) if e == 'volume_up': self.platform.volumeUp() elif e =='volume_down': self.platform.volumeDown() elif e =='mute': self.platform.toggleMute() elif e == 'shutdown': self.PlatformAction('shutdown') elif e =='forward': self.events.CtrlTurn('clockwise') elif e =='back': self.events.CtrlTurn('anticlockwise') elif e =='stop': self.events.CtrlPress('down') elif e =='pause': self.platform.streamerpause() elif e =='play': self.platform.streamerplay() else: print("Controller.RemoteAction> unknown event <%s>" % e) def SourceChange(self, e): print("SourceChange> event", e) if e == 'clockwise': self.platform.nextSource() elif e == 'anticlockwise': self.platform.prevSource() def AudioAction(self, e): print("AudioAction> event ",e) if e == 'silence_detected': self.platform.mute() elif e == 'signal_detected': self.platform.unmute() elif e == 'capture': # if self.audioready>0: # print("Controller.AudioAction> %d sample buffer underrun, dump old data " % self.audioready) self.platform.process() self.audioready +=1 def PlatformAction(self, e='error'): print("PlatformAction> event ", e) def StreamerAction(self, e): print("Controller.StreamerAction> event ", e) if e == 'new_track' or e == 'start': print("Controller.StreamerAction> new track - pop up display ", e) elif e == 'stop': print("Controller.StreamerAction> track stopped - display nothing new") self.platform.clear_track() elif e =='trackNotified': print("Controller.StreamerAction> track notification timeout") """ use the platform API to test each of the HW functions """ def main(self): logic = self.platform.sourceLogic() chlogic = self.platform.chLogic() status = self.platform.readAudioBoardState() chchanged = True # display status first time around while True: line = GetLine() if line: print("pressed>",line) if line == "q": return elif line >= "0" and line <= "5": ch = int(line) print("Channel=", ch, " source=", logic[ch]) self.platform.setSource(logic[ch]) chchanged = True elif line == "g": self.platform.gain(not status['gain']) chchanged = True elif line == "m": self.platform.volKnobEvent(RotaryEncoder.BUTTONDOWN) chchanged = True elif line == "s": print("AudioBoard>", self.platform.readAudioBoardState()) chchanged = True self.display.draw_status(self.platform.volume_db, \ self.platform.activeSourceText, \ self.platform.chid, \ self.platform.muteState, self.platform.gainState, self.platform.phonesdetectState) # this will just be the diagnostics in time time.sleep(0.005)
class Controller: """ Main control logic managing events and callbacks """ # timer constants volchangeTime = 2.0 srcChangeTime = 2.0 iconMoveTime = 0.2 menuTime = 7.0 welcomeTime = 3.0 screensaveTime= 6.0 shutdownTime = 1.0 # slight pause to ensure the shutdown screen is displayed trackchangeTime= 7.0 recordTime = 7.0 loopdelay = 0.0001 def __init__(self, test_mode=False): self.test_mode = test_mode """ Setup the events """ self.events = Events(( 'Platform', 'CtrlTurn', 'CtrlPress', 'VolKnob', 'Audio', 'RemotePress', 'Streamer')) """ Setup the HW, Displays and audio processing """ self.platform = Platform(self.events) if test_mode: display = self.platform.internaldisplay # this is used in test modes else: display = self.platform.frontdisplay """ Setup the Timer events """ self.volChangeTimer = Timer(Controller.volchangeTime, self.VolumeChange, ['stopVol'], 'volChangeTimer' ) self.srcChangeTimer = Timer(Controller.srcChangeTime, self.SourceChange, ['stopCtrl'], 'srcChangeTimer' ) self.iconMoveTimer = Timer(Controller.iconMoveTime, self.MoveIcon, ['iconTimeout'] , 'iconMoveTimer') self.menuTimer = Timer(Controller.menuTime, self.MenuAction, ['endmenu'] , 'menuTimer') self.screensaveTimer = Timer(Controller.screensaveTime, self.ScreenSave, ['start_screensave'] , 'screensaveTimer') self.welcomeTimer = Timer(Controller.welcomeTime, self.Welcomed, ['welcomeTimeout'], 'welcomeTimer' ) self.shutdownTimer = Timer(Controller.shutdownTime, self.platform.poweroff, ['shutdownTimeout'], 'shutdownTimer' ) self.trackChangeTimer= Timer(Controller.trackchangeTime, self.StreamerAction, ['trackNotified'], 'trackChangeTimer') self.recordTimer = Timer(Controller.recordTime, self.AudioAction, ['recordNotified'], 'recordTimer') """ Setup the event callbacks """ self.events.VolKnob += self.VolumeChange # when the volume knob, remote or switch is changed self.events.CtrlTurn += self.SourceChange # when the control knob, remote or switch is pressed self.events.CtrlPress += self.MenuAction # when when the control knob is pressed start the menu options self.events.Platform += self.PlatformAction # when the system detects a change to be acted on , eg Shutdown self.events.RemotePress += self.RemoteAction # when the remote controller is pressed self.events.Audio += self.AudioAction # respond to a new sample, or audio silence self.events.Streamer += self.StreamerAction # respond to a new sample, or audio silence """Set up the screen for inital Mode""" self.baseScreen = 'spectrum' self.preScreenSaver = self.baseScreen """ Set up the screen objects to be used """ self.screens = {} # dict for the screen objects self.screenList = {'main' : { 'class' : MainScreen, 'base' : 'yes', 'title' : '1/3 Oct Spectrum Analyser, Dial & source' }, 'start' : { 'class' : WelcomeScreen, 'base' : 'no', 'title' : 'welcome' }, 'volChange' : { 'class' : VolChangeScreen, 'base' : 'no', 'title' : 'Incidental volume change indicator' }, # 'fullSpectrum' : { 'class' : FullSpectrumScreen, 'base' : 'yes', 'title' : '1/6 Octave Spectrum Analyser' }, 'StreamerMeta' : { 'class' : PlayerScreen, 'base' : 'yes', 'title' : 'Track data, volume and source' }, 'trackChange' : { 'class' : TrackScreen, 'base' : 'no', 'title' : 'New Track data' }, 'stereoSpectrum' :{'class' : StereoSpectrumScreen, 'base' : 'yes', 'title' : 'Stereo Spectrum Analyser' }, 'VUMeters' : { 'class' : MetersAScreen, 'base' : 'yes', 'title' : 'Stereo VU Meters' }, 'shutdown' : { 'class' : ShutdownScreen, 'base' : 'no', 'title' : 'end' }, 'sourceVol' : { 'class' : SourceVolScreen,'base' : 'no', 'title' : 'Source Icons & Volume Dial' }, 'screenTitle' : { 'class' : ScreenTitle, 'base' : 'no', 'title' : 'Displays screen titles for menu' }, 'screenSaver' : { 'class' : ScreenSaver, 'base' : 'no', 'title' : 'all gone quiet' }, 'sourceVUVol' : { 'class' : SourceVUVolScreen, 'base' : 'yes', 'title' : ' Source Icons, VU & Vol Dial' }, 'spectrum' : { 'class' : SpectrumScreen, 'base' : 'yes', 'title' : ' left channel spectrum and volume'}, 'VUScreen' : { 'class' : VUScreen, 'base' : 'yes', 'title' : ' horizontal VU'}, 'VUVertScreen' : { 'class' : VUVScreen, 'base' : 'yes', 'title' : ' vertical VU'}, 'RecordScreen' : { 'class' : RecordingScreen, 'base' : 'no', 'title' : ' recording'}, 'recordFinishScreen' : { 'class' : RecordFinishScreen, 'base' : 'no', 'title' : ' record_end'} } for i, (name, c) in enumerate(self.screenList.items()): print(("Controller.__init__> screen %s %s" % (name,c))) self.screens.update( {name : c['class'](self.platform, display) }) print(("Controller.__init__> screen %s initialised OK" % name)) """ Menu functionality """ self.menuMode = False menuSequence = [] for name, c in self.screenList.items(): if c['base'] == 'yes': menuSequence.append( name ) self.screenmenu = ListNext(menuSequence, self.baseScreen) print("Controller.__init__> all OK", self.screenmenu) def startAction(self): self.welcomeTimer.start() self.setScreen('start') self.audioready = 0 self.platform.start_hw() def stopAction(self): self.platform.stop() def checkScreen(self, basis): """ return the current screen object to run """ Timer.checkTimers() if self.menuMode: self.screens['screenTitle'].draw( basis, self.screenList[self.activeScreen]['title'] ) return self.screens[self.activeScreen] def setScreen(self, s): self.activeScreen = s def VolumeChange(self, e='startVol'): if e == 'vol_change': self.volChangeTimer.start() self.activeScreen= 'volChange' self.platform.detectVolChange() elif e =='stopVol': self.activeScreen= self.baseScreen elif e =='mute': self.platform.mute() #mute the audio board elif e =='unmute': self.platform.unmute() #unmute the audio board elif e =='togglemute': self.platform.invertMute() #unmute the audio board elif e =='Button up': #detected that the mute button has raised - no action pass else: print("Controller.setVolumeChange> unknown event", e) def RemoteAction(self, e): print("Controller.RemoteAction: received event<%s>" % e) if e == 'volume_up': self.platform.volumeUp() elif e =='volume_down': self.platform.volumeDown() elif e =='mute': self.platform.toggleMute() elif e == 'shutdown': self.PlatformAction('shutdown') elif e =='forward': self.events.CtrlTurn('clockwise') elif e =='back': self.events.CtrlTurn('anticlockwise') elif e =='stop': self.events.CtrlPress('down') elif e =='pause': self.platform.streamerpause() elif e =='record': if self.platform.recordingState: self.platform.stop_recording() else: self.activeScreen= 'RecordScreen' self.platform.start_recording() else: print("Controller.RemoteAction> unknown event <%s>" % e) def MoveIcon(self,e): if self.activeScreen== 'sourceVol' or self.activeScreen== 'sourceVUVol': # print "MoveIcon>", e, self.activeScreen if e == 'iconTimeout': self.platform.nextIcon() self.iconMoveTimer.start() elif e == 'startIcons': self.iconMoveTimer.start() # else: # self.iconMoveTimer.cancel() def SourceChange(self, e): if e == 'clockwise': self.activeScreen= 'sourceVol' self.MoveIcon('startIcons') # get the icons moving is not already self.srcChangeTimer.start() self.events.CtrlPress -= self.MenuAction # self.platform.mute() self.platform.nextSource() elif e == 'anticlockwise': self.activeScreen= 'sourceVol' self.MoveIcon('startIcons') # get the icons moving is not already self.srcChangeTimer.start() self.events.CtrlPress -= self.MenuAction # self.platform.mute() self.platform.prevSource() elif e =='stopCtrl': self.activeScreen = self.baseScreen self.events.CtrlPress += self.MenuAction else: print("Controller.SourceChange> unknown event", e) def Welcomed(self, e): self.activeScreen= self.baseScreen def ScreenSave(self, e): print("Platform: ScreenSave: event %s, screen %s" % (e,self.activeScreen)) if e == 'time_screensave': if not self.screensaveTimer.is_alive(): self.screensaveTimer.start() elif e == 'cancel_screensave': self.screensaveTimer.cancel() if self.activeScreen == 'screenSaver': self.activeScreen = self.preScreenSaver elif e == 'start_screensave': if self.activeScreen != 'screenSaver': self.preScreenSaver = self.activeScreen self.activeScreen = 'screenSaver' else: print(("Platform: ScreenSave: event not recognised ", e)) def MenuAction(self, e): if e == 'startmenu': self.startMenu() elif e == 'down': if self.menuMode: self.endMenu() else: self.startMenu() elif e == 'endmenu': self.endMenu() elif e == 'anticlockwise': self.menuTimer.start() self.menuPrev() self.MoveIcon('startIcons') # get the icons moving is not already # print "Controller.MenuAction> prev screen", self.activeScreen if e == 'clockwise': self.menuTimer.start() self.menuNext() self.MoveIcon('startIcons') # get the icons moving is not already # print "Controller.MenuAction> next screen", self.activeScreen def AudioAction(self, e): if e == 'silence_detected': self.platform.mute() self.ScreenSave('time_screensave') elif e == 'signal_detected': self.platform.unmute() self.ScreenSave('cancel_screensave') elif e == 'capture': # if self.audioready>0: # print("Controller.AudioAction> %d sample buffer underrun, dump old data " % self.audioready) self.platform.process() self.audioready +=1 elif e == 'recording_stopped': self.recordTimer.start() self.activeScreen= 'recordFinishScreen' elif e == 'recordNotified': self.activeScreen= self.baseScreen else: print("Controller.AudioAction> unknown event ",e) def startMenu(self): self.menuMode = True self.events.CtrlTurn -= self.SourceChange #when the control knob or switch is pressed self.events.CtrlTurn += self.MenuAction #when the control knob or switch is pressed self.menuTimer.start() def endMenu(self): self.menuMode = False self.menuTimer.cancel() self.events.CtrlTurn += self.SourceChange #when the control knob or switch is pressed self.events.CtrlTurn -= self.MenuAction #when the control knob or switch is pressed def menuPrev(self): self.baseScreen = self.screenmenu.prev self.activeScreen = self.baseScreen print("Controller.menuPrev> active screen %s" % (self.activeScreen)) return self.screenmenu.curr def menuNext(self): self.baseScreen = self.screenmenu.next self.activeScreen = self.baseScreen print("Controller.menuPrev> active screen %s" % (self.activeScreen)) return self.screenmenu.curr def SystemChange(self, e='error'): print("Controller.SystemChange> event ", e) def PlatformAction(self, e='error'): if e == 'shutdown': self.activeScreen= 'shutdown' Timer.cancel_all() self.shutdownTimer.start() print("Controller.Platform> event ", e) elif e == 'phones_in': self.platform.mute() elif e == 'phones_out': self.platform.unmute() elif e == 'exit': exit() # this is a debug mode to terminate execution from the keyboard def StreamerAction(self, e): print("Controller.StreamerAction> event ", e) if e == 'new_track' or e == 'start': print("Controller.StreamerAction> new track - pop up display ", e) self.trackChangeTimer.start() self.activeScreen= 'trackChange' elif e == 'stop': print("Controller.StreamerAction> track stopped - display nothing new") self.platform.clear_track() elif e =='trackNotified': print("Controller.StreamerAction> track notification timeout") self.activeScreen= self.baseScreen else: print("Controller.StreamerAction> unknown event ", e) """ This is where execution starts.. configure the HW & Display objects set up the event handling which controls the display Mode(ie which screen) run the Display in an infinite loop """ def run(self): print("Controller.run> preDAC startup configured at ", time.gmtime()) self.startAction() self.audioready = 0 t = time.time() """ loop around updating the screen and responding to events """ while(True): # self.platform.captureAudio() # should become event driven """ return the current screen object to run """ Timer.checkTimers() self.platform.checkKeys() if self.platform.nohw: self.audioready = 1 if self.audioready>0: screen = self.screens[self.activeScreen] if self.test_mode: self.platform.internaldisplay.draw(screen) # this will just be the diagnostics in time # self.platform.internaldisplay.draw_status(self.platform.volume_db, \ # self.platform.activeSourceText, \ # self.platform.chid, \ # self.platform.muteState, self.platform.gainState, self.platform.phonesdetectState) # this will just be the diagnostics in time else: self.platform.frontdisplay.draw(screen) # if self.platform.internaldisplay is not None: # self.platform.internaldisplay.draw_status(self.platform.volume_db, \ # self.platform.activeSourceText, \ # self.platform.chid, \ # self.platform.muteState, self.platform.gainState, self.platform.phonesdetectState) # this will just be the diagnostics in time self.audioready = 0 # print("run> waited for audio: waited", 1000*(time.time()-t)) t = time.time() else: # print("run> waiting for audio: waited", 1000*(time.time()-t)) time.sleep(Controller.loopdelay) print("Controller.run> terminated")