Configure a callback in App Designer to be non-interruptable

I'm using USB connected Arduino device and have the following line:
configureCallback(app.PicoCom,"terminator",@app.PicoInput);
The function app.PicoInput does it's job, but I would like it to complete before going back to the main program. If a function has a component that calls it then the function will be the "callback area" of the app and the component has callback execution control. Since this function is called by an interrupt and is set up by startupFcn(app) it doesn't have a component. How can I make it non-interruptable without messing with flags and mutex?

 Accepted Answer

The secrets to making a function uninterruptible is:
  • write the code all on one line. MATLAB checks for interrupts at the beginning of each line of code, so if you write it all on one line then there will be no opportunity to interrupt
  • write the code entirely in terms of built-in functions. You might have prevented interrupts by writing all on one line, but if what you are calling is MATLAB code that was written on multiple lines then MATLAB will be checking for interrupts at the beginning of those lines.
  • do not call pause() or uifigure() or figure() or uiwait() or waitfor() or drawnow()

5 Comments

It's a bit long to put all on one line (even if I delete comments. But it turns out it doesn't take long so I guess that's not the problem.
(Go back to lag question 2178493-random-lags-while-running-app )
function PicoInput(app,src,~)
% check if there is more than 1 line. For some reason I don't get another callback!!!
while (app.PicoCom.NumBytesAvailable>0)
raw = readline(src);
if size(char(raw),2) == 0
return; % This should never happen, but it does!
end
ch = char(raw); % apparently a read line is a string, make it chars
if (ch(1:1)=='#') % A debug line from Pico,
AddDebugText(app,raw); % if DEBUG is on the text will display
% V85 special cases, H ws there, adding V for Odor Test light off
if ch(2:2)=='V' % Valve test finished
if app.OdorTestButton.Value
app.OdorTestButton.Value = 0; % Turn off
OdorTestButtonValueChanged(app);
end
end
if ch(2:2)=='H' % #Help! ..Pico not connected correctly
AddDebugText(app,"Restarting Pico");
try
write(app.PicoCom,"x2",'char'); % try rebooting too
catch
InitPicoPort(app);
end
end
return;
else % Important data to be saved?
% char2num is easy just num = char('x'); but other direction....
app.PicoType = double(ch(1:1)); % first char always "type" an ascii char
app.PicoType = uint8(app.PicoType); % Convert to uint8
app.PicoData = str2double(ch(2:end)); % numeric data starts at second char
app.PicoData = uint32(app.PicoData); % save as integer
end
if app.PicoData == 0 % Should never happen but if it does, discard
return;
end
% Deal with the returned results:
if (app.status == 2) || (app.status == 3) % Running (finishing) a trial?
% V27 SAVE THIS IN THE IN BUFFER during trial and V28 for "stopping too
% zzz ToDo probably don't need my own input buffer, let USB driver handle it???
% V2.9 add buffer overrun check (Might only be during debug??)
if (app.InPtr == app.OutPtr) && ~app.BFEmpty
Message = sprintf("Buffer overrun %c", app.PicoType);
wt = uiconfirm(app.MouseOdor,Message,"Pico Buffer", ...
Options="Uh-Oh",Icon = "error"); %#ok
% V84 clear it out
app.InitInBuffer; % Clear/init input buffer
% previously app.BFEmpty = true; % Call it empty but leave data for debug
else
app.InBuffer(app.InPtr,1) = app.PicoType;
app.InBuffer(app.InPtr,2) = app.PicoData;
if app.InPtr<size(app.InBuffer,1)
app.InPtr = app.InPtr + 1;
else
app.InPtr = 1;
end
app.BFEmpty = false; % Data just added
end
else
% Not in a trial but save licks (training), and m'scope sync (always)
DoLicksNoTrial(app,app.PicoType,app.PicoData)
end
end % end-while
end % PicoInput[];
if (app.status == 2) || (app.status == 3) % Running (finishing) a trial?
It is not obvious that app.status is defined at that point.
app.InBuffer(app.InPtr,1) = app.PicoType;
app.InBuffer(app.InPtr,2) = app.PicoData;
It is not obvious that app.InBuffer has been defined at that point.
Those are two different data types. If app.InBuffer has not been defined before this, then app.InBuffer will be initialized to the first type assigned to it, which would be uint8. You would need to initialize to uint32 to fit app.PicoData
if ch(2:2)=='H' % #Help! ..Pico not connected correctly
It bugs me that that is not an "elseif" ;-)
app.status is initialized during startup and well managed.
Data typing is handled in the code, structures are initialized as needed.
e.g.
function InitInBuffer(app)
% Clean out InBuffer reset pointers
app.InBuffer = zeros(40, 2); % Circular Array init
app.InPtr = 1; % Where to read
app.OutPtr = 1; % Where Pico Data goes
app.BFEmpty = true; % No data yet
end
The circular buffer is handled correctly.I use it to get data out of the Windows USB buffer where I can deal with in in my own time. Type isn't changed to a char until it's read from the buffer.
Typ = char(app.InBuffer(app.OutPtr,1));
if ~isletter(Typ) % manage possible error (it never happens)
And BTW the PicoInput code is about 80 lines so not going to fit on one line.
Hasn't been a problem any more with ML2025
function InitInBuffer(app)
% Clean out InBuffer reset pointers
app.InBuffer = zeros(40, 2); % Circular Array init
You are not returning app from the function, and app is not a global variable or a shared variable. All changes to app will be lost when the funtion returns.

Sign in to comment.

More Answers (0)

Categories

Products

Release

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!