예제 #1
0
def main():
    """
    The main function for the AutoHeadFix program.

    It initializes or loads settings and configurations, then endlessly loops running entries and head fix trials
    Ctrl-C is used to enter a menu-driven mode where settings can be altered.
    """
    try:
        # load general settings for this cage, mostly hardware pinouts
        # things not expected to change often - there is only one AHFconfig.jsn file, in the enclosing folder
        cageSettings = AHF_CageSet()
        #print (cageSettings)
        # get settings that may vary by experiment, including rewarder, camera parameters, and stimulator
        # More than one of these files can exist, and the user needs to choose one or make one
        # we will add some other  variables to expSettings so we can pass them as a single argument to functions
        # logFP, statsFP, dateStr, dayFolderPath, doHeadFix,
        # configFile can be specified if launched from command line, eg, sudo python3 myconfig or sudo python3 AHFexp_myconfig.jsn
        configFile = None
        if argv.__len__() > 1:
            configFile = argv[1]
        expSettings = AHF_Settings(configFile)
        # nextDay starts tomorrow at KDAYSTARTHOUR
        #nextDay = (int((time() - timezone)/KSECSPERDAY) + 1) * KSECSPERDAY + timezone + (KDAYSTARTHOUR * KSECSPERHOUR)
        nextDay = ((int(
            (time() - timezone + localtime().tm_isdst * 3600) / KSECSPERDAY)) *
                   KSECSPERDAY) + timezone - (localtime().tm_isdst * 3600
                                              ) + KSECSPERDAY + KDAYSTARTHOUR
        # Create folders where the files for today will be stored
        makeDayFolderPath(expSettings, cageSettings)
        # initialize mice with zero mice
        mice = Mice()
        # make daily Log files and quick stats file
        makeLogFile(expSettings, cageSettings)
        makeQuickStatsFile(expSettings, cageSettings, mice)
        #Generate h5 file to store mouse-individual data
        makeH5File(expSettings, cageSettings, mice)
        updateStats(expSettings.statsFP, mice)
        backup_H5(expSettings, cageSettings)
        # set up the GPIO pins for each for their respective functionalities.
        GPIO.setmode(GPIO.BCM)
        GPIO.setwarnings(False)
        GPIO.setup(cageSettings.ledPin, GPIO.OUT,
                   initial=GPIO.LOW)  # turns on brain illumination LED
        GPIO.setup(cageSettings.led2Pin, GPIO.OUT,
                   initial=GPIO.LOW)  # turns on masking stim LED2
        GPIO.setup(cageSettings.tirPin,
                   GPIO.IN)  # Tag-in-range output from RFID tag reader
        GPIO.setup(cageSettings.contactPin,
                   GPIO.IN,
                   pull_up_down=getattr(GPIO,
                                        "PUD_" + cageSettings.contactPUD))
        if cageSettings.contactPolarity == 'RISING':
            expSettings.contactEdge = GPIO.RISING
            expSettings.noContactEdge = GPIO.FALLING
            expSettings.contactState = GPIO.HIGH
            expSettings.noContactState = GPIO.LOW
        else:
            expSettings.contactEdge = GPIO.FALLING
            expSettings.noContactEdge = GPIO.RISING
            expSettings.contactState = GPIO.LOW
            expSettings.noContactState = GPIO.HIGH
        # make head fixer - does its own GPIO initialization from info in cageSettings
        headFixer = AHF_HeadFixer.get_class(
            cageSettings.headFixer)(cageSettings)
        # make a rewarder
        rewarder = AHF_Rewarder(30e-03, cageSettings.rewardPin)
        rewarder.addToDict('entrance', expSettings.entranceRewardTime)
        rewarder.addToDict('task', expSettings.taskRewardTime)
        # make a notifier object
        if expSettings.hasTextMsg == True:
            notifier = AHF_Notifier(cageSettings.cageID, expSettings.phoneList)
        else:
            notifier = None
        # make RFID reader
        tagReader = TagReader(cageSettings.serialPort, False, None)
        # configure camera
        camera = AHF_Camera(expSettings.camParamsDict)
        # make UDP Trigger
        if expSettings.hasUDP == True:
            UDPTrigger = AHF_UDPTrig(expSettings.UDPList)
            print(UDPTrigger)
        else:
            UDPTrigger = None
        # make a lick detector
        simpleLogger = Simple_Logger(expSettings.logFP)
        lickDetector = AHF_LickDetector((0, 1), 26, simpleLogger)
        sleep(1)
        lickDetector.start_logging()
        # make stimulator(s)
        stimulator = [
            AHF_Stimulator.get_class(i)(cageSettings, expSettings, rewarder,
                                        lickDetector, camera)
            for i in expSettings.stimulator
        ]
        #Stimdict is chosen from the first stimulator
        expSettings.stimDict = stimulator[0].configDict
        # Entry beam breaker
        if cageSettings.hasEntryBB == True:
            GPIO.setup(cageSettings.entryBBpin,
                       GPIO.IN,
                       pull_up_down=GPIO.PUD_UP)
            GPIO.add_event_detect(cageSettings.entryBBpin, GPIO.BOTH,
                                  entryBBCallback)
            #GPIO.add_event_callback (cageSettings.entryBBpin, entryBBCallback)
            gTubePanicTime = time() + 25920000  # a month from now.
            gTubeMaxTime = expSettings.inChamberTimeLimit
    except Exception as anError:
        print('Unexpected error starting AutoHeadFix:', str(anError))
        raise anError
        exit(0)
    try:
        print('Waiting for a mouse...')
        while True:  #start main loop
            try:
                # wait for mouse entry, with occasional timeout to catch keyboard interrupt
                GPIO.wait_for_edge(
                    cageSettings.tirPin, GPIO.RISING, timeout=kTIMEOUTmS
                )  # wait for entry based on Tag-in-range pin
                if (GPIO.input(cageSettings.tirPin) == GPIO.HIGH):
                    try:
                        tag = tagReader.readTag()
                    except (IOError, ValueError):
                        tagReader.clearBuffer()
                        continue
                    entryTime = time()
                    if cageSettings.hasEntryBB == True:
                        GPIO.remove_event_detect(cageSettings.entryBBpin)
                    thisMouse = mice.getMouseFromTag(tag)
                    if thisMouse is None:
                        # try to open mouse config file to initialize mouse data
                        thisMouse = Mouse(tag, 1, 0, 0, 0, 0, 0)
                        mice.addMouse(thisMouse, expSettings.statsFP)
                    writeToLogFile(expSettings.logFP, thisMouse, 'entry')
                    thisMouse.entries += 1
                    # if we have entrance reward, first wait for entrance reward or first head-fix, which countermands entry reward
                    if thisMouse.entranceRewards < expSettings.maxEntryRewards:
                        giveEntranceReward = True
                        expSettings.doHeadFix = expSettings.propHeadFix > random(
                        )
                        while GPIO.input(
                                cageSettings.tirPin) == GPIO.HIGH and time(
                                ) < (entryTime + expSettings.entryRewardDelay):
                            GPIO.wait_for_edge(cageSettings.contactPin,
                                               expSettings.contactEdge,
                                               timeout=kTIMEOUTmS)
                            if (GPIO.input(cageSettings.contactPin) ==
                                    expSettings.contactState):
                                runTrial(thisMouse, expSettings, cageSettings,
                                         rewarder, headFixer,
                                         stimulator[thisMouse.stimType],
                                         UDPTrigger)
                                giveEntranceReward = False
                                break
                        if (GPIO.input(cageSettings.tirPin)
                                == GPIO.HIGH) and giveEntranceReward == True:
                            thisMouse.reward(
                                rewarder, 'entrance'
                            )  # entrance reward was not countermanded by an early headfix
                            writeToLogFile(expSettings.logFP, thisMouse,
                                           'entryReward')
                    # wait for contacts and run trials till mouse exits or time in chamber exceeded
                    expSettings.doHeadFix = expSettings.propHeadFix > random()
                    while GPIO.input(
                            cageSettings.tirPin) == GPIO.HIGH and time(
                            ) < entryTime + expSettings.inChamberTimeLimit:
                        if (GPIO.input(cageSettings.contactPin) ==
                                expSettings.noContactState):
                            GPIO.wait_for_edge(cageSettings.contactPin,
                                               expSettings.contactEdge,
                                               timeout=kTIMEOUTmS)
                        if (GPIO.input(cageSettings.contactPin) ==
                                expSettings.contactState):
                            runTrial(thisMouse, expSettings, cageSettings,
                                     rewarder, headFixer,
                                     stimulator[thisMouse.stimType],
                                     UDPTrigger)
                            expSettings.doHeadFix = expSettings.propHeadFix > random(
                            )  # set doHeadFix for next contact
                    # either mouse left the chamber or has been in chamber too long
                    if GPIO.input(cageSettings.tirPin) == GPIO.HIGH and time(
                    ) > entryTime + expSettings.inChamberTimeLimit:
                        # explictly turn off pistons, though they should be off at end of trial
                        headFixer.releaseMouse()
                        if expSettings.hasTextMsg == True:
                            notifier.notify(thisMouse.tag,
                                            (time() - entryTime), True)
                        # wait for mouse to leave chamber, with no timeout, unless it left while we did last 3 lines
                        if GPIO.input(cageSettings.tirPin) == GPIO.HIGH:
                            GPIO.wait_for_edge(cageSettings.tirPin,
                                               GPIO.FALLING)
                        if expSettings.hasTextMsg == True:
                            notifier.notify(thisMouse.tag,
                                            (time() - entryTime), False)
                    tagReader.clearBuffer()
                    if cageSettings.hasEntryBB == True:
                        #GPIO.setup (cageSettings.entryBBpin, GPIO.IN, pull_up_down = GPIO.PUD_UP)
                        GPIO.add_event_detect(cageSettings.entryBBpin,
                                              GPIO.BOTH, entryBBCallback)
                    # after exit, update stats
                    writeToLogFile(expSettings.logFP, thisMouse, 'exit')
                    updateH5File(expSettings, cageSettings, mice, stimulator)
                    updateStats(expSettings.statsFP, mice, thisMouse)
                    # after each exit check for a new day
                    if time() > nextDay:
                        # stop lick logging so we dont write to file when it is closed
                        lickDetector.stop_logging()
                        mice.show()
                        writeToLogFile(expSettings.logFP, None, 'SeshEnd')
                        expSettings.logFP.close()
                        expSettings.statsFP.close()
                        makeDayFolderPath(expSettings, cageSettings)
                        makeLogFile(expSettings, cageSettings)
                        simpleLogger.logFP = expSettings.logFP
                        makeQuickStatsFile(expSettings, cageSettings, mice)
                        for i in stimulator:
                            i.nextDay(expSettings.logFP)
                        nextDay += KSECSPERDAY
                        mice.clear()
                        updateH5File(expSettings, cageSettings, mice,
                                     stimulator)
                        updateStats(expSettings.statsFP, mice)
                        backup_H5(expSettings, cageSettings)
                        # reinitialize lick detector because it can lock up if too many licks when not logging
                        lickDetector.__init__((0, 1), 26, simpleLogger)
                        lickDetector.start_logging()
                    print('Waiting for a mouse...')
                else:
                    # check for entry beam break while idling between trials
                    if cageSettings.hasEntryBB == True and time(
                    ) > gTubePanicTime:
                        print(
                            'Some one has been in the entrance of this tube for too long'
                        )
                        # explictly turn off pistons, though they should be off
                        headFixer.releaseMouse()
                        BBentryTime = gTubePanicTime - gTubeMaxTime
                        if expSettings.hasTextMsg == True:
                            notifier.notify(
                                0, (time() - BBentryTime), True
                            )  # we don't have an RFID for this mouse, so use 0
                        # wait for mouse to leave chamber
                        while time() > gTubePanicTime:
                            sleep(kTIMEOUTmS / 1000)
                        print(
                            'looks like some one managed to escape the entrance of this tube'
                        )
                        if expSettings.hasTextMsg == True:
                            notifier.notify(0, (time() - BBentryTime), False)
            except KeyboardInterrupt:
                GPIO.output(cageSettings.ledPin, GPIO.LOW)
                headFixer.releaseMouse()
                GPIO.output(cageSettings.rewardPin, GPIO.LOW)
                lickDetector.stop_logging()
                if cageSettings.hasEntryBB == True:
                    sleep(1)
                    GPIO.remove_event_detect(cageSettings.entryBBpin)
                    print('removed BB event detect')
                while True:
                    event = input(
                        'Enter:\nr to return to head fix trials\nq to quit\nv to run valve control\nh for hardware tester\nm for mice inspection\nc for camera configuration\ne for experiment configuration\n:'
                    )
                    if event == 'r' or event == "R":
                        lickDetector.start_logging()
                        sleep(1)
                        if cageSettings.hasEntryBB == True:
                            sleep(1)
                            print('Restarting entry bb')
                            GPIO.setup(cageSettings.entryBBpin,
                                       GPIO.IN,
                                       pull_up_down=GPIO.PUD_UP)
                            GPIO.add_event_detect(cageSettings.entryBBpin,
                                                  GPIO.BOTH, entryBBCallback)
                        break
                    elif event == 'q' or event == 'Q':
                        exit(0)
                    elif event == 'v' or event == "V":
                        valveControl(cageSettings)
                    elif event == 'h' or event == 'H':
                        hardwareTester(cageSettings, tagReader, headFixer,
                                       stimulator, expSettings)
                        if cageSettings.contactPolarity == 'RISING':
                            expSettings.contactEdge = GPIO.RISING
                            expSettings.noContactEdge = GPIO.FALLING
                            expSettings.contactState = GPIO.HIGH
                            expSettings.noContactState = GPIO.LOW
                        else:
                            expSettings.contactEdge = GPIO.FALLING
                            expSettings.noContactEdge = GPIO.RISING
                            expSettings.contactState = GPIO.LOW
                            expSettings.noContactState = GPIO.HIGH
                    elif event == 'm' or event == 'M':
                        mice.show()
                        for i, j in enumerate(expSettings.stimulator):
                            print('\t' + str(i) + ': ' + str(j))
                        inputStr = input(
                            'Which stimulator-specific inspection method would you like to run?'
                        )
                        try:
                            stimulator[int(inputStr)].inspect_mice(
                                mice, cageSettings, expSettings)
                        except:
                            print("Stimulator doesn't exist.")
                        updateH5File(expSettings, cageSettings, mice,
                                     stimulator)
                    elif event == 'c' or event == 'C':
                        camParams = camera.adjust_config_from_user()
                    elif event == 'e' or event == 'E':
                        modCode = expSettings.edit_from_user()
                        if modCode >= 2:
                            stimulator[modCode - 2] = AHF_Stimulator.get_class(
                                expSettings.stimulator[modCode - 2])(
                                    cageSettings, expSettings.stimDict,
                                    rewarder, lickDetector, expSettings.logFP,
                                    camera)
                        if modCode & 1:
                            for stim in stimulator:
                                stim.change_config(expSettings.stimDict)
    except Exception as anError:
        print('AutoHeadFix error:' + str(anError))
        raise anError
    finally:
        for stim in stimulator:
            stim.quitting()
        GPIO.output(cageSettings.ledPin, False)
        headFixer.releaseMouse()
        GPIO.output(cageSettings.rewardPin, False)
        GPIO.cleanup()
        writeToLogFile(expSettings.logFP, None, 'SeshEnd')
        expSettings.logFP.close()
        expSettings.statsFP.close()
        camera.close()
        print('AutoHeadFix Stopped')
예제 #2
0
from AHF_CageSet import AHF_CageSet
from AHF_Mouse import Mouse, Mice
from AHF_TagReader import AHF_TagReader
from time import sleep


if __name__ == "__main__":
    cageSettings = AHF_CageSet()

    print (cageSettings.mouseConfigPath)

    reader = AHF_TagReader(cageSettings.serialPort)
    while True: 
        try:
            reader.clearBuffer()

            tag = reader.readTag()
            
            print ("Read Tag: " + str(tag))

            mouse = Mouse(tag, 0, 0, 0, 0, cageSettings.mouseConfigPath)

        except KeyboardInterrupt:
            break

    print("All mice in config files I hope!")
예제 #3
0
            outPutStr = mStr + \
                datetime.fromtimestamp(int(rewardTime)).isoformat(' ') + event
            print(outPutStr)
            if self.textfp != None:
                outPutStr = mStr + '{:.2f}'.format(rewardTime) + event
                self.textfp.write(outPutStr + '\n')
            self.textfp.flush()


if __name__ == '__main__':
    import RPi.GPIO as GPIO
    try:
        GPIO.setmode(GPIO.BCM)
        rewarder = AHF_Rewarder(30e-03, 24)
        rewarder.addToDict('task', 50e-03)
        thisMouse = Mouse(2525, 0, 0, 0, 0)
        #stimFile = AHF_Stimulator.get_stimulator ()
        #stimulator = AHF_Stimulator.get_class (stimFile)(stimdict, rewarder, None)
        stimdict = {'nRewards': 5, 'rewardInterval': .25}
        #stimdict = AHF_Stimulator.configure({})
        #print ('stimdict:')
        # for key in sorted (stimdict.keys()):
        #   print (key + ' = ' + str (stimdict[key]))
        stimulator = AHF_Stimulator_Rewards(stimdict, rewarder, None)
        print(stimulator.configStim(thisMouse))
        stimulator.run()
        stimulator.logfile()
        thisMouse.show()
    except FileNotFoundError:
        print('File not found')
    finally:
예제 #4
0
def main():
    """
    The main function for the AutoHeadFix program.

    It initializes or loads settings and configurations, then endlessly loops running entries and head fix trials
    Ctrl-C is used to enter a menu-driven mode where settings can be altered.
    """
    try:
        #print (str (argv))
        # load general settings for this cage, mostly hardward pinouts
        # things not expected to change often - there is only one AHFconfig.jsn
        # file, in the enclosing folder
        cageSettings = AHF_CageSet()
        # get settings that may vary by experiment, including rewarder, camera pramaters, and stimulator
        # More than one of these files can exist, and the user needs to choose one or make one
        # we will add some other  variables to expSettings so we can pass them as a single argument to functions
        # logFP, statsFP, dateStr, dayFolderPath,   doHeadFix,
        expSettings = AHF_Settings(None)
        # nextDay starts tomorrow at KDAYSTARTHOUR
        nextDay = (int((time() - timezone) / KSECSPERDAY) + 1) * \
            KSECSPERDAY + timezone + (KDAYSTARTHOUR * KSECSPERHOUR)
        # Create folders where the files for today will be stored
        makeDayFolderPath(expSettings, cageSettings)
        # initialize mice with zero mice
        mice = Mice()
        # make daily Log files and quick stats file
        makeLogFile(expSettings, cageSettings)
        makeQuickStatsFile(expSettings, cageSettings, mice)
        # set up the GPIO headers each for their respective functionalities.
        GPIO.setmode(GPIO.BCM)
        GPIO.setwarnings(False)
        GPIO.setup(cageSettings.pistonsPin, GPIO.OUT, initial=GPIO.LOW)
        GPIO.setup(cageSettings.ledPin, GPIO.OUT, initial=GPIO.LOW)
        GPIO.setup(cageSettings.tirPin, GPIO.IN)
        GPIO.setup(cageSettings.contactPin, GPIO.IN)
        # make a rewarder - TODO: make one for each mouse and record water for
        # each mouse in its own rewarder
        rewarder = AHF_Rewarder(30e-03, cageSettings.rewardPin)
        rewarder.addToDict('entrance', expSettings.entranceRewardTime)
        rewarder.addToDict('task', expSettings.taskRewardTime)
        # make a notifier object
        if expSettings.hasTextMsg == True:
            notifier = AHF_Notifier(cageSettings.cageID, expSettings.phoneList)
        else:
            notifier = None
        # make RFID reader
        tagReader = AHF_TagReader(cageSettings.serialPort, False)
        # configure camera
        camera = AHF_Camera(expSettings.camParamsDict)
        # make UDP Trigger
        if expSettings.hasUDP == True:
            UDPTrigger = AHF_UDPTrig(expSettings.UDPList)
        else:
            UDPTrigger = None
        # make stimulator
        stimulator = AHF_Stimulator.get_class(expSettings.stimulator)(
            expSettings.stimDict, rewarder, expSettings.logFP)
        expSettings.stimDict = stimulator.configDict
    except Exception as anError:
        print ('Unexpected error starting AutoHeadFix:', str(anError))
        return
    try:
        print ('Waiting for a mouse...')
        while True:  # start main loop
            try:
                # wait for mouse entry, with occasional timeout to catch
                # keyboard interrupt
                # wait for entry based on Tag-in-range pin
                GPIO.wait_for_edge(cageSettings.tirPin,
                                   GPIO.RISING, timeout=kTIMEOUTmS)
                if (GPIO.input(cageSettings.tirPin) == GPIO.HIGH):
                    try:
                        tag = tagReader.readTag()
                    except (IOError, ValueError):
                        continue
                    entryTime = time()
                    thisMouse = mice.getMouseFromTag(tag)
                    if thisMouse is None:
                        thisMouse = Mouse(tag, 1, 0, 0, 0)
                        mice.addMouse(thisMouse, expSettings.statsFP)
                    writeToLogFile(expSettings.logFP, thisMouse, 'entry')
                    thisMouse.entries += 1
                    # if we have entrance reward, first wait for entrance
                    # reward or first head-fix, which countermands entry reward
                    if thisMouse.entranceRewards < expSettings.maxEntryRewards:
                        giveEntranceReward = True
                        expSettings.doHeadFix = expSettings.propHeadFix > random()
                        while GPIO.input(cageSettings.tirPin) == GPIO.HIGH and time() < (entryTime + expSettings.entryRewardDelay):
                            GPIO.wait_for_edge(
                                cageSettings.contactPin, GPIO.RISING, timeout=kTIMEOUTmS)
                            if (GPIO.input(cageSettings.contactPin) == GPIO.HIGH):
                                runTrial(thisMouse, expSettings,
                                         cageSettings, camera, rewarder, stimulator)
                                giveEntranceReward = False
                                break
                        if (GPIO.input(cageSettings.tirPin) == GPIO.HIGH) and giveEntranceReward == True:
                            # entrance reward was not countermanded by an early
                            # headfix
                            thisMouse.reward(rewarder, 'entrance')
                            thisMouse.entranceRewards += 1
                            writeToLogFile(expSettings.logFP,
                                           thisMouse, 'entryReward')
                    # wait for contacts and run trials till mouse exits or time
                    # in chamber exceeded
                    expSettings.doHeadFix = expSettings.propHeadFix > random()
                    while GPIO.input(cageSettings.tirPin) == GPIO.HIGH and time() < entryTime + expSettings.inChamberTimeLimit:
                        GPIO.wait_for_edge(
                            cageSettings.contactPin, GPIO.RISING, timeout=kTIMEOUTmS)
                        if (GPIO.input(cageSettings.contactPin) == GPIO.HIGH):
                            runTrial(thisMouse, expSettings, cageSettings,
                                     camera, rewarder, stimulator, UDPTrigger)
                            # set doHeadFix for next contact
                            expSettings.doHeadFix = expSettings.propHeadFix > random()
                    # either mouse left the chamber or has been in chamber too
                    # long
                    if GPIO.input(cageSettings.tirPin) == GPIO.HIGH and time() > entryTime + expSettings.inChamberTimeLimit:
                        # explictly turn off pistons, though they should be off
                        # at end of trial
                        GPIO.output(cageSettings.pistonsPin, GPIO.LOW)
                        if expSettings.hasNotifier == True:
                            notifier.notify(
                                thisMouse.tag, (time() - entryTime),  True)
                        # wait for mouse to leave chamber, with no timeout
                        GPIO.wait_for_edge(cageSettings.tirPin, GPIO.FALLING)
                        if expSettings.hasNotifier == True:
                            notifier.notify(
                                thisMouse.tag, (time() - entryTime), False)
                    tagReader.clearBuffer()
                    # after exit, update stats
                    writeToLogFile(expSettings.logFP, thisMouse, 'exit')
                    updateStats(expSettings.statsFP, mice, thisMouse)
                    # after each exit check for a new day
                    if time() > nextDay:
                        mice.show()
                        writeToLogFile(logFP, None, 'SeshEnd')
                        expSettings.logFP.close()
                        expSettings.statsFP.close()
                        dayFolderPath = makeDayFolderPath(cageSettings)
                        expSettings.logFP = makeLogFile(
                            dayFolderPath, cageSettings)
                        expSettings.statsFP = makeQuickStatsFile(
                            dayFolderPath, cageSettings, mice)
                        stimulator.nextDay(expSettings.logFP)
                        nextDay += KSECSPERDAY
                        mice.clear()
                    print ('Waiting for a mouse...')
            except KeyboardInterrupt:
                GPIO.output(cageSettings.ledPin, GPIO.LOW)
                GPIO.output(cageSettings.pistonsPin, GPIO.LOW)
                GPIO.output(cageSettings.rewardPin, GPIO.LOW)
                while True:
                    event = input(
                        'Enter:\nr to return to head fix trials\nq to quit\nv to run valve control\nh for hardware tester\nc for camera configuration\ne for experiment configuration\n:')
                    if event == 'r' or event == "R":
                        break
                    elif event == 'q' or event == 'Q':
                        return
                    elif event == 'v' or event == "V":
                        valveControl(cageSettings)
                    elif event == 'h' or event == 'H':
                        hardwareTester(cageSettings, tagReader)
                    elif event == 'c' or event == 'C':
                        camParams = camera.adjust_config_from_user()
                    elif event == 'e' or event == 'E':
                        modCode = expSettings.edit_from_user()
                        if modCode & 2:
                            stimulator = AHF_Stimulator.get_class(expSettings.stimulator)(
                                expSettings.stimDict, rewarder, expSettings.logFP)
                        if modCode & 1:
                            stimulator.change_config(expSettings.stimDict)
    except Exception as anError:
        print ('AutoHeadFix error:' + str(anError))
    finally:
        stimulator.quitting()
        GPIO.output(cageSettings.ledPin, False)
        GPIO.output(cageSettings.pistonsPin, False)
        GPIO.output(cageSettings.rewardPin, False)
        GPIO.cleanup()
        writeToLogFile(expSettings.logFP, None, 'SeshEnd')
        expSettings.logFP.close()
        expSettings.statsFP.close()
        print ('AutoHeadFix Stopped')