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')
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!")
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:
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')