Example #1
0
    def dur_from_vol(self, vol):
        """
        Given a desired volume, compute an open duration.

        Must have calibration available in prefs, see :meth:`~.Terminal.calibrate_ports`.

        Args:
            vol (float, int): desired reward volume in uL

        Returns:
            int: computed opening duration for given volume
        """
        # find our pin name
        if not self.name:
            self.name = self.get_name()

        # prefs should have loaded any calibration
        try:
            self.calibration = prefs.get('PORT_CALIBRATION')[self.name]
        except KeyError:
            # try using name prepended with PORTS_, which happens for hardware objects with implicit names
            self.calibration = prefs.get('PORT_CALIBRATION')[self.name.replace(
                'PORTS_', '')]
        except Exception as e:
            self.logger.exception(
                f'couldnt get calibration, using default LUT y = 3.5 + 2. got error {e}'
            )
            self.calibration = {'slope': 3.5, 'intercept': 2}
        # compute duration from slope and intercept
        duration = round(
            float(self.calibration['intercept']) +
            (float(self.calibration['slope']) * float(vol)))

        return duration
Example #2
0
    def _process(self, transform):

        self.transform = autopilot.transform.make_transform(transform)

        self.node = Net_Node(f"{prefs.get('NAME')}_TRANSFORMER",
                             upstream=prefs.get('NAME'),
                             port=prefs.get('MSGPORT'),
                             listens={'CONTINUOUS': self.l_process},
                             instance=False)

        self.node.send(self.return_id, 'STATE', value='READY')

        while True:
            try:
                # value = self.input_q.get_nowait()
                value = self.input_q.popleft()
            # except Empty:
            except IndexError:
                sleep(0.001)
                continue
            result = self.transform.process(value)

            self.node.logger.debug(f'Processed frame, result: {result}')

            if self.operation == "trigger":
                if result != self._last_result:
                    self.node.send(self.return_id, self.return_key, result)
                    self._last_result = result

            elif self.operation == 'stream':
                # FIXME: Another key that's not TRIGGER
                self.node.send(self.return_id, self.return_key, result)

            elif self.operation == 'debug':
                pass
    def update_protocols(self):
        """
        If we change the protocol file, update the stored version in subject files
        """
        #
        # get list of protocol files
        protocols = os.listdir(prefs.get('PROTOCOLDIR'))
        protocols = [p for p in protocols if p.endswith('.json')]

        updated_subjects = []
        subjects = self.subject_list
        for subject in subjects:
            if subject not in self.subjects.keys():
                self.subjects[subject] = Subject(subject)

            protocol_bool = [
                self.subjects[subject].protocol_name == os.path.splitext(p)[0]
                for p in protocols
            ]
            if any(protocol_bool):
                which_prot = np.where(protocol_bool)[0][0]
                protocol = protocols[which_prot]
                self.subjects[subject].assign_protocol(
                    os.path.join(prefs.get('PROTOCOLDIR'), protocol),
                    step_n=self.subjects[subject].step)
                updated_subjects.append(subject)

        msgbox = QtWidgets.QMessageBox()
        msgbox.setText("Subject Protocols Updated for:")
        msgbox.setDetailedText("\n".join(sorted(updated_subjects)))
        msgbox.exec_()
Example #4
0
    def init_networking(self, listens=None, **kwargs):
        """
        Spawn a :class:`.Net_Node` to :attr:`Hardware.node` for streaming or networked command

        Args:
            listens (dict): Dictionary mapping message keys to handling methods
            **kwargs: Passed to :class:`.Net_Node`

        Returns:

        """

        if not listens:
            listens = self.listens

        self.node = Net_Node(
            self.name,
            upstream=prefs.get('NAME'),
            port=prefs.get('MSGPORT'),
            listens=listens,
            instance=False,
            **kwargs
            #upstream_ip=prefs.get('TERMINALIP'),
            #daemon=False
        )
Example #5
0
    def __init__(self, stage_block = None, **kwargs):

        super(Parallax, self).__init__()

        self.stage_block = stage_block

        self.init_hardware()

        self.node = Net_Node(id="{}_TASK".format(prefs.get('NAME')),
                             upstream=prefs.get('NAME'),
                             port=prefs.get('MSGPORT'),
                             listens = {},
                             instance = False)

        self.subject = kwargs['subject']
        # value = {
        #     'child': {'parent': prefs.get('NAME'), 'subject': self.subject},
        #     'subject' : self.subject,
        #
        # }
        # value.update(self.CHILDREN['HEADCAM'])
        #
        # self.node.send(to=prefs.get('NAME'), key='CHILD', value=value)

        self.stages = itertools.cycle([self.test])

        self.n_trials = itertools.count()

        # print(self.hardware)

        # self.hardware['CAMS']['EYE'].capture()
        self.hardware['CAMERAS']['SIDE'].stream(to="T")
        self.hardware['CAMERAS']['SIDE'].capture()
Example #6
0
def start_jackd():
    if not JACKD:
        raise ImportError('jackd was not found in autopilot.external or as a system install')

    # get specific launch string from prefs
    if prefs.get("JACKDSTRING"):
        jackd_string = prefs.get('JACKDSTRING').lstrip('jackd')

    else:
        jackd_string = ""

    # replace string fs with number
    if prefs.get('FS'):
        jackd_string = jackd_string.replace('-rfs', f"-r{prefs.get('FS')}")

    # construct rest of launch string!
    # if JACKD_MODULE:
    #     jackd_path = os.path.join(autopilot_jack.__path__._path[0])
    #
    #     # now set as env variables...
    #     # specify location of libraries when starting jackd
    #     # lib_string = "LD_LIBRARY_PATH=" + os.path.join(jackd_path, 'lib')
    #     #
    #     # specify location of drivers when starting jackd
    #     # os.environ['JACK_DRIVER_DIR'] = os.path.join(jackd_path, 'lib', 'jack')
    #     # driver_string = "JACK_DRIVER_DIR=" + os.path.join(jackd_path, 'lib', 'jack')
    #
    #     jackd_bin = os.path.join(jackd_path, 'bin', 'jackd')
    #
    #     # combine all the pieces
    #     # launch_jackd = " ".join([lib_string, driver_string, jackd_bin, jackd_string])
    #
    # else:
    jackd_bin = shutil.which('jackd')

    #jackd_bin = 'jackd'

        # launch_jackd = " ".join([jackd_bin, jackd_string])

    launch_jackd = " ".join([jackd_bin, jackd_string])

    proc = subprocess.Popen(launch_jackd, shell=True)
    globals()['JACKD_PROCESS'] = proc

    # kill process when session ends
    def kill_proc(*args):
        proc.kill()
        sys.exit(1)
    atexit.register(kill_proc)
    signal.signal(signal.SIGTERM, kill_proc)

    # sleep to let it boot
    sleep(2)

    return proc
Example #7
0
    def request(self):
        # wait for the subject to hold the wheel still
        # Set the event lock
        self.stage_block.clear()
        # wait on any ongoing punishment stimulus
        self.punish_block.wait()

        # Reset all the variables that need to be
        #for v in self.resetting_variables:
        #    v = None

        # reset triggers if there are any left
        self.triggers = {}

        # calculate orientation change
        # half the time, don't change, otherwise, do change
        if random() < 0.5:
            self.shift = 0
            self.target = False
        else:
            self.shift = random() * 180.0
            self.target = True

        # Set sound trigger and LEDs
        # We make two triggers to play the sound and change the light color
        change_to_blue = lambda: self.hardware['LEDS']['C'].set_color(
            [0, 0, 255])

        # set triggers
        self.triggers['F'] = [
            change_to_blue, lambda: self.stim.play('shift', self.shift)
        ]

        # set to green in the meantime
        self.set_leds({'C': [0, 255, 0]})

        # tell our wheel to start measuring
        self.node.send(to=[prefs.get('NAME'),
                           prefs.get('CHILDID'), 'wheel_0'],
                       key="MEASURE",
                       value={
                           'mode': 'steady',
                           'thresh': 100
                       })

        self.current_trial = next(self.trial_counter)
        data = {
            'target': self.target,
            'shift': self.shift,
            'trial_num': self.current_trial
        }

        self.current_stage = 0
        return data
Example #8
0
def test_prefs_defaults(default_pref):

    # make sure that we didnt' actually load anything from some phantom uh prefs file idk
    if prefs._INITIALIZED.value:
        warnings.warn('prefs was initialized, so defaults could not be tested')
        return

    if 'default' in default_pref[1].keys():
        with pytest.warns(UserWarning):
            assert prefs.get(default_pref[0]) == default_pref[1]['default']
    else:
        assert prefs.get(default_pref[0]) is None
Example #9
0
    def blank_LEDs(self):
        """
        If any 'LEDS' are defined in `prefs.get('HARDWARE')` ,
        instantiate them, set their color to [0,0,0],
        and then release them.
        """
        if 'LEDS' not in prefs.get('HARDWARE').keys():
            return

        for position, pins in prefs.get('HARDWARE')['LEDS'].items():
            led = gpio.LED_RGB(pins=pins)
            time.sleep(1.)
            led.set_color(col=[0, 0, 0])
            led.release()
Example #10
0
    def __init__(self, *args, **kwargs):
        super(ImageItem_TimedUpdate, self).__init__(*args, **kwargs)

        if globals()['VIDEO_TIMER'] is None:
            globals()['VIDEO_TIMER'] = QtCore.QTimer()

        self.timer = globals()['VIDEO_TIMER']
        self.timer.stop()
        self.timer.timeout.connect(self.update_img)
        if prefs.get('DRAWFPS'):
            self.fps = prefs.get('DRAWFPS')
        else:
            self.fps = 10.
        self.timer.start(1. / self.fps)
    def new_protocol(self):
        """
        Open a :class:`.gui.Protocol_Wizard` to create a new protocol.

        Prompts for name of protocol, then saves in `prefs.get('PROTOCOLDIR')`
        """
        self.new_protocol_window = Protocol_Wizard()
        self.new_protocol_window.exec_()

        if self.new_protocol_window.result() == 1:
            steps = self.new_protocol_window.steps

            # The values useful to the step functions are stored with a 'value' key in the param_dict
            save_steps = []
            for s in steps:
                param_values = {}
                for k, v in s.items():
                    if 'value' in v.keys():
                        param_values[k] = v['value']
                    elif k == 'stim':
                        # TODO: Super hacky - don't do this. Refactor params already.
                        param_values[k] = {}
                        for stimtype, stim in v.items():
                            param_values[k][stimtype] = stim
                save_steps.append(param_values)

            # Name the protocol
            name, ok = QtWidgets.QInputDialog.getText(self, "Name Protocol",
                                                      "Protocol Name:")
            if ok and name != '':
                protocol_file = os.path.join(prefs.get('PROTOCOLDIR'),
                                             name + '.json')
                with open(protocol_file, 'w') as pfile_open:
                    json.dump(save_steps,
                              pfile_open,
                              indent=4,
                              separators=(',', ': '),
                              sort_keys=True)
            elif name == '' or not ok:
                placeholder_name = 'protocol_created_{}'.format(
                    datetime.date.today().isoformat())
                protocol_file = os.path.join(prefs.get('PROTOCOLDIR'),
                                             placeholder_name + '.json')
                with open(protocol_file, 'w') as pfile_open:
                    json.dump(save_steps,
                              pfile_open,
                              indent=4,
                              separators=(',', ': '),
                              sort_keys=True)
Example #12
0
    def calibrate_port(self, port_name, n_clicks, open_dur, iti):
        """
        Run port calibration routine

        Open a :class:`.hardware.gpio.Solenoid` repeatedly,
        measure volume of water dispersed, compute lookup table mapping
        valve open times to volume.

        Continuously sends progress of test with ``CAL_PROGRESS`` messages

        Args:
            port_name (str): Port name as specified in ``prefs``
            n_clicks (int): number of times the valve should be opened
            open_dur (int, float): how long the valve should be opened for in ms
            iti (int, float): how long we should :func:`~time.sleep` between openings

        """
        pin_num = prefs.get('HARDWARE')['PORTS'][port_name]
        port = gpio.Solenoid(pin_num, duration=int(open_dur))
        msg = {'click_num': 0, 'pilot': self.name, 'port': port_name}

        iti = float(iti) / 1000.0

        cal_name = "Cal_{}".format(self.name)

        for i in range(int(n_clicks)):
            port.open()
            msg['click_num'] = i + 1
            self.node.send(to=cal_name, key='CAL_PROGRESS', value=msg)
            time.sleep(iti)

        port.release()
Example #13
0
    def l_cal_result(self, value):
        """
        Save the results of a port calibration

        """

        # files for storing raw and fit calibration results
        cal_fn = os.path.join(prefs.get('BASEDIR'), 'port_calibration.json')

        if os.path.exists(cal_fn):
            try:
                with open(cal_fn, 'r') as cal_file:
                    calibration = json.load(cal_file)
            except ValueError:
                # usually no json can be decoded, that's fine calibrations aren't expensive
                calibration = {}
        else:
            calibration = {}

        for port, results in value.items():
            if port in calibration.keys():
                calibration[port].extend(results)
            else:
                calibration[port] = results

        with open(cal_fn, 'w+') as cal_file:
            json.dump(calibration, cal_file)
Example #14
0
def pyo_server(debug=False):
    """
    Returns a booted and started pyo audio server

    Warning:
        Use of pyo is generally discouraged due to dropout issues and
        the general opacity of the module.

    Args:
        debug (bool): If true, setVerbosity of pyo server to 8.
    """
    # Jackd should already be running from the launch script created by setup_pilot, we we just
    pyo_server = pyo.Server(audio='jack',
                            nchnls=int(prefs.get('NCHANNELS')),
                            duplex=0,
                            buffersize=4096,
                            sr=192000,
                            ichnls=0)

    # Deactivate MIDI because we don't use it and it's expensive
    pyo_server.deactivateMidi()

    # We have to set pyo to not automatically try to connect to inputs when there aren't any
    pyo_server.setJackAuto(False, True)

    # debug
    if debug:
        pyo_server.setVerbosity(8)

    # Then boot and start
    pyo_server.boot()
    pyo_server.start()

    return pyo_server
Example #15
0
    def l_update(self, value):
        # receive two points, convert to distance, angle, and then to color
        if any(value[:, 2] < 0.2):
            return

        angle = self.transforms['angle'].process(value)
        distance = self.transforms['distance'].process(value)

        color = self.transforms['color'].process((angle, 1, distance))
        acquired = self.led_lock.acquire(blocking=False)
        if acquired:
            try:
                self.hardware['LEDS']['C'].set(r=color[0],
                                               g=color[1],
                                               b=color[2])
            finally:
                self.led_lock.release()

        # self.stream.put({
        #     'angle': angle,
        #     'distance': distance,
        #     'timestamp': datetime.now().isoformat(),
        #     'subject': self.subject
        # })
        self.node.send(
            'T', 'DATA', {
                'angle': angle,
                'distance': distance,
                'timestamp': datetime.now().isoformat(),
                'subject': self.subject,
                'pilot': prefs.get('NAME'),
                'continuous': True,
                't': time()
            })
def load_pilotdb(file_name=None, reverse=False):
    """
    Try to load the file_db

    Args:
        reverse (bool): Return inverted pilot db mapping subjects: pilots (default False)
        file_name (str): Path of ``pilot_db.json``, if None, use ``prefs.get('PILOT_DB')``

    Returns:
        :class:`collections.OrderedDict` : pilot_db.json or reversed pilot_db
    """

    if file_name is None:
        file_name = prefs.get('PILOT_DB')

    with open(file_name) as pilot_file:
        pilot_db = json.load(pilot_file, object_pairs_hook=odict)

    if reverse:
        # simplify pilot db
        pilot_db = odict({k: v['subjects'] for k, v in pilot_db.items()})
        pilot_dict = odict()
        for pilot, subjectlist in pilot_db.items():
            for ms in subjectlist:
                pilot_dict[ms] = pilot
        pilot_db = pilot_dict

    return pilot_db
Example #17
0
    def init_audio(self):
        """
        Initialize an audio server depending on the value of
        `prefs.get('AUDIOSERVER')`

        * 'pyo' = :func:`.pyoserver.pyo_server`
        * 'jack' = :class:`.jackclient.JackClient`
        """
        if prefs.get('AUDIOSERVER') == 'pyo':
            self.server = pyoserver.pyo_server()
            self.logger.info("pyo server started")
        elif prefs.get('AUDIOSERVER') in ('jack', True):
            self.jackd = external.start_jackd()
            self.server = jackclient.JackClient()
            self.server.start()
            self.logger.info('Started jack audio server')
Example #18
0
    def __init__(self, videos, fps=None):
        """
        Display Video data as it is collected.

        Uses the :class:`ImageItem_TimedUpdate` class to do timed frame updates.

        Args:
            videos (list, tuple): Names of video streams that will be displayed
            fps (int): if None, draw according to ``prefs.get('DRAWFPS')``. Otherwise frequency of widget update

        Attributes:
            videos (list, tuple): Names of video streams that will be displayed
            fps (int): if None, draw according to ``prefs.get('DRAWFPS')``. Otherwise frequency of widget update
            ifps (int): 1/fps, duration of frame in s
            qs (dict): Dictionary of :class:`~queue.Queue`s in which frames will be dumped
            quitting (:class:`threading.Event`): Signal to quit drawing
            update_thread (:class:`threading.Thread`): Thread with target=:meth:`~.Video._update_frame`
            layout (:class:`PySide2.QtWidgets.QGridLayout`): Widget layout
            vid_widgets (dict): dict containing widgets for each of the individual video streams.
        """
        super(Video, self).__init__()

        self.videos = videos

        if fps is None:
            if prefs.get('DRAWFPS'):
                self.fps = prefs.get('DRAWFPS')
            else:
                self.fps = 10
        else:
            self.fps = fps

        self.ifps = 1.0 / self.fps

        self.layout = None
        self.vid_widgets = {}

        #self.q = Queue(maxsize=1)
        self.qs = {}
        self.quitting = Event()
        self.quitting.clear()

        self.init_gui()

        self.update_thread = Thread(target=self._update_frame)
        self.update_thread.setDaemon(True)
        self.update_thread.start()
Example #19
0
    def __init__(self,
                 stim=None,
                 reward=50,
                 timeout=1000,
                 stage_block=None,
                 **kwargs):
        super(GoNoGo, self).__init__()

        self.stage_block = stage_block
        self.trial_counter = itertools.count()

        self.punish_dur = 500.0

        self.reward = reward
        self.timeout = timeout

        self.init_hardware()
        self.set_reward(self.reward)

        self.node = Net_Node(id="T_{}".format(prefs.get('NAME')),
                             upstream=prefs.get('NAME'),
                             port=prefs.get('MSGPORT'),
                             listens={},
                             instance=True)

        # get our child started
        self.subject = kwargs['subject']
        value = {
            'child': {
                'parent': prefs.get('NAME'),
                'subject': kwargs['subject']
            },
            'task_type': 'Wheel Child',
            'subject': kwargs['subject']
        }

        self.node.send(to=prefs.get('NAME'), key='CHILD', value=value)

        # hardcoding stimulus for testing
        self.stim = Grating(angle=0,
                            freq=(4, 0),
                            rate=1,
                            size=(1, 1),
                            debug=True)

        self.stages = itertools.cycle(
            [self.request, self.discrim, self.reinforce])
Example #20
0
    def get_name(self):
        """
        Usually Hardware is only instantiated with its pin number,
        but we can get its name from prefs
        """

        # TODO: Unify identification of hardware types across prefs and hardware objects
        try:
            our_type = prefs.get('HARDWARE')[self.type]
        except KeyError:
            our_type = prefs.get('HARDWARE')[self.__class__.__name__]

        for name, pin in our_type.items():
            if self.pin == pin:
                return name
            elif isinstance(pin, dict):
                if self.pin == pin['pin']:
                    return name
Example #21
0
    def __init__(self, pilot, x_width=50, parent=None):
        """
        Args:
            pilot (str): The name of our pilot
            x_width (int): How many trials in the past should we plot?
        """
        #super(Plot, self).__init__(QtOpenGL.QGLFormat(QtOpenGL.QGL.SampleBuffers), parent)
        super(Plot, self).__init__()

        self.logger = init_logger(self)

        self.parent = parent
        self.layout = None
        self.infobox = None
        self.n_trials = None
        self.session_trials = 0
        self.info = {}
        self.plot = None
        self.xrange = None
        self.plot_params = {}
        self.data = {
        }  # Keep a dict of the data we are keeping track of, will be instantiated on start
        self.plots = {}
        self.state = "IDLE"
        self.continuous = False
        self.last_time = 0
        self.video = None
        self.videos = []

        self.invoker = get_invoker()

        # The name of our pilot, used to listen for events
        self.pilot = pilot

        # Set initial x-value, will update when data starts coming in
        self.x_width = x_width
        self.last_trial = self.x_width

        # Inits the basic widget settings
        self.init_plots()

        ## Station
        # Start the listener, subscribes to terminal_networking that will broadcast data
        self.listens = {
            'START': self.l_start,  # Receiving a new task
            'DATA': self.l_data,  # Receiving a new datapoint
            'CONTINUOUS': self.l_data,
            'STOP': self.l_stop,
            'PARAM': self.l_param,  # changing some param
            'STATE': self.l_state
        }

        self.node = Net_Node(id='P_{}'.format(self.pilot),
                             upstream="T",
                             port=prefs.get('MSGPORT'),
                             listens=self.listens,
                             instance=True)
Example #22
0
    def open_file(self):
        """
        Setup a table to store data locally.

        Opens `prefs.get('DATADIR')/local.h5`, creates a group for the current subject,
        a new table for the current day.

        .. todo::

            This needs to be unified with a general file constructor abstracted from :class:`.Subject` so it doesn't reimplement file creation!!

        Returns:
            (:class:`tables.File`, :class:`tables.Table`,
            :class:`tables.tableextension.Row`): The file, table, and row for the local data table
        """
        local_file = os.path.join(prefs.get('DATADIR'), 'local.h5')
        try:
            h5f = tables.open_file(local_file, mode='a')
        except (IOError, tables.HDF5ExtError) as e:
            self.logger.warning("local file was broken, making new")
            self.logger.warning(e)
            os.remove(local_file)
            h5f = tables.open_file(local_file, mode='w')
            os.chmod(local_file, 0o777)

        try:
            h5f.create_group("/", self.subject,
                             "Local Data for {}".format(self.subject))
        except tables.NodeError:
            # already made it
            pass
        subject_group = h5f.get_node('/', self.subject)

        # Make a table for today's data, appending a conflict-avoidance int if one already exists
        datestring = datetime.date.today().isoformat()
        conflict_avoid = 0
        while datestring in subject_group:
            conflict_avoid += 1
            datestring = datetime.date.today().isoformat() + '-' + str(
                conflict_avoid)

        # Get data table descriptor
        if hasattr(self.task, 'TrialData'):
            table_descriptor = self.task.TrialData

            table = h5f.create_table(
                subject_group, datestring, table_descriptor,
                "Subject {} on {}".format(self.subject, datestring))

            # The Row object is what we write data into as it comes in
            row = table.row
            return h5f, table, row

        else:
            return h5f, None, None
Example #23
0
    def boot_server(self):
        """
        Called by :meth:`.JackClient.run` to boot the server upon starting the process.

        Activates the client and connects it to the number of outports
        determined by `prefs.get('NCHANNELS')`

        :class:`jack.Client` s can't be kept alive, so this must be called just before
        processing sample starts.
        """

        self.client = jack.Client(self.name)
        self.blocksize = self.client.blocksize
        self.fs = self.client.samplerate
        self.zero_arr = np.zeros((self.blocksize, 1), dtype='float32')

        self.client.set_process_callback(self.process)

        self.client.outports.register('out_0')

        self.client.activate()
        target_ports = self.client.get_ports(is_physical=True,
                                             is_input=True,
                                             is_audio=True)

        if prefs.get('OUTCHANNELS'):
            if isinstance(prefs.get('OUTCHANNELS'), list):
                for outchan in prefs.get('OUTCHANNELS'):

                    self.client.outports[0].connect(target_ports[int(outchan)])
            elif isinstance(prefs.get('OUTCHANNELS'), int):
                self.client.outports[0].connect(
                    target_ports[prefs.get('OUTCHANNELS')])
            elif isinstance(prefs.get('OUTCHANNELS'), str):
                try:
                    self.client.outports[0].connect(target_ports[int(
                        prefs.get('OUTCHANNELS'))])
                except TypeError:
                    Exception(
                        'Could not coerce prefs.get(\'OUTCHANNELS\') to an integer or list of ints. Connecting to port 0. got {}'
                        .format(prefs.get('OUTCHANNELS')))
                    self.client.outports[0].connect(target_ports[0])
        else:
            self.client.outports[0].connect(target_ports[0])
            if prefs.get('NCHANNELS') == 2:
                # TODO: Limited, obvs. want to handle arbitrary output arrangements.
                self.client.outports[0].connect(target_ports[1])
Example #24
0
    def calibration_curve(self, path=None, calibration=None):
        """
        # compute curve to compute duration from desired volume

        Args:
            calibration:
            path: If present, use calibration file specified, otherwise use default.
        """

        lut_fn = os.path.join(prefs.get('BASEDIR'),
                              'port_calibration_fit.json')

        if not calibration:
            # if we weren't given calibration results, load them
            if path:
                open_fn = path
            else:
                open_fn = os.path.join(prefs.get('BASEDIR'),
                                       "port_calibration.json")

            with open(open_fn, 'r') as open_f:
                calibration = json.load(open_f)

        luts = {}
        for port, samples in calibration.items():
            sample_df = pd.DataFrame(samples)
            # TODO: Filter for only most recent timestamps

            # volumes are saved in mL because of how they are measured, durations are stored in ms
            # but reward volumes are typically in the uL range, so we make the conversion
            # by multiplying by 1000
            line_fit = linregress(
                (sample_df['vol'] / sample_df['n_clicks']) * 1000.,
                sample_df['dur'])
            luts[port] = {
                'intercept': line_fit.intercept,
                'slope': line_fit.slope
            }

        # write to file, overwriting any previous
        with open(lut_fn, 'w') as lutf:
            json.dump(luts, lutf)
Example #25
0
 def protocols(self):
     """
     Returns:
         list: list of protocol files in ``prefs.get('PROTOCOLDIR')``
     """
     # get list of protocol files
     protocols = os.listdir(prefs.get('PROTOCOLDIR'))
     protocols = [
         os.path.splitext(p)[0] for p in protocols if p.endswith('.json')
     ]
     return protocols
Example #26
0
    def _stream(self):
        self.node = Net_Node("T_CHILD",
                             upstream=prefs.get('NAME'),
                             port=prefs.get('MSGPORT'),
                             listens={},
                             instance=True)

        while True:
            for name, cam in self.cams.items():
                try:
                    frame, timestamp = cam.q.get_nowait()
                    self.node.send(key='CONTINUOUS',
                                   value={
                                       cam.name: frame,
                                       'timestamp': timestamp
                                   },
                                   repeat=False,
                                   flags={'MINPRINT': True})
                except Empty:
                    pass
Example #27
0
    def dlc_dir(self) -> str:
        """
        ``{prefs.get('BASE_DIR')}/dlc``
        Returns:
            str
        """
        if 'DLCDIR' in prefs._PREFS.keys():
            dlc_dir = prefs.get('DLCDIR')
        else:
            dlc_dir = os.path.join(prefs.get('BASEDIR'), 'dlc')
            if not os.path.exists(dlc_dir):
                try:
                    os.mkdir(dlc_dir)

                except OSError as e:
                    raise OSError(
                        f'No DLC dir found and one could not be created!\n{e}')
            prefs.set('DLC_DIR', dlc_dir)

        return dlc_dir
Example #28
0
    def __init__(self, stage_block=None, fs=10, thresh=100, **kwargs):
        self.fs = fs
        self.thresh = thresh

        self.hardware = {}
        self.hardware['OUTPUT'] = Digital_Out(prefs.get('HARDWARE')['OUTPUT'])
        self.hardware['WHEEL'] = Wheel(digi_out=self.hardware['OUTPUT'],
                                       fs=self.fs,
                                       thresh=self.thresh,
                                       mode="steady")
        self.stages = cycle([self.noop])
        self.stage_block = stage_block
Example #29
0
def start_pigpiod():
    if not PIGPIO:
        raise ImportError('the pigpiod daemon was not found! use autopilot.setup.')

    with globals()['PIGPIO_LOCK']:
        if globals()['PIGPIO_DAEMON'] is not None:
            return globals()['PIGPIO_DAEMON']

        launch_pigpiod = shutil.which('pigpiod')
        if launch_pigpiod is None:
            raise RuntimeError('the pigpiod binary was not found!')

        if prefs.get( 'PIGPIOARGS'):
            launch_pigpiod += ' ' + prefs.get('PIGPIOARGS')

        if prefs.get( 'PIGPIOMASK'):
            # if it's been converted to an integer, convert back to a string and zfill any leading zeros that were lost
            if isinstance(prefs.get('PIGPIOMASK'), int):
                prefs.set('PIGPIOMASK', str(prefs.get('PIGPIOMASK')).zfill(28))
            launch_pigpiod += ' -x ' + prefs.get('PIGPIOMASK')

        proc = subprocess.Popen('sudo ' + launch_pigpiod, shell=True)
        globals()['PIGPIO_DAEMON'] = proc

        # kill process when session ends
        def kill_proc(*args):
            proc.kill()
            sys.exit(1)
        atexit.register(kill_proc)
        signal.signal(signal.SIGTERM, kill_proc)

        # sleep to let it boot up
        sleep(1)

        return proc
Example #30
0
    def __init__(self, path, amplitude=0.01, **kwargs):
        """
        Args:
            path (str): Path to a .wav file relative to the `prefs.get('SOUNDDIR')`
            amplitude (float): amplitude of the sound as a proportion of 1.
            **kwargs: extraneous parameters that might come along with instantiating us
        """
        super(File, self).__init__()

        if os.path.exists(path):
            self.path = path
        elif os.path.exists(os.path.join(prefs.get('SOUNDDIR'), path)):
            self.path = os.path.join(prefs.get('SOUNDDIR'), path)
        else:
            Exception(
                'Could not find {} in current directory or sound directory'.
                format(path))

        self.amplitude = float(amplitude)

        # because files can be v memory intensive, we only load the sound once we're called to buffer them
        # store our initialization status
        self.initialized = False