1

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.

Bee
  • 175
  • 1
  • 10

2 Answers2

2

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.

sebastian
  • 9,526
  • 26
  • 54
  • Thank you for your answer, which I believe is the perfect solution when being used individually. But I am afraid, as being a noob in Matlab/programming, how to use it while I am already working with a standard GUI (Guide) where the two portions (Send and Receive) are separate. Do you have any suggestion on using them in standard GUIDE generated GUI? – Bee Jan 16 '14 at 07:18
  • @Bee: See my answer below, the second part is a way to implement it using GUIDE. It retains your approach of using an infinite loop, includes a Start button to get it running and relies on toggle buttons to activate and deactivate the sending and receiving. If there's anything there you need clarification on, just add a comment and I'll do my best to clarify ;) – scenia Jan 29 '14 at 14:18
1

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.

scenia
  • 1,609
  • 14
  • 33
  • Ok, I just changed my mind. Using hidden elements is stupid. Toggle Buttons are the way to go. I'll edit the above answer and give you a Toggle button version, just give me a few moments. – scenia Jan 14 '14 at 12:01
  • You could also try running the loop in the OpeningFcn already, but it might not work. Another way to automatically start it would be to start a timer in the OpeningFcn and execute the loop in the timer's 'StartFcn' (use 'StartDelay' and otherwise default settings). – scenia Jan 29 '14 at 14:22