Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nate's task #11

Merged
merged 7 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 50 additions & 7 deletions iblrig_custom_tasks/nate_optoBiasedChoiceWorld/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@

Additionally the state machine is modified to add output TTLs for optogenetic stimulation
"""

import logging
import random
import sys
from importlib.util import find_spec
from pathlib import Path
from typing import Literal

Expand All @@ -17,6 +21,13 @@
from iblrig.base_choice_world import SOFTCODE, BiasedChoiceWorldSession
from pybpodapi.protocol import StateMachine

sys.path.append('C:\zapit-tcp-bridge\python')
if find_spec('TCPclient') is None:
raise ImportError(f'{__file__} requires zapit-tcp-bridge')
from TCPclient import TCPclient

stim_location_history = []

log = logging.getLogger('iblrig.task')

INTERACTIVE_DELAY = 1.0
Expand All @@ -40,11 +51,13 @@ def __init__(
is_opto_stimulation=False,
states_opto_ttls=None,
states_opto_stop=None,
states_mask_ttls=None,
):
super().__init__(bpod)
self.is_opto_stimulation = is_opto_stimulation
self.states_opto_ttls = states_opto_ttls or []
self.states_opto_stop = states_opto_stop or []
self.states_mask_ttls = states_mask_ttls or []

def add_state(self, **kwargs):
if self.is_opto_stimulation:
Expand All @@ -55,11 +68,16 @@ def add_state(self, **kwargs):
]
elif kwargs['state_name'] in self.states_opto_stop:
kwargs['output_actions'] += [('SoftCode', SOFTCODE_STOP_ZAPIT)]
if kwargs['state_name'] in self.states_mask_ttls:
kwargs['output_actions'] += [
('PWM1', 255),
]
super().add_state(**kwargs)


class Session(BiasedChoiceWorldSession):
protocol_name = 'nate_optoBiasedChoiceWorld'
extractor_tasks = ['TrialRegisterRaw', 'ChoiceWorldTrials', 'TrainingStatus']

def __init__(
self,
Expand All @@ -68,19 +86,16 @@ def __init__(
contrast_set_probability_type: Literal['skew_zero', 'uniform'] = DEFAULTS['CONTRAST_SET_PROBABILITY_TYPE'],
opto_ttl_states: list[str] = DEFAULTS['OPTO_TTL_STATES'],
opto_stop_states: list[str] = DEFAULTS['OPTO_STOP_STATES'],
mask_ttl_states: list[str] = DEFAULTS['MASK_TTL_STATES'],
**kwargs,
):
super().__init__(*args, **kwargs)
self.task_params['CONTRAST_SET_PROBABILITY_TYPE'] = contrast_set_probability_type
self.task_params['OPTO_TTL_STATES'] = opto_ttl_states
self.task_params['OPTO_STOP_STATES'] = opto_stop_states
self.task_params['MASK_TTL_STATES'] = mask_ttl_states
self.task_params['PROBABILITY_OPTO_STIM'] = probability_opto_stim

# loads in the settings in order to determine the main sync and thus the pipeline extractor tasks
is_main_sync = self.hardware_settings.get('MAIN_SYNC', False)
trials_task = 'OptoTrialsBpod' if is_main_sync else 'OptoTrialsNidq'
self.extractor_tasks = ['TrialRegisterRaw', trials_task, 'TrainingStatus']

# generates the opto stimulation for each trial
self.trials_table['opto_stimulation'] = np.random.choice(
[0, 1],
Expand All @@ -89,6 +104,12 @@ def __init__(
).astype(bool)

def start_hardware(self):
self.client = TCPclient(tcp_port=1488, tcp_ip='127.0.0.1')

self.client.close() # need to ensure is closed first; currently nowhere that this is defined at end of task!
self.client.connect()
self.num_cond = self.client.get_num_conditions()[1][0]
log.warning(f'Number of conditions: {self.num_cond}')
super().start_hardware()
# add the softcodes for the zapit opto stimulation
soft_code_dict = self.bpod.softcodes
Expand All @@ -98,15 +119,27 @@ def start_hardware(self):

def zapit_arm_laser(self):
log.warning('Arming laser')
# TODO: insert code for arming the laser here
# this is where you define the laser stim (i.e., arm the laser)

self.current_location_idx = random.randrange(1, int(self.num_cond))

# hZP.send_samples(
# conditionNum=current_location_idx, hardwareTriggered=True, logging=True
# )
response = self.client.send_samples(
conditionNum=self.current_location_idx, laser_On=True, hardwareTriggered_On=True, logging_On=True
)
log.warning(response)
stim_location_history.append(self.current_location_idx)

def zapit_fire_laser(self):
# just logging - actual firing will be triggered by the state machine via TTL
# this really only triggers a ttl and sends a log entry - no need to plug in code here
log.warning('Firing laser')

def zapit_stop_laser(self):
log.warning('Stopping laser')
# TODO: insert code for stopping the laser here
response = self.client.stop_optostim()

def _instantiate_state_machine(self, trial_number=None):
"""
Expand All @@ -123,6 +156,7 @@ def _instantiate_state_machine(self, trial_number=None):
is_opto_stimulation=is_opto_stimulation,
states_opto_ttls=self.task_params['OPTO_TTL_STATES'],
states_opto_stop=self.task_params['OPTO_STOP_STATES'],
states_mask_ttls=self.task_params['MASK_TTL_STATES'],
)

@staticmethod
Expand Down Expand Up @@ -164,6 +198,15 @@ def extra_parser():
type=str,
help='list of the state machine states where opto stim should be stopped',
)
parser.add_argument(
'--mask_ttl_states',
option_strings=['--mask_ttl_states'],
dest='mask_ttl_states',
default=DEFAULTS['MASK_TTL_STATES'],
nargs='+',
type=str,
help='list of the state machine states where mask stim should be delivered',
)
return parser


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,19 @@
- no_go
- error
- reward
'MASK_TTL_STATES': # list of the state machine states where mask stim should be delivered
- trial_start
- delay_initiation
- reset_rotary_encoder
- quiescent_period
- stim_on
- interactive_delay
- play_tone
- reset2_rotary_encoder
- closed_loop
- no_go
- freeze_error
- error
- freeze_reward
- reward
'PROBABILITY_OPTO_STIM': 0.2 # probability of optogenetic stimulation
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Here we test for the state machine code and the task to be importable by the GUI
"""

from iblrig_custom_tasks.nate_optoBiasedChoiceWorld.task import Session

task = Session(subject='toto')
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "project_extraction"
version = "0.2.3"
version = "0.2.4"
description = "Custom extractors for satellite tasks"
dynamic = [ "readme" ]
keywords = [ "IBL", "neuro-science" ]
Expand Down
Loading