Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
olfStim/olfStimStartTrial.m
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
374 lines (311 sloc)
15.1 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function smell = olfStimStartTrial(trialNum, smell) | |
% smell = olfStimStartTrial(trialNum, smell) | |
% This function assumes all information for the current trial are present | |
% in smell and that these values are correct. From here on no more checking | |
% whether numbers make sense or not. Will just result in errors or | |
% incorrect triggering of the vials. | |
% | |
% To do: | |
% -get the actual timing of events from LASOM and write it into the | |
% smell structure. | |
% | |
% lorenzpammer 2011/12 | |
%% Decide whether to output information to the command window for debugging; | |
debug = true; | |
%debug = false; | |
%% Fetch some variables from the gui appdata | |
global olfStimTestMode | |
global olfStimScriptMode | |
if isempty(olfStimScriptMode) | |
~isempty(findobj('Tag', 'olfStim')); % See whether the olfStimGui is present (true) or not (false) | |
end | |
% Extract the gui handle structure from the appdata of the figure: | |
if ~isempty(olfStimScriptMode) | |
h=[]; | |
% In scripting mode, we'll declare olfactometerH a global variable, as | |
% we don't have the gui to add it as appdata. This is bad programming, | |
% try to find a better solution. | |
global olfactometerH | |
else isempty(olfStimScriptMode) | |
h = appdataManager('olfStimGui','get','h'); | |
% Extract the lasom handle from the appdata of the figure: | |
olfactometerH = appdataManager('olfStimGui','get','olfactometerH'); | |
% % Extract the olfStimTestMode variable | |
% olfStimTestMode = appdataManager('olfStimGui','get','olfStimTestMode'); | |
end | |
%% | |
% Check whether olfactometerH has not been released properly. If so, close it. | |
if iscom(olfactometerH) | |
warnStr = sprintf('The connection to the LASOM wasn''t released properly in a previous trial. Closing it now.'); | |
protocolUtilities.logWindow.issueLogMessage(warnStr); | |
release(olfactometerH); | |
end | |
clear olfactometerH; | |
%% Build the osq file for the current trial | |
% buildTrialOsq.m will create an osq file taking into account the | |
% olfactometerInstructions for the current trial. | |
trialOsq = buildTrialOsq(trialNum,smell); | |
% Add the osq file for the current trial into the smell structure: | |
smell.trial(trialNum).trialOsqFile = trialOsq; | |
if debug | |
disp(trialOsq) | |
end | |
%% Connect to LASOM and set it up | |
olfactometerH = olfactometerAccess.connect(debug); | |
% Write the olfactometer activeX handle into the appdata of the figure: | |
% make this conditional to allow SCRIPTING | |
if isempty(olfStimScriptMode) | |
appdataManager('olfStimGui','set',olfactometerH); | |
end | |
%% Update smell: | |
if trialNum == 1 && ~olfStimTestMode | |
% Get the ID from the olfactometer: | |
smell.olfactometerSettings.olfactometerID = olfactometerAccess.getID(debug,olfactometerH); | |
end | |
%% Send osq file of the current trial to the LASOM | |
callingFunctionName = 'olfStimStartTrial.m'; % Define the name of the initalizing function | |
osqPath = which(callingFunctionName); | |
osqPath(length(osqPath)-length(callingFunctionName):length(osqPath))=[]; | |
dd = filesep(); | |
osqPath=[osqPath dd 'olfactometerUtilities' dd 'osq' dd]; | |
clear callingFunctionName | |
pathTrialOsq = [osqPath 'trial.osq']; | |
% Clear old sequences, send new one to olfactometer and compile it. | |
olfactometerAccess.sendSequence(debug,olfactometerH,pathTrialOsq); | |
%% Set MFC flow rates | |
slave = smell.trial(trialNum).slave; | |
smell = calculateMfcFlowRates(trialNum,smell,'error'); | |
percentOfCapacityAir = smell.trial(trialNum).flowRateMfcAir / smell.olfactometerSettings.slave(slave).maxFlowRateMfcAir * 100; | |
percentOfCapacityN = smell.trial(trialNum).flowRateMfcN / smell.olfactometerSettings.slave(slave).maxFlowRateMfcNitrogen * 100; | |
% These commands should be externalized into the olfactometerAccess function. | |
if ~olfStimTestMode | |
olfactometerAccess.setMfcFlowRate(debug, olfactometerH, slave, 1, percentOfCapacityAir); | |
olfactometerAccess.setMfcFlowRate(debug, olfactometerH, slave, 2, percentOfCapacityN); | |
end | |
%% Start sequencer | |
olfactometerAccess.executeSequence(debug,olfactometerH); | |
if olfStimTestMode | |
disp('olfStim is currently in test mode. No interaction with olfactometer.') | |
end | |
% Trigger trial: | |
% Triggering is done from an external device. | |
%% Prepare for timer action | |
% Delete all old timers | |
try | |
stop(timerfindall); | |
end | |
delete(timerfindall); | |
%% Measure MFC flow rate continuously throughout the trial | |
% Starting and stopping the measurement | |
% Define timepoints when Mfc flow rate should be measured. Measure every | |
% x seconds, from the start of the trial (0s) to the end, defined by the end | |
% of the sequencer. | |
% Problem, that measuring takes quite a long time, therefore long | |
% intervals: | |
measurementInterval = 0.5; % measurement interval in seconds | |
slave = smell.trial(trialNum).slave; | |
% Set up the timer, and its callbacks for measuring the mfc flow | |
mfcMeasureTimer = timer('ExecutionMode','fixedRate','Period',measurementInterval,... | |
'StartDelay',0,'TasksToExecute',Inf,... | |
'TimerFcn',@measureMfcFlowRate,'StopFcn',@measureMfcFlowStopped,... | |
'BusyMode','error','ErrorFcn',@measureMfcErrorFcn); | |
% Start the timer, only once the sequencer received the trial start signal. | |
% Check for this with another timer (readLasomStatusTimer - see below) | |
% ticID = tic; | |
% set(mfcMeasureTimer,'UserData',ticID); | |
% start(mfcMeasureTimer); | |
% pause(5); | |
% if isvalid(mfcMeasureTimer) | |
% stop(mfcMeasureTimer) | |
% end | |
% Callback functions of timer: | |
function measureMfcFlowRate(obj,event) | |
% Every 2000 ms, jump into this function measure the mfc flow rates | |
% and write the returned values into the smell structure: | |
measurementNo = get(mfcMeasureTimer,'TasksExecuted'); | |
elapsedTime = toc(get(mfcMeasureTimer,'UserData')); | |
smell.trial(trialNum).lasomEventLog.flowRateMfcAir(1,measurementNo) = ... | |
elapsedTime; | |
smell.trial(trialNum).lasomEventLog.flowRateMfcN(1,measurementNo) = ... | |
elapsedTime; | |
if ~olfStimTestMode % only execute when we aren't in test mode | |
% Get the current MFC flow rate measurement. Will be returned | |
% in percentage of total flow: | |
smell.trial(trialNum).lasomEventLog.flowRateMfcAir(2,measurementNo) = ... | |
olfactometerAccess.getMfcFlowRateMeasure(debug,olfactometerH,slave,1); | |
smell.trial(trialNum).lasomEventLog.flowRateMfcN(2,measurementNo) = ... | |
olfactometerAccess.getMfcFlowRateMeasure(debug,olfactometerH,slave,2); | |
% Calculate flow rates in l/min: | |
mfcAirFlow=(smell.trial(trialNum).lasomEventLog.flowRateMfcAir(2,measurementNo)/100)*smell.olfactometerSettings.slave(slave).maxFlowRateMfcAir; | |
mfcNFlow=(smell.trial(trialNum).lasomEventLog.flowRateMfcN(2,measurementNo)/100)*smell.olfactometerSettings.slave(slave).maxFlowRateMfcNitrogen; | |
% Check whether the measured flow rates deviate by more than 5% | |
% from the target flow rates | |
deviationAirFlow = abs(smell.trial(trialNum).lasomEventLog.flowRateMfcAir(2,measurementNo) - percentOfCapacityAir); | |
if deviationAirFlow > 5 | |
warnStr = sprintf('ATTENTION! Air flow rate deviates by more than 5%% from target flow. Measured air flow: %.3f %%, Target air flow: %.3f %%.\n',... | |
smell.trial(trialNum).lasomEventLog.flowRateMfcAir(2,measurementNo), percentOfCapacityAir); | |
protocolUtilities.logWindow.issueLogMessage(warnStr); | |
end | |
deviationNFlow = abs(smell.trial(trialNum).lasomEventLog.flowRateMfcN(2,measurementNo) - percentOfCapacityN); | |
if deviationNFlow > 5 | |
warnStr = sprintf('ATTENTION! Nitrogen flow rate deviates by more than 5%% from target flow. Measured N flow: %.3f%%, Target N flow: %.3f%%.\n',... | |
smell.trial(trialNum).lasomEventLog.flowRateMfcN(2,measurementNo), percentOfCapacityN); | |
protocolUtilities.logWindow.issueLogMessage(warnStr); | |
end | |
% Print the measured flow rates to the command window: | |
fprintf('Measurement of MFC flow #%d. Air: %.3f l/min, N2: %.3f l/min.\n',... | |
measurementNo,mfcAirFlow, mfcNFlow); | |
end | |
end | |
function measureMfcFlowStopped(varargin) | |
% At the end of the trial, after last measurement of mfc flow, jump | |
% into this function and stop the timer. | |
stop(mfcMeasureTimer); | |
delete(mfcMeasureTimer); | |
if debug | |
disp('Stopped measuring MFC flowrate.'); | |
end | |
end | |
function measureMfcErrorFcn(~,~) | |
warnStr = sprintf('Can''t fulfill MFC measuring requests at the set interval. Giving up.'); | |
protocolUtilities.logWindow.issueLogMessage(warnStr); | |
stop(mfcMeasureTimer) | |
end | |
clear measurementPoints index olfactometerTimes timeOfLastAction measurementInterval | |
%% Read status messages coming from LASOM | |
% Sequencer file (osq) ends with the command 'EmitStatus' this results in | |
% the sequencer queuing a status message to the USB host. Here the function | |
% waits until receiving that message. Then continue. | |
readStatusInterval = 1; % measurement interval in seconds 1000Hz | |
tasksToExecute = 10e7; % this high number is a hack, because if infinite tasks should be executed one cannot hold the function until the timer is done. | |
% Set up the timer, and its callbacks for measuring the mfc flow | |
readLasomStatusTimer = timer('ExecutionMode','fixedRate','Period',readStatusInterval,... | |
'StartDelay',0,'TasksToExecute',tasksToExecute,... | |
'BusyMode','error','ErrorFcn',@readLasomStatusErrorFcn,... | |
'TimerFcn',{@readLasomStatusUntilTrialStart},'StopFcn',{@trialStarted}); | |
start(readLasomStatusTimer) | |
% pause(20); | |
% if isvalid(readLasomStatusTimer) | |
% disp('stopped lasom timer from timeout') | |
% stop(readLasomStatusTimer) | |
% release(olfactometerH) | |
% end | |
% if isvalid(mfcMeasureTimer) | |
% disp('stopped mfc timer from timeout') | |
% stop(mfcMeasureTimer) | |
% release(olfactometerH) | |
% end | |
% | |
wait(readLasomStatusTimer) % keeps function active until timer stops (once sequencer is idle) | |
delete(readLasomStatusTimer) | |
if iscom(olfactometerH) | |
release(olfactometerH) | |
end | |
if ~isempty(timerfindall) | |
delete(timerfindall) | |
end | |
%% Callback functions of timer: | |
function readLasomStatusUntilTrialStart(obj,event) | |
% Every 1000 ms, jump into this function and read the last emitted | |
% status: | |
measurementNo = get(readLasomStatusTimer,'TasksExecuted'); | |
if ~olfStimTestMode % only execute when we aren't in test mode | |
lasomStatus = olfactometerAccess.getUpdate(debug,olfactometerH); | |
startVariableStatus = olfactometerAccess.getStateOfVariable(debug,olfactometerH,1); | |
else | |
% if we're in test mode set the two variables: | |
lasomStatus = 1; | |
startVariableStatus = 1; | |
end | |
if debug | |
fprintf('Checking sequencer status. Sequencer status: %d, Start variable: %d\n',... | |
lasomStatus, startVariableStatus); | |
end | |
% If the variable with index 1 ($Var1) is set to 1, this means | |
% the sequencer has started to execute the trial (eg after | |
% exiting the initial whileloop). | |
if lasomStatus == 1 && ... | |
startVariableStatus == 1; | |
% | |
% if debug | |
% fprintf('Started to execute trial.\n'); | |
% end | |
ticID = tic; | |
set(mfcMeasureTimer,'UserData',ticID); | |
start(mfcMeasureTimer); | |
stop(readLasomStatusTimer) % will execute trialStarted subfunction. | |
msg = sprintf('Started to execute trial #%d.\n',trialNum); | |
buildSmell('updateFields',[],[],trialNum,[],[],'time'); % enter time of actually starting the trial into smell. | |
protocolUtilities.logWindow.issueLogMessage(msg); | |
end | |
if measurementNo >= 2 && (lasomStatus == 205 || startVariableStatus == 205) | |
warning('LASOM throws error 205 at reading status. Stopped reading status & measuring flow. Not purging.') | |
stop(mfcMeasureTimer) | |
% Release the connection to the olfactometer | |
stop(readLasomStatusTimer) | |
% delete(readLasomStatusTimer) | |
release(olfactometerH) | |
end | |
end | |
function trialStarted(obj,event) | |
set(readLasomStatusTimer,'Period',2); % Once the trial started read statuses at a rate of 10 Hz | |
set(readLasomStatusTimer,'TimerFcn',@readLasomStatusAfterTrialStart); | |
set(readLasomStatusTimer,'StopFcn',''); | |
start(readLasomStatusTimer); | |
if debug | |
disp('2nd phase of checking LASOM status initiated.') | |
end | |
end | |
function readLasomStatusAfterTrialStart(obj,event) | |
if ~olfStimTestMode % only execute when we aren't in test mode | |
lasomStatus = olfactometerAccess.getUpdate(debug,olfactometerH); | |
startVariableStatus = olfactometerAccess.getStateOfVariable(debug,olfactometerH,1); | |
else | |
% if we're in test mode set the two variables: | |
lasomStatus = 0; | |
startVariableStatus = 0; | |
end | |
if debug | |
fprintf('2nd phase of checking sequencer status. Sequencer status: %d, Start variable: %d\n',... | |
lasomStatus, startVariableStatus); | |
end | |
if startVariableStatus == 0 %lasomStatus == 0 && ... | |
if lasomStatus ~= 0 | |
disp('Sequencer didn''t terminate. Still quitting trial.') | |
end | |
% At the end of the trial, jump into this function and stop the timer. | |
stop(readLasomStatusTimer) | |
if debug | |
fprintf('Sequencer finished. Stopped the timer readLasomStatus.\n'); | |
end | |
% If purging is used by the user, set mfcs to maximum flow rate | |
% at the end of the trial: | |
settingNames = {smell.trial(trialNum).olfactometerInstructions.name}; | |
index = find(strcmp('purge',settingNames)); | |
if smell.trial(trialNum).olfactometerInstructions(index).used && ~olfStimTestMode | |
olfactometerAccess.setMfcFlowRate(debug,olfactometerH,slave,1,100); | |
olfactometerAccess.setMfcFlowRate(debug,olfactometerH,slave,2,100); | |
fprintf('Purging olfactometer.\n') | |
end | |
% Stop measuring the Mfc flow: | |
stop(mfcMeasureTimer) | |
% To do get events after trial. | |
% test = get(olfactometerH, 'SequencerLabelTimeValue', '@') | |
% Release the connection to the olfactometer | |
if ~olfStimTestMode | |
release(olfactometerH) | |
end | |
fprintf('Executed trial %d successfully.\n',trialNum) | |
end | |
end | |
function readLasomStatusErrorFcn(~,~) | |
% Need to put add an error function for this timer, because the MFC | |
% measuring can take longer than the defined measurement interval, | |
% and then has to be stopped, as it would result overloading the | |
% computer and a lot of unwanted behavior. | |
warnStr = sprintf('Can''t fulfill LASOM reading requests at the set interval. Giving up.'); | |
protocolUtilities.logWindow.issueLogMessage(warnStr); | |
disp(lasterror) | |
stop(readLasomStatusTimer) | |
end | |
end |