@@method<bool threshDistanceSensor(int sensorIndex)> bool threshDistanceSensor(int sensorIndex) { Serial.print("Thresholding distance sensor "); Serial.println(sensorIndex); return readAI(distanceSensorPins[sensorIndex]) > distanceSensorThresholds[sensorIndex]; }
/* TICK FUNCTION GETS CALLED EVERY TICK - i.e. at 6kHz*/ void tick_func(void) { /* Check if run is stopping */ if (stop_run == 0){ /* Monitor scim ai vlt - if voltage is low set scim_state low */ scim_ai_vlt = readAI(scan_image_frame_clock_chan); if (scim_ai_vlt <= ai_threshold) { scim_state = 0; } /* Read ball tracker ai vlt */ ball_tracker_clock_ai_vlt = readAI(ball_tracker_clock_ai_chan); /* If second read - i.e. at 500Hz */ if (second_ai_read == 1) { second_ai_read = 0; /* Check if ball clock low*/ if (ball_tracker_clock_ai_vlt < ai_threshold) { ball_tracker_clock_low_flag = 1; } /* Generate camera displacement vector */ /* average current AI read with AI read from last tick */ for (ii = 0; ii < 4; ii++) { cam_vel_ai_vlt[ii] = (cam_vel_ai_vlt[ii] + readAI(cam_ai_chan[ii]))/2; /* convert to steps */ cam_vel_steps[ii] = round((cam_vel_ai_vlt[ii] - zero_V[ii])/step_V); } /* calculate forward and lateral motion */ for_ball_motion = 0; lat_ball_motion = 0; for (ii = 0; ii < 4; ii++) { for_ball_motion = for_ball_motion + A_calib[0][ii]*cam_vel_steps[ii]; lat_ball_motion = lat_ball_motion + A_calib[1][ii]*cam_vel_steps[ii]; } /* Calculate mean forward and lateral velocity */ if (cur_speed_ind == speed_time_length) { cur_speed_ind = 0; } for_vel_history[cur_speed_ind] = for_ball_motion; lat_vel_history[cur_speed_ind] = lat_ball_motion; cur_speed_ind++; mean_for_vel = 0; mean_lat_vel = 0; for (jj = 0; jj < speed_time_length; jj++) { mean_for_vel = mean_for_vel + for_vel_history[jj]; mean_lat_vel = mean_lat_vel + lat_vel_history[jj]; } mean_for_vel = mean_for_vel/speed_time_length; mean_lat_vel = mean_lat_vel/speed_time_length; /* Check if running or not */ if (mean_for_vel > run_speed_thresh) { running_ind = 1; } else { running_ind = 0; } /* Check if licked */ lick_in_vlt = readAI(lick_in_chan); if (lick_in_vlt > 1) { lick_state = 1; } else { lick_state = 0; } /* Check if trial has ended, and if so make a new one */ if (frac_trial >= 1 || cur_trial_time >= trial_timeout[cur_trial_num]) { /* Pick new trial number */ if (trial_random_order == 1) { cur_trial_num = (unsigned int) (trial_num_types)*rand(); } else { cur_trial_num = trial_num_sequence[cur_trial_block]-1; cur_trial_repeat++; if (cur_trial_repeat >= trial_num_repeats[cur_trial_block]){ cur_trial_block++; cur_trial_repeat = 0; } if (cur_trial_block >= trial_num_sequence_length) { cur_trial_block = 0; } } /* Determine target left and right starting wall positions */ if (trial_cor_reset[cur_trial_num] == 1) { cor_pos = trial_ol_values[cur_trial_num][0]; } cor_width = trial_cor_width[cur_trial_num][0]; l_lat_pos_target = cor_width - cor_pos; r_lat_pos_target = cor_pos; if (trial_left_wall[cur_trial_num] == 0){ l_lat_pos_target = max_wall_pos; } if (trial_right_wall[cur_trial_num] == 0){ r_lat_pos_target = max_wall_pos; } inter_trial_time = 0; test_val = 0; test_val_exit = 0; mf_val = 0; mf_val_exit = 0; ps_val = 0; ps_val_exit = 0; turn_period = 0; gain_period = 0; ol_period = 0; water_period = 0; cur_trial_time = 0; cur_trial_dist = 0; cur_trial_lat = 0; frac_trial = 0; frac_trial_prev = 0; wv_time = 0; bv_time = 0; mf_period_counter = 0; ps_period_counter = 0; ps_spots_counter = 0; } /* Check if in iti */ if (inter_trial_time <= trial_iti[cur_trial_num]) { inter_trial_trig = 1; inter_trial_time = inter_trial_time + 1/sample_freq; /* send left and right walls to target positions */ l_lat_pos = l_lat_pos + .008*(l_lat_pos_target - l_lat_pos); r_lat_pos = r_lat_pos + .008*(r_lat_pos_target - r_lat_pos); } else { /* During trial */ inter_trial_trig = 0; /* Determine how far along trial */ if (trial_type[cur_trial_num] == 1) { frac_trial = cur_trial_dist/trial_duration[cur_trial_num]; } else { frac_trial = cur_trial_time/trial_timeout[cur_trial_num]; } /* Check limits */ if (frac_trial < 0){ frac_trial = 0; } /* Get the current corridor width value - check all turn positions and see which one in */ for (ii = 0; ii < trial_num_cor_widths-1; ii++) { if (frac_trial >= trial_cor_width_positions[cur_trial_num][ii] & frac_trial < trial_cor_width_positions[cur_trial_num][ii+1]){ cor_period = ii; } } /* Get the current ol pos value - check all turn positions and see which one in */ for (ii = 0; ii < trial_num_open_loop-1; ii++) { if (frac_trial >= trial_ol_positions[cur_trial_num][ii] & frac_trial < trial_ol_positions[cur_trial_num][ii+1]){ ol_period = ii; } } /* Get the current gain value - check all gain positions and see which one in */ for (ii = 0; ii < trial_num_gain; ii++) { if (frac_trial >= trial_gain_positions[cur_trial_num][ii] & frac_trial < trial_gain_positions[cur_trial_num][ii+1]){ gain_period = ii; } } /* Get the current turn value - check all turn positions and see which one in */ for (ii = 0; ii < trial_num_turns; ii++) { if (frac_trial >= trial_turn_positions[cur_trial_num][ii] & frac_trial < trial_turn_positions[cur_trial_num][ii+1]){ turn_period = ii; } } /* update corridor width */ cor_width_start = trial_cor_width[cur_trial_num][cor_period]; cor_width_stop = trial_cor_width[cur_trial_num][cor_period+1]; cor_width_update = (frac_trial - trial_cor_width_positions[cur_trial_num][cor_period])/(trial_cor_width_positions[cur_trial_num][cor_period+1] - trial_cor_width_positions[cur_trial_num][cor_period])*cor_width_stop + (trial_cor_width_positions[cur_trial_num][cor_period+1] - frac_trial)/(trial_cor_width_positions[cur_trial_num][cor_period+1] - trial_cor_width_positions[cur_trial_num][cor_period])*cor_width_start; cor_width_offset = (cor_width_update - cor_width)/2; cor_width = cor_width_update; cor_pos = cor_pos + cor_width_offset; if (cor_width > max_cor_width){ cor_width = max_cor_width; } if (cor_width < 0){ cor_width = 0; } /* update open loop wall position */ cor_pos_target_start = trial_ol_values[cur_trial_num][ol_period]; cor_pos_target_stop = trial_ol_values[cur_trial_num][ol_period+1]; /*cor_pos_update = (frac_trial - trial_ol_positions[cur_trial_num][ol_period])/(trial_ol_positions[cur_trial_num][ol_period+1] - trial_ol_positions[cur_trial_num][ol_period])*cor_pos_target_stop + (trial_ol_positions[cur_trial_num][ol_period+1] - frac_trial)/(trial_ol_positions[cur_trial_num][ol_period+1] - trial_ol_positions[cur_trial_num][ol_period])*cor_pos_target_start;*/ cor_pos_update = (cor_pos_target_stop - cor_pos_target_start)/(trial_ol_positions[cur_trial_num][ol_period+1] - trial_ol_positions[cur_trial_num][ol_period])*(frac_trial - frac_trial_prev); frac_trial_prev = frac_trial; cor_pos = cor_pos + cor_pos_update; /* update gain value */ gain_val = trial_gain_values[cur_trial_num][gain_period]; /* update turn value */ turn_val = trial_turn_values[cur_trial_num][turn_period]; /* update closed loop corridor position */ cor_pos = cor_pos - 10*wall_ball_gain/sample_freq*gain_val*(for_ball_motion*sin(turn_val*3.141/180) + lat_ball_motion*cos(turn_val*3.141/180)); /* Check cor pos bounds */ if (cor_pos > cor_width) { cor_pos = cor_width; } if (cor_pos < 0) { cor_pos = 0; } l_lat_pos = cor_width - cor_pos; r_lat_pos = cor_pos; /* Check walls enabled */ if (trial_left_wall[cur_trial_num] == 0){ l_lat_pos = max_wall_pos; } if (trial_right_wall[cur_trial_num] == 0){ r_lat_pos = max_wall_pos; } /* Get the current test period value */ if (test_val_exit == 0 & frac_trial >= trial_test_period[cur_trial_num][0] & frac_trial < trial_test_period[cur_trial_num][1]){ test_val = 1; } if (frac_trial >= trial_test_period[cur_trial_num][1]){ test_val = 0; test_val_exit = 1; } /* determine contingency on how water is being delivered */ if (trial_water_range_type[cur_trial_num] == 0){ water_pos_val = cor_pos; } else if (trial_water_range_type[cur_trial_num] == 1) { water_pos_val = cor_pos/cor_width; } else { water_pos_val = cur_trial_lat; } /* Get the current water period value */ if (water_period < trial_num_water_drops){ /* Decide if delivering water */ if (trial_water_enabled[cur_trial_num] == 1 & frac_trial >= trial_water_pos[cur_trial_num][water_period] & water_pos_val >= trial_water_range_min[cur_trial_num][water_period] & water_pos_val <= trial_water_range_max[cur_trial_num][water_period]){ water_on = 1; valve_open_time = trial_water_drop_size[cur_trial_num][water_period]; valve_open_time = round(valve_open_time/2); water_period++; } } /* Get the current mf period value */ if (trial_masking_flash[cur_trial_num] > 0 & mf_val_exit == 0 & frac_trial >= trial_mf_period[cur_trial_num][0] & frac_trial < trial_mf_period[cur_trial_num][1]){ mf_val = 1; } if (frac_trial >= trial_mf_period[cur_trial_num][1]){ mf_val = 0; mf_val_exit = 1; } /* Get the current ps period value */ if (trial_photostim[cur_trial_num] > 0 & ps_val_exit == 0 & frac_trial >= trial_ps_period[cur_trial_num][0] & frac_trial < trial_ps_period[cur_trial_num][1]){ ps_val = 1; } if (frac_trial >= trial_ps_period[cur_trial_num][1]){ ps_val = 0; ps_val_exit = 1; } /* Update trial distance and trial time */ cur_trial_dist = cur_trial_dist + for_ball_motion/sample_freq; cur_trial_lat = cur_trial_lat + lat_ball_motion/sample_freq; cur_trial_time = cur_trial_time + 1/sample_freq; } /* Check bounds of wall position */ if (r_lat_pos > max_wall_pos) { r_lat_pos = max_wall_pos; } if (r_lat_pos < 0) { r_lat_pos = 0; } if (l_lat_pos > max_wall_pos) { l_lat_pos = max_wall_pos; } if (l_lat_pos < 0) { l_lat_pos = 0; } r_for_pos = r_for_pos_default; l_for_pos = l_for_pos_default; /* Send AO for wall position */ r_for_vlt = wall_mm_to_vlt(r_for_pos); l_for_vlt = wall_mm_to_vlt(l_for_pos); r_lat_vlt = wall_mm_to_vlt(r_lat_pos); l_lat_vlt = wall_mm_to_vlt(l_lat_pos); writeAO(r_wall_for_ao_chan, r_wall_for_ao_offset + r_for_vlt); writeAO(r_wall_lat_ao_chan, r_wall_lat_ao_offset + r_lat_vlt); writeAO(l_wall_for_ao_chan, l_wall_for_ao_offset + l_for_vlt); writeAO(l_wall_lat_ao_chan, l_wall_lat_ao_offset + l_lat_vlt); if (ext_valve_trig == 1 || water_dist > dist_thresh & dist_thresh < 200){ water_on_ext = 1; } water_dist = water_dist + for_ball_motion/sample_freq; /* If delivering water */ if (water_on == 1) { if (valve_time < valve_open_time) { } else { valve_time = 0; water_on = 0; } valve_time++; } if (water_on_ext == 1) { if (valve_time_ext < valve_open_time_default) { } else { valve_time_ext = 0; water_on_ext = 0; water_dist = 0; ext_valve_trig = 0; } valve_time_ext++; } if (water_on == 1 || water_on_ext == 1) { writeDIO(water_valve_trig, 1); } else { writeDIO(water_valve_trig, 0); } tick_period = 0; /* Masking flash */ if (mf_val == 1){ if (mf_period_counter >= trial_mf_pulse_dur[cur_trial_num] + trial_mf_pulse_iti[cur_trial_num]){ mf_period_counter = 0; } if (mf_period_counter < trial_mf_pulse_dur[cur_trial_num]){ masking_flash_on = 1; } else { masking_flash_on = 0; } mf_period_counter++; } else { masking_flash_on = 0; } if (trial_masking_flash[cur_trial_num] == 1) { writeDIO(mf_dio_blue, masking_flash_on); writeDIO(mf_dio_yellow, 0); } else if (trial_masking_flash[cur_trial_num] == 2) { writeDIO(mf_dio_blue, 0); writeDIO(mf_dio_yellow, masking_flash_on); } else { writeDIO(mf_dio_blue, masking_flash_on); writeDIO(mf_dio_yellow, masking_flash_on); } /* Deal with laser and galvos */ if (ps_val == 1){ if (ps_period_counter >= trial_ps_num_sites[cur_trial_num]*trial_ps_pulse_dur[cur_trial_num] + trial_ps_pulse_iti[cur_trial_num]){ ps_period_counter = 0; } if (ps_period_counter < trial_ps_num_sites[cur_trial_num]*trial_ps_pulse_dur[cur_trial_num]){ laser_shutter = 0; cur_site_ind = floor(ps_period_counter/trial_ps_pulse_dur[cur_trial_num]); if (trial_ps_closed_loop[cur_trial_num] == 1) { if (cor_pos < cor_width/2) { laser_power = trial_ps_peak_power[cur_trial_num]*(cor_width/2 - cor_pos)/(cor_width/2); x_mirror_pos = trial_ps_x_pos[cur_trial_num][cur_site_ind]; } else { laser_power = trial_ps_peak_power[cur_trial_num]*(cor_pos - cor_width/2)/(cor_width/2); x_mirror_pos = -trial_ps_x_pos[cur_trial_num][cur_site_ind]; } y_mirror_pos = trial_ps_y_pos[cur_trial_num][cur_site_ind]; } else { laser_power = trial_ps_peak_power[cur_trial_num]; x_mirror_pos = trial_ps_x_pos[cur_trial_num][cur_site_ind]; y_mirror_pos = trial_ps_y_pos[cur_trial_num][cur_site_ind]; } } else { laser_power = 0; } ps_period_counter++; } else { laser_shutter = 1; } if (trial_ps_stop_threshold[cur_trial_num] == 1 & running_ind == 0) { laser_power = 0; } if (laser_calibration_mode == 1) { if (x_mirror_pos > 10){ x_mirror_pos = 10; } if (x_mirror_pos < -10){ x_mirror_pos = -10; } if (y_mirror_pos > 10){ y_mirror_pos = 10; } if (y_mirror_pos < -10){ y_mirror_pos = -10; } x_mirror_pos_vlt = x_mirror_pos; y_mirror_pos_vlt = y_mirror_pos; if (laser_power > 5){ laser_power = 5; } if (laser_power < 0){ laser_power = 0; } laser_power_vlt = laser_power; } else { x_mirror_pos_vlt = galvo_x_mm_to_vlt(x_mirror_pos); y_mirror_pos_vlt = galvo_y_mm_to_vlt(y_mirror_pos); if (trial_photostim[cur_trial_num] == 1) { laser_power_vlt = blue_laser_mW_to_vlt(laser_power); } else if (trial_photostim[cur_trial_num] == 2) { laser_power_vlt = yellow_laser_mW_to_vlt(laser_power); } else { laser_power_vlt = blue_laser_mW_to_vlt(laser_power); } } if (laser_shutter == 1) { laser_power = 0; laser_power_vlt = 0; x_mirror_pos = - max_galvo_pos; y_mirror_pos = - max_galvo_pos; x_mirror_pos_vlt = 8; y_mirror_pos_vlt = 8; } writeAO(laser_power_ao_chan, laser_power_ao_offset + laser_power_vlt); writeAO(x_mirror_ao_chan, x_mirror_ao_offset + x_mirror_pos_vlt); writeAO(y_mirror_ao_chan, y_mirror_ao_offset + y_mirror_pos_vlt); /* Send triggers for behaviour cameras*/ if (bv_time == 0 && inter_trial_trig == 0) { writeDIO(bv_trig, 1); } else { writeDIO(bv_trig, 0); } bv_time++; if (bv_time == bv_period) { bv_time = 0; } /* Send triggers for whisker cameras*/ if (wv_time == 0 && inter_trial_trig == 0) { writeDIO(wv_trig, 1); led_pulse_on = 0; } else { writeDIO(wv_trig, 0); } wv_time++; if (wv_time == wv_period) { wv_time = 0; } /* Trial DO Triggers */ writeDIO(trial_iti_trig, inter_trial_trig); writeDIO(trial_on_trig, 1-inter_trial_trig); writeDIO(trial_test_trig, test_val); writeDIO(trial_ephys_trig, 1-inter_trial_trig); writeAO(iti_ao_chan, iti_ao_offset + 5*(inter_trial_trig)); /* Sync pulse */ writeDIO(synch_pulse, 1); writeAO(synch_ao_chan, synch_ao_offset + 5); led_pulse_on = 0; scim_logging_ai_vlt = readAI(scim_logging_chan); if (scim_logging_ai_vlt >= ai_threshold) { scim_logging = 1; } else { scim_logging = 0; } /* Create Log Vectors */ log_state_a = water_on + 2*lick_state + 4*inter_trial_trig; log_state_b = scim_state + 2*masking_flash_on + 4*running_ind; log_state_c = test_val + 2*scim_logging + 4*water_on_ext; log_cur_state = 10000*log_state_c+1000*log_state_b+100*log_state_a + cur_trial_num; log_ball_motion = cam_vel_steps[0] + 36*cam_vel_steps[1] + 36*36*cam_vel_steps[2]+ 36*36*36*cam_vel_steps[3]; /* convert to cam_motion_vect for logging */ if (laser_calibration_mode == 1){ if (scim_ai_vlt < 0 ) { scim_ai_vlt = 0; } log_cor_pos = 100*scim_ai_vlt; log_photo_stim = floor(10*laser_power)*10000 + floor((x_mirror_pos+max_galvo_pos)*10)*100 + floor((y_mirror_pos+max_galvo_pos)*10); } else { log_cor_pos = floor(10*cor_pos) + 1000*floor(10*(cor_width)); log_photo_stim = floor(10*laser_power)*10000 + floor((x_mirror_pos+max_galvo_pos)*10)*100 + floor((y_mirror_pos+max_galvo_pos)*10); } /* log_cor_pos = cam_vel_ai_vlt[0]*1000;*/ logValue("ps", log_photo_stim); /* stim code */ logValue("bm", log_ball_motion); /* ball_motion_vector code */ logValue("wm", log_cor_pos); /* wall pos */ logValue("st", log_cur_state); /* state_vector code */ scim_state = 1; } else { if (ball_tracker_clock_ai_vlt >= ai_threshold && ball_tracker_clock_low_flag == 1) { for (ii = 0; ii < 4; ii++) { cam_vel_ai_vlt[ii] = readAI(cam_ai_chan[ii]); } ball_tracker_clock_low_flag = 0; second_ai_read = 1; led_pulse_on++; if (led_pulse_on > 2){ writeDIO(wv_trig, 0); writeDIO(synch_pulse, 0); writeAO(synch_ao_chan, synch_ao_offset); } } else if (ball_tracker_clock_ai_vlt < ai_threshold) { ball_tracker_clock_low_flag = 1; led_pulse_on++; if (led_pulse_on > 2){ writeDIO(wv_trig, 0); writeDIO(synch_pulse, 0); } } } } else { /* If run is stopping */ /* send left and right walls to target positions */ l_lat_pos = l_lat_pos + .0005*(max_wall_pos - l_lat_pos); r_lat_pos = r_lat_pos + .0005*(max_wall_pos - r_lat_pos); if (r_lat_pos > max_wall_pos) { r_lat_pos = max_wall_pos; } if (r_lat_pos < 0) { r_lat_pos = 0; } if (l_lat_pos > max_wall_pos) { l_lat_pos = max_wall_pos; } if (l_lat_pos < 0) { l_lat_pos = 0; } r_lat_vlt = wall_mm_to_vlt(r_lat_pos); l_lat_vlt = wall_mm_to_vlt(l_lat_pos); writeAO(r_wall_lat_ao_chan, r_wall_lat_ao_offset + r_lat_vlt); writeAO(l_wall_lat_ao_chan, l_wall_lat_ao_offset + l_lat_vlt); writeAO(r_wall_for_ao_chan, r_wall_for_ao_offset + r_for_vlt); writeAO(l_wall_for_ao_chan, l_wall_for_ao_offset + l_for_vlt); writeAO(laser_power_ao_chan , laser_power_ao_offset); writeAO(x_mirror_ao_chan , x_mirror_ao_offset); writeAO(y_mirror_ao_chan , y_mirror_ao_offset); writeAO(iti_ao_chan, iti_ao_offset); writeAO(synch_ao_chan, synch_ao_offset); writeDIO(water_valve_trig, 0); writeDIO(trial_test_trig, 0); writeDIO(wv_trig, 0); writeDIO(bv_trig, 0); writeDIO(sound_trig, 0); writeDIO(mf_dio_blue, 0); writeDIO(mf_dio_yellow, 0); writeDIO(sound_trig_2, 0); writeDIO(trial_on_trig, 0); writeDIO(trial_iti_trig, 0); writeDIO(synch_pulse, 0); writeDIO(trial_ephys_trig, 0); } }
@@method<int readDistanceSensor(int sensorIndex)> int readDistanceSensor(int sensorIndex) { Serial.print("Reading distance sensor "); Serial.println(sensorIndex); return readAI(distanceSensorPins[sensorIndex]); }