Exemple #1
0
 def add_mice(self):
     try:
         tagreader = TagReader(RFID_serialPort,
                               RFID_doCheckSum,
                               timeOutSecs=RFID_timeout,
                               kind=RFID_kind)
     except Exception as e:
         raise e
     i = 0
     print('Scan mice now')
     while i < 1:
         try:
             tag = tagreader.readTag()
             i += 1
             print(tag)
         except ValueError as e:
             print(str(e))
     tagreader.clearBuffer()
     SPT_lvl = input('Enter SPT level for new mouse:')
     SPT_Spout = input('Enter initial SPT spout for new mouse (R/L):')
     temp = {tag: {'SPT_Pattern': SPT_Spout, 'SPT_level': int(SPT_lvl)}}
     self.mice_config.update(temp)
Exemple #2
0
            values1 = [tag, timestamp, weight_float, 0, 'N', Cage]
            cur1.execute(insert_statment, values)
        else:
            with open(record_filename, 'r') as csv1:
                reader = csv.reader(csv1)
                reader1 = list(reader)
                Baseline_Weight = float(reader1[1][2])
                not_valu = round((float(weight_float) - Baseline_Weight) /
                                 Baseline_Weight * 100, 1)
                print(str(not_valu))
                if (float(weight_float) -
                        Baseline_Weight) / Baseline_Weight * 100 < -15.0:
                    CO = 'Y'
                    print('Mouse Underweight, Need supplment water')
                else:
                    CO = 'N'
            values = [
                tag, timestamp, weight_float,
                round((float(weight_float) - Baseline_Weight) /
                      Baseline_Weight * 100, 1), CO, Cage
            ]
            with open(record_filename, "a") as file:
                file.write(timestamp + "," + str(tag) + "," +
                           str(weight_float) + ',' + str(not_valu) + '%' +
                           ',' + CO + ',' + Cage + "\n")
            cur1.execute(insert_statment, values)
    except ValueError as e:
        print(str(e))
        tagReader.clearBuffer()
print('Read ' + ' tags')
def htloop (cageSet, tagReader, headFixer, stimulator, expSettings):
    """
    Presents a menu asking user to choose a bit of hardware to test, and runs the tests

    If a test fails, a dialog is presented asking user to change the pin setup. The modified pinout
    can be saved, overwriting the configuration in ./AHF_Config.jsn
    Commands are:
    t= tagReader: trys to read a tag and, if successful, monitors Tag in Range Pin until tag goes away
    r = reward solenoid:  Opens the reward solenoid for a 1 second duration, then closes it
    c = contact check:  Monitors the head contact pin until contact, and then while contact is maintained
    f = head Fixer
    e = Entry beam break
    p = pistons solenoid: Energizes the pistons for a 2 second duration, and then de-energizes them
    l = LED: Turns on the brain illumination LED for a 2 second duration, then off
    h = sHow config settings: Prints out the current pinout in the AHF_CageSet object
    v = saVe modified config file: Saves the the AHF_CageSet object to the file ./AHF_Config.jsn
    q = quit: quits the program
    """
    if cageSet.contactPolarity == 'RISING':
          contactEdge = GPIO.RISING
          noContactEdge = GPIO.FALLING
          contactState = GPIO.HIGH
          noContactState = GPIO.LOW
    else:
          contactEdge = GPIO.FALLING
          noContactEdge = GPIO.RISING
          contactState = GPIO.LOW
          noContactState = GPIO.HIGH
    try:
        while (True):
            inputStr = input ('t=tagReader, r=reward solenoid, c=contact check, e= entry beam break, f=head Fixer, l=LED, s=stimulator tester, h=sHow config, v= saVe config, q=quit:')
            if inputStr == 't': # t for tagreader
                if tagReader == None:
                    cageSet.serialPort = input ('First, set the tag reader serial port:')
                    try:
                        tagReader = TagReader (cageSet.serialPort, True)
                        inputStr =  input ('Do you want to read a tag now?')
                        if inputStr[0] == 'n' or inputStr[0] == "N":
                            continue
                    except IOError as anError:
                        print ('Try setting the serial port again.')
                        tagReader = None
                if tagReader is not None:
                    try:
                        if (tagReader.serialPort.inWaiting() < 16):
                            print ('No data in serial buffer')
                            tagError = True
                        else:
                            tagID = tagReader.readTag()
                            tagError = False
                    except (IOError, ValueError) as anError:
                        tagError = True
                    if tagError == True:
                        print ('Serial Port Tag-Read Error\n')
                        tagReader.clearBuffer()
                        inputStr = input ('Do you want to change the tag reader serial port (currently ' + cageSet.serialPort + ')?')
                        if inputStr == 'y' or inputStr == "Y":
                            cageSet.serialPort = input ('Enter New Serial Port:')
                            # remake tagReader and open serial port
                            tagReader = TagReader (cageSet.serialPort, True)
                    else:
                        print ("Tag ID =", tagID)
                        # now check Tag-In-Range pin function
                        if (GPIO.input (cageSet.tirPin)== GPIO.LOW):
                            print ('Tag was never registered as being "in range"')
                            tagError = True
                        else:
                            startTime = time()
                            GPIO.wait_for_edge (cageSet.tirPin, GPIO.FALLING, timeout= 10000)
                            if (time () > startTime + 10.0):
                                print ('Tag stayed in range for over 10 seconds')
                                tagError = True
                            else:
                                print ('Tag no longer in range')
                                tagError = False
                        if (tagError == True):
                            inputStr = input ('Do you want to change the tag-in-range Pin (currently ' + str (cageSet.tirPin) + ')?')
                            if inputStr[0] == 'y' or inputStr[0] == "Y":
                                cageSet.tirPin = int (input('Enter New tag-in-range Pin:'))
                                GPIO.setup (cageSet.tirPin, GPIO.IN)
            elif inputStr == 'r': # r for reward solenoid
                print ('Reward Solenoid opening for 3 sec')
                GPIO.output(cageSet.rewardPin, 1)
                sleep(3.0)
                GPIO.output(cageSet.rewardPin, 0)
                inputStr= input('Reward Solenoid closed.\nDo you want to change the Reward Solenoid Pin (currently ' + str (cageSet.rewardPin) + ')?')
                if inputStr[0] == 'y' or inputStr[0] == "Y":
                    cageSet.rewardPin = int (input('Enter New Reward Solenoid Pin:' ))
                    GPIO.setup (cageSet.rewardPin, GPIO.OUT, initial=GPIO.LOW)
            elif inputStr == 'c': #c for contact on head fix
                if GPIO.input (cageSet.contactPin)== contactState:
                    print ('Contact pin already indicates contact.')
                    err=True
                else:
                    GPIO.wait_for_edge (cageSet.contactPin, contactEdge, 100)
                    if GPIO.input (cageSet.contactPin)== noContactState:
                        print ('No Contact after 10 seconds.')
                        err = True
                    else:
                        print ('Contact Made.')
                        GPIO.wait_for_edge (cageSet.contactPin, noContactEdge, 100)
                        if GPIO.input (cageSet.contactPin)== contactState:
                            print ('Contact maintained for 10 seconds.')
                            err = True
                        else:
                            print ('Contact Broken')
                            err = False
                if err == True:
                    inputStr= input ('Do you want to change Contact settings (currently pin=' + str (cageSet.contactPin) + ', polarity=' + str(cageSet.contactPolarity) + ', pull up/down =' + str (cageSet.contactPUD) + ')?')
                    if inputStr[0] == 'y' or inputStr[0] == "Y":
                        cageSet.contactPin= int (input ('Enter the GPIO pin connected to the headbar contacts or IR beam-breaker:'))
                        contactInt = int (input ('Enter the contact polarity, 0=FALLING for IR beam-breaker or falling polarity electrical contacts, 1=RISING for rising polarity elctrical contacts:'))
                        if contactInt == 0:
                            cageSet.contactPolarity = 'FALLING'
                        else:
                            cageSet.contactPolarity = 'RISING'
                        contactInt = int (input('Enter desired resistor on contact pin, 0=OFF if external resistor present, else 1=DOWN if rising polarity electrical contact or 2 = UP if IR beam-breaker or falling polarity electrical contacts:'))
                        if contactInt ==0:
                            cageSet.contactPUD = 'OFF'
                        elif contactInt == 1:
                            cageSet.contactPUD = 'DOWN'
                        else:
                            cageSet.contactPUD='UP'
                    GPIO.setup (cageSet.contactPin, GPIO.IN, pull_up_down=getattr (GPIO, "PUD_" + cageSet.contactPUD))
                    if cageSet.contactPolarity =='RISING':
                        contactEdge = GPIO.RISING
                        noContactEdge = GPIO.FALLING
                        contactState = GPIO.HIGH
                        noContactState = GPIO.LOW
                    else:
                        contactEdge = GPIO.FALLING
                        noContactEdge = GPIO.RISING
                        contactState = GPIO.LOW
                        noContactState = GPIO.HIGH
            elif inputStr == 'e': # beam break at enty
                if GPIO.input (cageSet.entryBBpin)== GPIO.LOW:
                    print ('Entry beam break is already broken')
                    err=True
                else:
                    GPIO.wait_for_edge (cageSet.entryBBpin, GPIO.FALLING, timeout= 10000)
                    if GPIO.input (cageSet.entryBBpin)== GPIO.HIGH:
                        print ('Entry beam not broken after 10 seconds.')
                        err = True
                    else:
                        print ('Entry Beam Broken.')
                        GPIO.wait_for_edge (cageSet.entryBBpin, GPIO.RISING, timeout= 10000)
                        if GPIO.input (cageSet.entryBBpin)== GPIO.LOW:
                            print ('Entry Beam Broken maintained for 10 seconds.')
                            err = True
                        else:
                            print ('Entry Beam Intact Again.')
                            err = False
                if err == True:
                    inputStr= input ('Do you want to change the Entry Beam Break Pin (currently pin=' + str (cageSet.entryBBpin)+ '?')
                    if inputStr[0] == 'y' or inputStr[0] == "Y":
                        cageSet.entryBBpin= int (input ('Enter the GPIO pin connected to the tube entry IR beam-breaker:'))
                        GPIO.setup (cageSet.entryBBpin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

            elif inputStr == 'f': # head Fixer, run test from headFixer class
                headFixer.test(cageSet)
            elif inputStr == 'l': # l for LED trigger
                print ('LED turning ON for 2 seconds.')
                GPIO.output(cageSet.ledPin, 1)
                sleep (2)
                GPIO.output(cageSet.ledPin, 0)
                inputStr=input ('LED turned OFF\nDo you want to change the LED Pin (currently ' + str(cageSet.ledPin) + ')?')
                if inputStr == 'y' or inputStr == "Y":
                    cageSet.ledPin = int (input('Enter New LED Pin:'))
                    GPIO.setup (cageSet.ledPin, GPIO.OUT, initial = GPIO.LOW)
            elif inputStr == 's':
                for i,j in enumerate(expSettings.stimulator):
                    print('\t'+str(i)+': '+str(j))
                inputStr = input ('Which stimulator tester would you like to run?')
                try:
                    stimulator[int(inputStr)].tester(expSettings)
                except:
                    print('Input is not a valid number!')
            elif inputStr == 'h':
                cageSet.show()
            elif inputStr=='v':
                cageSet.save()
            elif inputStr == 'q':
                break
    except KeyboardInterrupt:
        print ("quitting.")
    finally:
        if __name__ == '__main__':
            GPIO.cleanup() # this ensures a clean exit
Exemple #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:
        # 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')