MATLAB: exiting infinite loop without using global variable in GUI - matlab

Background: I have several portion in an GUI to handle different tasks. In 1 portion (portion1) I have text input and send button. So once I will click send it would send one data to my serial port. Another portion (portion2) would receive signal from serial port which have been received from other devices. Both the portions are using two buttons; one to start the work of that particular portion and one to stop the work. I have used global variables and while loop (with boolean) to exit the infinite loop, as I need to send the data or receive data continuously.
My question: Problem is when I am using global variables and the above mentioned way of using infinite loop, if I click portion1, portion1 will start iterate. Now if I click portion2 then portion1 will be stopped. But I need to use them both at the same time and both of them will continuously send and receive data until I click other button (s) to exit the infinite loop.
My sample code for clarification:
function send_Callback(hObject, eventdata, handles)
global firstFlag;
firstFlag = true;
while firstFlag
%Required codes
end
function haltSend_Callback(hObject, eventdata, handles)
global firstFlag;
firstFlag = false;
function receive_Callback(hObject, eventdata, handles)
global secondFlag;
secondFlag = true;
while true
%Required codes
end
function stopReceive_Callback(hObject, eventdata, handles)
global secondFlag;
secondFlag=false;
I have tried to find a solution referring to internet, but most of the solutions are using global variable. It would be better if I could work without global variables. But even if my requirements are fulfilled (as per my question) it would work.

Global or not is not the issue here.
Callbacks in Matlab all run on the same thread.
So when callback1 is running and you trigger callback2, callback2 will interrupt callback1.
callback1 will then only proceed once callback2 is finished.
You can only slightly modify this procedure using the BusyAction property:
http://www.mathworks.de/de/help/matlab/ref/uicontrol_props.html#bqxoija
But this won't help in your case.
In a "proper" programming language, you'd have a sending and a receiving thread running in parallel. You can't do this matlab however - unless you're e.g. willing to write java-code.
If you want to stick with matlab, the closest to thread would be timers.
These would replace your while loops.
E.g. as in the following minimalistic example:
function cbtest()
try close('cbtest');end
f = figure('name', 'cbtest');
% create the timers:
period = 0.2; % period in seconds, in which the timer shall execute
sendTimer = timer('TimerFcn', #sendFcn, 'ExecutionMode', 'fixedDelay', 'Period', period, 'TasksToExecute', Inf);
recvTimer = timer('TimerFcn', #recvFcn, 'ExecutionMode', 'fixedDelay', 'Period', period, 'TasksToExecute', Inf);
uicontrol(f, 'position', [10 10 100 25], 'Callback', #(a,b) start(sendTimer), 'string', 'start1');
uicontrol(f, 'position', [120 10 100 25], 'Callback', #(a,b) stop(sendTimer), 'string', 'stop1');
uicontrol(f, 'position', [10 50 100 25], 'Callback', #(a,b) start(recvTimer), 'string', 'start2');
uicontrol(f, 'position', [120 50 100 25], 'Callback', #(a,b) stop(recvTimer), 'string', 'stop2');
end
function sendFcn(hTimer, timerEvt)
% your send-loop-code
disp('sending');
end
function recvFcn(hTimer, timerEvt)
% your receive-loop-code
disp('receiving');
end
sendFcn and recvFcn here then should contain the code you have within your according while loops.
You can of course lower the period to your needs, I chose the above for testing purposes.

Your problem is that you're executing the loop inside the Callbacks. So when the second button is clicked, the second callback will start and loop infinitely, until it is ended. The first loop will wait for the second Callback to terminate until it can resume. What you need is a main program where you execute your loop. Nesting the Callbacks will make sure they can access and change the local variables without making them global. If you're fine with building a GUI programmatically, try this:
function main()
sendFlag = false;
receiveFlag = false;
while true
if sendFlag
% Your Sending code
end
if receiveFlag
% Your Receiving code
end
end
function send_Callback(~,~,~)
sendFlag = true;
end
% other Callbacks
end
Then in the Callbacks for your Buttons (you could use Toggle Buttons by the way), you simply set the sendFlag and receiveFlag, respectively.
Using GUIDE, you want to use toggle buttons.
I don't exactly know how GUIDE handles the OpeningFcn, so you should probably put a "Start" button into your GUI which basically executes the above program with a few changes:
function startbutton_Callback(hObject,~,handles)
while true
handles = guidata(hObject); % Updates handles structure
sendFlag = get(handles.sendtoggle, 'Value');
if sendFlag
% Your Sending code
end
receiveFlag = get(handles.receivetoggle, 'Value');
if receiveFlag
% Your Receiving code
end
end
Also, create send and receive toggle buttons and set their 'Min' to 0 and 'Max' to 1. This will make them switch their 'Value' property (which you read in the above loop) between 0 and 1 when you click them. In the Callback, you can change what they display:
function send_Callback(hObject,~,handles)
on = get(hObject,'Value');
if on
set(hObject, 'String', 'Stop sending');
else
set(hObject, 'String', 'Start sending');
end
guidata(hObject,handles); % Update GUI data
Now your main function, which starts when you click the start button, runs the loop and just checks the toggle buttons' states to determine whether to send and receive.

Related

How to make a countdown timer in MATLAB GUIDE?

I'm trying to make a timer that counts down from 20 to 0 (seconds) in GUIDE. In the meantime the user will perform a simple action (clicking a radio button in a group button) and at the end of that 20 seconds a message will appear (depending on which button the user clicked).
I looked around but it seems that there isn't a timer object for GUIDE (why don't they make one since it's so useful??). However I tried to make one and below there's the result, it doesn't work.
I initialised setappdata in MyGUI_OpeningFcn:
% Initialize setappdata
timeout = 20;
setappdata(handles.figure1,'timeout', timeout);
Next_calculation is radio button and timerBox is a static text.
function Next_calculation_Callback(hObject, eventdata, handles)
[..]
timeout = getappdata(handles.figure1,'timeout');
t = timer('Period', 1.0,... % 1 second
'StartFcn', set(handles.timerBox,'String',num2str(timeout)), ...
'ExecutionMode', 'fixedRate', ... % Starts immediately after the timer callback function is added to the MATLAB execution queue
'TasksToExecute', timeout, ... % Indicates the number of times the timer object is to execute the TimerFcn callback
'TimerFcn', #my_timer ... % callback to function
);
start(t)
Once the timer begins, it calls TimerFcn that calls my_timer. I should pass a handle to my_timer, but I don't know exactly how.
function my_timer(hObject, eventdata)
% I think I'm supposed to pass (hObject, eventdata) to my_timer
% handles should be getting the current figure from hObject
handles = guidata( ancestor(hObject, 'figure1') );
timeout = getappdata(handles.figure1,'timeout');
t_left = timeout - 1.0;
% show the updated time
set(handles.timerBox,'String',num2str(t_left));
% update 'timeout'
setappdata(handles.figure1,'timeout',t_left)
You need to use a custom anonymous function for the TimerFcn to pass the necessary data to your timer callback
set(t, 'TimerFcn', #(s,e)my_timer(hObject, handles))
You can then define your my_timer callback as
function my_timer(hObject, handles)
% Do stuff with handles
end

Real-time update of values inside a call_back function[the values are from external function(of another .m file)]

I have an external function say "external_func" (seperate .m file)
Inside this function a while loop is called, and this while loop update a variabl named "update_prog"
Now I will pass this value into the GUIDE using
assignin('base', 'update_prog', update_prog); % passing to workspace
I am making this
"update_prog" as global variable and calling it into GUIDE .m file
function pb1_Callback(hObject, eventdata, handles)
global update_prog
% hObject handle to pb1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% else
% set(handles.pb1,'enable','on');
% end
% update_prog first value prints, but it wont updates as the loop in external_func goes on.
drawnow;
set(handles.slider1,'Value',update_prog)
external_func;
so here in the GUIDE .m file I can get the value
"update_prog" but it wont keep up with the while loop. I used "drawnow" but its of no use.
How can I refine this value "update_prog" as the while loop in the "external_func" goes through multiple iterations. [Note: The updated values are there in the callback function of GUIDE, but unless there is a callback the callback function wont update the "update_prog"], so how can I acheive this real-time update inside a call_back function.
[Note: passing the variables through function input is not possible here in my case, so I am looking for alternatives]
Edit1: please consider this link, which has an exampleWhich may clarify you what I am trying to acheive
What I am doing here is
Passing the variable(which is being updated in the while loop of the externel function) into GUI.
I will use this variable to show the progress on the progress bar(Slider).
What is the problem?
1. The variable inside the GUI callback(Consdier I will press a push button and then it will call the function with while loop) will put the updated values into the set(handles.slider,'Value',variable)
By doing this I cant move the slider.
Why?
Callback updates the variable only when I press the push button, next all the updates to the variable will not be updated, so progress bar/slider wont move.
I wouldn't recommend to pass your variable in 3 steps with an intermediate workspace (external->base workspace->GUI). I would rather recommend to pass your variable directly (external->GUI).
Each Matlab figure offers a space to store variables (Application Data) of any type. I would suggest reading the article Share Data Among Callbacks and read the documentation for the 3 functions:
guidata
setappdata
getappdata
This way will offer you much more control over the scope of your variables and you won't need any global declaration.
Below is an example of a simple gui. The gui declare the variable in it's user space (with setappdata), then uses a timer to periodically read this variable (with getappdata).
The external function do whatever you want it to do (just a random number in the example), then to update the variable you use the same setappdata. The only thing you need for that is the handle of the main GUI figure, so in the example I give it as input of the external function.
The GUI also has two buttons to start and stop the update.
The code for the main example GUI 'theGui.m' is :
function h = theGui
%// basic GUI with 2 buttons and 1 slider
h.fig = figure('Position',[433 434 500 100],'Menubar','none','CloseRequestFcn',#my_closefcn) ;
h.sld = uicontrol('Style','Slider','Position',[20 20 460 20]) ;
h.btnStart = uicontrol('Style','pushbutton','String','Start updating','Callback',#btnStart_callback,'Position',[20 50 200 30]);
h.btnStop = uicontrol('Style','pushbutton','String','Stop updating','Callback',#btnStop_callback,'Position',[280 50 200 30],'Max',1,'Min',0);
%// Define the timer
h.t = timer ;
h.t.Period = 0.1 ; %// 0.1s refresh interval
h.t.TimerFcn = {#timer_callback,h.fig} ;
h.t.ExecutionMode = 'fixedSpacing' ;
%// initialise the variable to update in the GUI appdata
update_prog = 0 ;
setappdata( h.fig , 'update_prog' , update_prog ) ;
%// save handles
guidata( h.fig , h );
function btnStart_callback(hobj,~)
h = guidata( hobj ) ; %// retrieve handles
if strcmp('off',h.t.Running) %// Start timer (only if not already running)
start(h.t)
end
function btnStop_callback(hobj,~)
h = guidata( hobj ) ; %// retrieve handles
stop(h.t) %// Stop timer
function timer_callback(~,~,hfig)
update_prog = getappdata( hfig , 'update_prog' ) ; %// retrieve the 'update_prog' variable value
h = guidata( hfig ) ; %// retrieve handles
set(h.sld , 'Value' , update_prog) ; %// update the slider object with the retrieved value
function my_closefcn(hobj,~)
%// this function is only to clean up when the GUI will be closed.
%// It is recommended to delete the timer manually
h = guidata( hobj ) ; %// retrieve handles
stop(h.t) %// Stop timer (in case it is still running)
delete(h.t) ; %// delete the timer
delete(h.fig) ; %// destroy the figure
And the code for external_func.m
function external_func( guiMainFigureHandle )
%// This function will only generate random numbers and push them into the
%// variable 'update_prog' contained in the GUI appdata.
%// This is why this function NEEDS the handle of the gui to be able to
%// access the Application Data space of the gui.
for k = 1:100
randomValue = rand(1) ; %// generate a random value
hfig = ancestor( guiMainFigureHandle , 'figure' ) ; %// make sure the handle provided is the top level figure
setappdata( hfig , 'update_prog' , randomValue) ; %// update the variable value
pause(0.1) ;
end
Edit:
I place this in edit instead of changing the code above because I don't recommend messing with the root object if you don't need to. But in your case it can be a way round your problem.
If your external function doesn't have access to the GUI, it can always update a part of memory which is available for all the programs running in a given Matlab session, namely the root object. The handle for it is reserved and is the same for any program: 0 (although since v2014b there is another way to invoke it : groot, it is still always the same handle for all Matlab).
So in the example above, in theGui.m, use instead:
setappdata( 0 , 'update_prog' , update_prog ) ;
in the main routine, then in the subfunction function timer_callback(~,~,hfig), use:
update_prog = getappdata( 0 , 'update_prog' ) ; %// retrieve the 'update_prog' variable
And your function external_func() doesn't need any extra argument, the update only needs one line:
setappdata( 0 , 'update_prog' , update_prog) ; %// update the variable value
I "suspect" that your update_prog variable in the base workspace is not a global (you must define it to be global in every workspace that you want to use it).
Since your using globals (there are many better ways to do this - but thats not your question) - why don't you simply define the update_prog variable to be global in your external_func function (replace the assign call).
edit put a drawnow in your external_func function. That way when you click on the button it will update.
edit 3
I think I know what you want to do, try this example and see if it does what you want - updated to show how you find the slider object in your code and update inside your loop:
function mygui
% create a figure
f = figure;
% create a uicontrol slider - note that I give it a tag.
uicontrol ( 'style', 'slider', 'Position', [0 200 200 40], 'tag', 'MYSLIDER', 'backgroundcolor', 'white', 'parent', f );
% create a push button which we can press to update
uicontrol ( 'string', 'Press 2 start', 'callback', #(a,b)myLoop(), 'Position', [0 0 200 50] )
end
% This replicates your "external_func" function.
function myLoop()
% since you cant pass in any var -> you need to find the slider object
% you can do this by using findobj and search for the tag of the item
uic = findobj ( 0, 'tag', 'MYSLIDER' );
% find the figure handle (only needed for this demo)
f = ancestor ( uic, 'figure' );
% initialise the value which will be used to update the slider
count = 0;
% create your loop
while ishandle(f)
% incrememt the count variable -> this will end up on the slider value
count = count + 1e-5;
% reset count if > 1 -> so the slider cant go out of range.
if count >= 1
count = 0;
end
set ( uic, 'Value', count );
% initiate a drawnow -> this allows matlab to process GUI events
drawnow();
end
end
The downside of this is you insert a drawnow in your loop -> which could slow it down somewhat.
If this doesn't fix your problem you need to explain better what you want to do... (in my view)

Is this a race condition in matlab?

The title says it all. I was wondering if the following code is prone to a race condition.
classdef Foo < handle
properties
value = true
end
methods
function toggle(o, ~, ~)
o.value = ~o.value;
end
end
end
function main
foo = Foo;
uicontrol('style', 'pushbutton', 'callback',#foo.toggle);
drawnow
%// Endless loop which gets broken up by a button press
while foo.value
pause(1)
end
%// What happens if I press the button twice, really fast? There
%// is no external function called between here and the previous
%// while loop.
if foo.value
error('Race')
else
fprintf('\nWe made it\n')
end
Am I save from the race condition since everything happens in the event dispatch thread? Is the same still true if I play with Interruptible and BusyAction property of the button? I found the matlab help quite confusing.
In case it matters I'm using R2012a.

Matlab GUI: Reading from Serial port and showing in different listboxes at the same time

I am working with serial port and multiple list boxes to read data in serial port. The listboxes are used to read specific data (suppose the data is coming from 3 different sources, so I have 3 listboxes).
Now the problem:
I want to read all the data separately and continuously. I mean, when I am clicking one listbox (e.g. listbox#2) after reading listbox#1's data, the listbox#1 automatically stops, so again I need to click listbox#1 to read the data for listbox#1. But I want to get the data continuously in all the listboxes without clicking (clicking for first time to initializing) every time. How can I achieve this? I have tried other ways but not working.
Additional comment: It worked as per the below comments.
Sample code [Edited and OpeningFcn has been added]:
function main_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
handles.timer = timer(...
'ExecutionMode', 'fixedRate', ... % Run timer repeatedly
'Period', 1, ... % Initial period is 1 sec.
'TimerFcn', {#listbox1_Callback, handles});
guidata(hObject, handles);
function listbox1_Callback(hObject, eventdata, handles)
%serConn is the connection to COM port
out = fscanf(handles.serConn);
string = 'degrees1';
t=1;
while(t < 15)
if strncmp(out,string,8)
rxtext = out(14:15);
currList = get(handles.listbox, 'String');
set(handles.listbox,'String',...
[currList ; [temp]]);
end
pause(5);
t = t+1;
end

How to create a GUI inside a function in MATLAB?

Is it possible to write a GUI from inside a function?
The problem is that the callback of all GUI-functions are evaluated in the global workspace. But functions have their own workspace and can not access variables in the global workspace. Is it possible to make the GUI-functions use the workspace of the function? For example:
function myvar = myfunc()
myvar = true;
h_fig = figure;
% create a useless button
uicontrol( h_fig, 'style', 'pushbutton', ...
'string', 'clickme', ...
'callback', 'myvar = false' );
% wait for the button to be pressed
while myvar
pause( 0.2 );
end
close( h_fig );
disp( 'this will never be displayed' );
end
This event-loop will run indefinitely, since the callback will not modify myvar in the function. Instead it will create a new myvar in the global workspace.
There are a number of ways to build a GUI, such as using the App Designer, GUIDE, or creating it programmatically (I'll illustrate this option below). It's also important to be aware of the different ways to define callback functions for your GUI components and the options available for sharing data between components.
The approach I'm partial to is using nested functions as callbacks. Here's a simple GUI as an example:
function make_useless_button()
% Initialize variables and graphics:
iCounter = 0;
hFigure = figure;
hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ...
'String', 'Blah', 'Callback', #increment);
% Nested callback function:
function increment(~, ~)
iCounter = iCounter+1;
disp(iCounter);
end
end
When you run this code, the counter displayed should increment by one every time you press the button, because the nested function increment has access to the workspace of make_useless_button and thus can modify iCounter. Note that the button callback is set to a function handle to increment, and that this function must accept two arguments by default: a graphics handle for the UI component that triggered the callback, and a structure of associated event data. We ignore them with the ~ in this case since we aren't using them.
Extending the above approach to your particular problem, you could add your loop and change the callback so it sets your flag variable to false:
function make_stop_button()
% Initialize variables and graphics:
keepLooping = true;
hFigure = figure;
hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ...
'String', 'Stop', 'Callback', #stop_fcn);
% Keep looping until the button is pressed:
while keepLooping,
drawnow;
end
% Delete the figure:
delete(hFigure);
% Nested callback function:
function stop_fcn(~, ~)
keepLooping = false;
end
end
The drawnow is needed here to give the button callback a chance to interrupt the program flow within the loop and modify the value of keepLooping.
You can declare a variable global in your function and global in the GUI code, certainly if the callback is in a separate function rather than inline. I've done this in a little skeleton GUI I use to make quick menu system.
In your code above you may be able to add the global keyword to your initial declaration and also to your inline callback i.e. 'global myvar = false'
I found a solution to the problem. The callback-function has to modify the handle-structure of the GUI. This structure can be accessed both from within the callback and from the function without introducing new variables to the global workspace:
function myfunc()
h_fig = figure;
% add continue_loop to the GUI-handles structure
fig_handles = guihandles( h_fig );
fig_handles.continue_loop = true;
guidata( h_fig, fig_handles );
% create a useless button
uicontrol( h_fig, 'style', 'pushbutton', ...
'string', 'clickme', ...
'callback', #gui_callback );
% wait for the button to be pressed
while fig_handles.continue_loop
fig_handles = guidata( h_fig ); % update handles
pause( 0.2 );
end
close( h_fig );
disp( 'callback ran successfully' );
end
% The arguments are the Matlab-defaults for GUI-callbacks.
function gui_callback( hObject, eventdata, handles )
% modify and save handles-Structure
handles.continue_loop = false;
guidata( hObject, handles );
end
note that since the while-loop will only update fig_handles when it is run, you will always have at least 0.2 seconds delay until the loop catches the modification of fig_handles.continue_loop