I would be very grateful for help, advice or suggestion. I have an application to control geodetic instrument using synchoronous interface. However some commands are asynchronous by its nature, e.g. GetReflectors. After this command is triggered I receive as many server answers as is the number of available reflectors. So I have registered an COM event and associate handler function. So far so good. I can display the data coming but I do not know how to pass some variable to the main function. I tried to save variable as .mat file or in .txt file and read it. Actually it works in Matlab but it does not works in compiled .exe aplication (Error firing event). Even disp command does not work in compiled aplication (display nothing). So the main question is: how to pass variables from handler to main function. Is there a way? Global variables? Thank you Filip
Edit: I am adding an code to demostrate the problem... I need to save Reflector Name and Reflector ID so as the user can choose one (because there are multiple events coming with different Reflectors).
function pushbutton_GetReflectors_Callback(hObject, eventdata, handles)
ltsync = actxserver ('LTControl.LTCommandSync2'); %Act as server: LTConnect2
ltsync.events() %List of all COM events
ltsync.registerevent({'ReflectorsData' 'ReflectorsHandler'}) %Register event
ltsync.GetReflectors() %Ask instrument for reflectors
pause(3) %Time to receive answers
end
function ReflectorsHandler(varargin) %Handler of the event ReflectorsData
%var1,var2,reflectorID,reflectorName,var5,surfaceOffset,reflectorsTotal,var8,var9
disp('Reflector Data:');
disp(varargin{3}) %Reflector ID
disp(varargin{4}) %Reflector name
end
I believe you can solve this problem by passing a function handle to registerevent instead of just the string function name, and creating a class to allow you to pass the data back. First, the class:
classdef ReflectorsResponse < handle
properties (SetAccess = private)
reflectors
responseComplete = false;
reflectorsTotal = NaN;
end
methods
function respond(obj, varargin)
% Create a struct for each reflector (or you could define
% another class, but let's keep it simple for the time being)
newRefl = struct();
newRefl.ID = varargin{3};
newRefl.name = varargin{4};
newRefl.surfaceOffset = varargin{6};
% ... store other properties in struct
% Store this reflector
obj.reflectors = [obj.reflectors; newRefl];
% Store total reflector count and check for completion
if isnan(obj.reflectorsTotal)
obj.reflectorsTotal = varargin{7};
end
if length(obj.reflectors) == obj.reflectorsTotal
obj.responseComplete = true;
end
end
end
end
You can then use this by making the respond method your handler:
function pushbutton_GetReflectors_Callback(hObject, eventdata, handles)
% Create the response object and associated handler function handle
response = ReflectorsResponse();
handlerFun = #(varargin)response.respond(varargin{:});
ltsync = actxserver ('LTControl.LTCommandSync2'); %Act as server: LTConnect2
ltsync.events() %List of all COM events
ltsync.registerevent({'ReflectorsData' handlerFun}) %Register event
ltsync.GetReflectors() %Ask instrument for reflectors
% Wait for request to complete
while ~response.responseComplete
pause(0.1);
drawnow update;
% NOTE: Should add a timeout to this loop
end
% Do stuff with response.reflectors
end
This will wait until there has been a response for each of the reflectors, the number of which is determined from the first response. Note that you should add a timeout to the while loop, otherwise you risk waiting infinitely.
If there are lots of these asynchronous requests that you have to handle, I would suggest encapsulating the entire request/response sequence (including the creation of the ActiveX server, setup of the event handler, and waiting for the response(s)) in a generalised base class, and deriving specific subclasses for each different request.
Related
I'm creating a MATLAB GUI using the app designer (very similar to, but better than, GUIDE) which I want to use to monitor the data output of my simulink model in real time.
In other words, I have a simulink model and a GUI, both running in the same MATLAB instance and I want to send packets over UDP from the simulink model and use that data in my GUI to update plots. However, I don't know how to read the data from the UDP packet without blocking.
Is there a way to bind a handler when a packet is received so that I can execute a function to update plots/fields?
Of course, beside BytesAvailableFcn matlab has the datagramreceivedfcn to call your custom function on new dagatrams, which is nonblocking while fread/fscanf are blocking (temporarily). Regarding callbacks in matlab read events and cbs
Compilable standalone could look like:
%% standalone main
%{
see docs/*
%}
function exitcode = main(port, remotePort)
% sanitize input
if(~exist('port','var') || ~exist('remotePort','var'))
disp(['args: port remotePort']);
exit(1);
end
if ischar(port)
port=str2num(port);
end
if ischar(remotePort)
remotePort=str2num(remotePort);
end
% create udp object
u = udp('127.0.0.1',remotePort, 'LocalPort', port);
% connect the UDP object to the host
fopen(u);
exitcode = 0;
% since we poll, suppress warning
warning('off','instrument:fscanf:unsuccessfulRead');
warning VERBOSE
% specify callback on datagram
while true
msgEnc= fscanf(u);
% timed out without datagram
if isempty(msgEnc)
continue
end
% do sth with msgEnc (which is a readable string)
fprintf(u, 'heard sth'); %answer
end
end
If you would like to use simulink block use udpreceive
which has a non-blokcking capability
A First In First Out (FIFO) buffer receives the data. At every time
step, the Data port outputs the requested values from the buffer. In a
nonblocking mode, the Status port indicates if the block has received
new data.
It's my first post here, so hello everyone!
My question is about MATLAB GUI interface. In my code, there is a function callback from a pushbutton and I would like to disable every push/slide-able element in my GUI during processing this callback. Unfortunatelly, when I set 'enable' property of these elements to 'off' at the beginning of a callback and then I set it back to 'on' at the end, property doesn't change.
I think I know why it happens. Probably because if callback changes anything, it happens just after the function is finished and every change inside it does not affect any element outside of the function until the processing is done. That's why I don't see all these elements disabled - because at the end of the function I set everything 'on' and that's the only thing which takes place at all.
Regarding to this - is there any option I can change 'enable' property DURING executing a function? Code is shown below:
function [] = mListLaunchButton_call(varargin)
// Some global declarations
global a phi launchBlanker
global servoNumber servoZeroPosition servoDegreePerDegree servoDirection
// Assigning a class
Manual = varargin{3};
// Enabling "Stop" button and disabling everything else
set(Manual.listStopButton,'enable','on');
set(Manual.listSaveButton,'enable','off');
set(Manual.listDeleteButton,'enable','off');
set(Manual.listClearButton,'enable','off');
set(Manual.listLaunchButton,'enable','off');
set(Manual.closeButton,'enable','off');
for i = 1 : 5
set(Manual.sliderDOF(i),'enable','off');
end
%%%%%%%%%%%%%%%%%%%% HERE FUNCTION DOES SOME STUFF %%%%%%%%%%%%%%%%
// Disabling "Stop" button and enabling eveything else
set(Manual.listStopButton,'enable','off');
set(Manual.listSaveButton,'enable','on');
set(Manual.listDeleteButton,'enable','on');
set(Manual.listClearButton,'enable','on');
set(Manual.listLaunchButton,'enable','on');
set(Manual.closeButton,'enable','on');
for i = 1 : 5
set(Manual.sliderDOF(i),'enable','on');
end
Try using the drawnow command after your initial enabling/disabling of GUI controls and before the line:
%%%%%%%%%%%%%%%%%%%% HERE FUNCTION DOES SOME STUFF %%%%%%%%%%%%%%%%
This should cause MATLAB to flush the queued GUI events and update your screen before moving onto the meat of the function.
I would like to be able to terminate my current running scripts( functions ) by calling a command in the code. Return would only terminate the current function not entire script. Therefore return is not the one.
What I am looking for is a command which does exactly what CTRL + C do.
I have already seen this: how to stop execution and noticed that no one has yet provided a proper answer for this question in there either.
ultimately I want to terminate the entire running scripts upon closing a figure:
hFig = figure('CloseRequestFcn',{#closeHandler});
.
.
.
function closeHandler (src,evnt)
CTRL+C <--- I am looking for such a command
end
PS. function error() will not work either: Try this:
function terminateInCode()
hFig = figure('CloseRequestFcn',{#closeHandler});
while(1)
plot(10*rand,10*rand,'+');
pause(0.1);
end;
function closeHandler (src,evnt)
delete(hFig);
error('program terminated!');
end
end
Here is a sample function with example based on yuk's answer. Components include:
Insure the command window has focus to receive the CTRL+C
Use a timer to release CTRL+C after the break has occurred
Use a Java robot to press CTRL+C
Sample function is below:
function terminateExecution
%terminateExecution Emulates CTRL-C
% terminateExecution Stops operation of a program by emulating a
% CTRL-C press by the user.
%
% Running this function
%
%Example:
%for ix = 1:100
% disp(ix)
% if ix>20
% terminateExecution;
% end
%end
%1) request focus be transferred to the command window
% (H/T http://undocumentedmatlab.com/blog/changing-matlab-command-window-colors/)
cmdWindow = com.mathworks.mde.cmdwin.CmdWin.getInstance();
cmdWindow.grabFocus();
%2) Wait for focus transfer to complete (up to 2 seconds)
focustransferTimer = tic;
while ~cmdWindow.isFocusOwner
pause(0.1); %Pause some small interval
if (toc(focustransferTimer) > 2)
error('Error transferring focus for CTRL+C press.')
end
end
%3) Use Java robot to execute a CTRL+C in the (now focused) command window.
%3.1) Setup a timer to relase CTRL + C in 1 second
% Try to reuse an existing timer if possible (this would be a holdover
% from a previous execution)
t_all = timerfindall;
releaseTimer = [];
ix_timer = 1;
while isempty(releaseTimer) && (ix_timer<= length(t_all))
if isequal(t_all(ix_timer).TimerFcn, #releaseCtrl_C)
releaseTimer = t_all(ix_timer);
end
ix_timer = ix_timer+1;
end
if isempty(releaseTimer)
releaseTimer = timer;
releaseTimer.TimerFcn = #releaseCtrl_C;
end
releaseTimer.StartDelay = 1;
start(releaseTimer);
%3.2) Press press CTRL+C
pressCtrl_C
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function pressCtrl_C
import java.awt.Robot;
import java.awt.event.*;
SimKey=Robot;
SimKey.keyPress(KeyEvent.VK_CONTROL);
SimKey.keyPress(KeyEvent.VK_C);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function releaseCtrl_C(ignore1, ignore2)
import java.awt.Robot;
import java.awt.event.*;
SimKey=Robot;
SimKey.keyRelease(KeyEvent.VK_CONTROL);
SimKey.keyRelease(KeyEvent.VK_C);
Not sure it will work, just an idea. How about to emulate keyboard key press from MATLAB?
You can try either java.awd.Robot:
import java.awt.Robot;
import java.awt.event.*;
SimKey=Robot;
SimKey.keyPress(KeyEvent.VK_CONTROL);
SimKey.keyPress(KeyEvent.VK_C);
or WScript.Shell and SendKeys.
Unfortunately, it seems it cannot be done:
Mathworks
There is no way to programmatically issue a Ctrl+C in MATLAB besides using the keyboard's Ctrl+C combination.
As an alternative, you can use the ERROR command to force an error that will exit the code. For example:
error('Program terminated for a specific reason')
Here's an alternative that uses undocumented Matlab calls to place the key event directly into the command window. The method to do so is protected; this uses reflection to unprotect it.
Unlike #yuk and #Persuit's answers, this does not seem to have issues with the control key sticking. Additionally, it will always post directly to the command window without any race conditions or other issues of ensuring focus. And, I think that it fires deterministically -- it'll execute immediately.
The one caveat is that it uses an undocumented call to retreive the handle of the command window instance. This varies slightly by release as it is dependent upon the window frame layout. Some of Yair Altman's (undocumentedmatlab.com) work on the file exchange has more robust functions to grab this in a more general fashion; this code should work with most modern releases of Matlab (Tested on R2011a, both Mac & Win).
function interrupt
import java.awt.event.KeyEvent
import java.util.Calendar
import java.lang.reflection.*
cmdwin = handle(com.mathworks.mde.cmdwin.CmdWin.getInstance().getComponent(0).getComponent(0).getComponent(0),'CallbackProperties');
argSig = javaArray('java.lang.Class',1);
argSig(1) = java.lang.Class.forName('java.awt.event.KeyEvent');
method = cmdwin.getClass().getDeclaredMethod('processKeyEvent',argSig);
method.setAccessible(true);
cal = Calendar.getInstance();
args = javaArray('java.lang.Object',1);
args(1) = KeyEvent(cmdwin,KeyEvent.KEY_PRESSED,cal.getTime().getTime(),KeyEvent.CTRL_DOWN_MASK,KeyEvent.VK_C,KeyEvent.CHAR_UNDEFINED);
method.invoke(cmdwin,args);
You can use the function error. You will go back to matlab.
It will produce an error, but that is also what usually happen when you press CTRL+C, in a matlab script.
You should add some kind of message like error('Interrupted by user');
It is not exactly what you are asking for, but considering your example, your problem can be solved like that:
function terminateInCode()
hFig = figure('CloseRequestFcn',{#closeHandler});
stop=0;
while(~stop)
plot(10*rand,10*rand,'+');
pause(0.1);
end;
function closeHandler (src,evnt)
delete(hFig);
stop=1;
end
end
Try the return statement. It will push you out of a function.
If you want to terminate it completely you need to use ERROR.
You could always use EXIT if its really that disastrous.
I would like to be able to terminate my current running scripts( functions ) by calling a command in the code. Return would only terminate the current function not entire script. Therefore return is not the one.
What I am looking for is a command which does exactly what CTRL + C do.
I have already seen this: how to stop execution and noticed that no one has yet provided a proper answer for this question in there either.
ultimately I want to terminate the entire running scripts upon closing a figure:
hFig = figure('CloseRequestFcn',{#closeHandler});
.
.
.
function closeHandler (src,evnt)
CTRL+C <--- I am looking for such a command
end
PS. function error() will not work either: Try this:
function terminateInCode()
hFig = figure('CloseRequestFcn',{#closeHandler});
while(1)
plot(10*rand,10*rand,'+');
pause(0.1);
end;
function closeHandler (src,evnt)
delete(hFig);
error('program terminated!');
end
end
Here is a sample function with example based on yuk's answer. Components include:
Insure the command window has focus to receive the CTRL+C
Use a timer to release CTRL+C after the break has occurred
Use a Java robot to press CTRL+C
Sample function is below:
function terminateExecution
%terminateExecution Emulates CTRL-C
% terminateExecution Stops operation of a program by emulating a
% CTRL-C press by the user.
%
% Running this function
%
%Example:
%for ix = 1:100
% disp(ix)
% if ix>20
% terminateExecution;
% end
%end
%1) request focus be transferred to the command window
% (H/T http://undocumentedmatlab.com/blog/changing-matlab-command-window-colors/)
cmdWindow = com.mathworks.mde.cmdwin.CmdWin.getInstance();
cmdWindow.grabFocus();
%2) Wait for focus transfer to complete (up to 2 seconds)
focustransferTimer = tic;
while ~cmdWindow.isFocusOwner
pause(0.1); %Pause some small interval
if (toc(focustransferTimer) > 2)
error('Error transferring focus for CTRL+C press.')
end
end
%3) Use Java robot to execute a CTRL+C in the (now focused) command window.
%3.1) Setup a timer to relase CTRL + C in 1 second
% Try to reuse an existing timer if possible (this would be a holdover
% from a previous execution)
t_all = timerfindall;
releaseTimer = [];
ix_timer = 1;
while isempty(releaseTimer) && (ix_timer<= length(t_all))
if isequal(t_all(ix_timer).TimerFcn, #releaseCtrl_C)
releaseTimer = t_all(ix_timer);
end
ix_timer = ix_timer+1;
end
if isempty(releaseTimer)
releaseTimer = timer;
releaseTimer.TimerFcn = #releaseCtrl_C;
end
releaseTimer.StartDelay = 1;
start(releaseTimer);
%3.2) Press press CTRL+C
pressCtrl_C
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function pressCtrl_C
import java.awt.Robot;
import java.awt.event.*;
SimKey=Robot;
SimKey.keyPress(KeyEvent.VK_CONTROL);
SimKey.keyPress(KeyEvent.VK_C);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function releaseCtrl_C(ignore1, ignore2)
import java.awt.Robot;
import java.awt.event.*;
SimKey=Robot;
SimKey.keyRelease(KeyEvent.VK_CONTROL);
SimKey.keyRelease(KeyEvent.VK_C);
Not sure it will work, just an idea. How about to emulate keyboard key press from MATLAB?
You can try either java.awd.Robot:
import java.awt.Robot;
import java.awt.event.*;
SimKey=Robot;
SimKey.keyPress(KeyEvent.VK_CONTROL);
SimKey.keyPress(KeyEvent.VK_C);
or WScript.Shell and SendKeys.
Unfortunately, it seems it cannot be done:
Mathworks
There is no way to programmatically issue a Ctrl+C in MATLAB besides using the keyboard's Ctrl+C combination.
As an alternative, you can use the ERROR command to force an error that will exit the code. For example:
error('Program terminated for a specific reason')
Here's an alternative that uses undocumented Matlab calls to place the key event directly into the command window. The method to do so is protected; this uses reflection to unprotect it.
Unlike #yuk and #Persuit's answers, this does not seem to have issues with the control key sticking. Additionally, it will always post directly to the command window without any race conditions or other issues of ensuring focus. And, I think that it fires deterministically -- it'll execute immediately.
The one caveat is that it uses an undocumented call to retreive the handle of the command window instance. This varies slightly by release as it is dependent upon the window frame layout. Some of Yair Altman's (undocumentedmatlab.com) work on the file exchange has more robust functions to grab this in a more general fashion; this code should work with most modern releases of Matlab (Tested on R2011a, both Mac & Win).
function interrupt
import java.awt.event.KeyEvent
import java.util.Calendar
import java.lang.reflection.*
cmdwin = handle(com.mathworks.mde.cmdwin.CmdWin.getInstance().getComponent(0).getComponent(0).getComponent(0),'CallbackProperties');
argSig = javaArray('java.lang.Class',1);
argSig(1) = java.lang.Class.forName('java.awt.event.KeyEvent');
method = cmdwin.getClass().getDeclaredMethod('processKeyEvent',argSig);
method.setAccessible(true);
cal = Calendar.getInstance();
args = javaArray('java.lang.Object',1);
args(1) = KeyEvent(cmdwin,KeyEvent.KEY_PRESSED,cal.getTime().getTime(),KeyEvent.CTRL_DOWN_MASK,KeyEvent.VK_C,KeyEvent.CHAR_UNDEFINED);
method.invoke(cmdwin,args);
You can use the function error. You will go back to matlab.
It will produce an error, but that is also what usually happen when you press CTRL+C, in a matlab script.
You should add some kind of message like error('Interrupted by user');
It is not exactly what you are asking for, but considering your example, your problem can be solved like that:
function terminateInCode()
hFig = figure('CloseRequestFcn',{#closeHandler});
stop=0;
while(~stop)
plot(10*rand,10*rand,'+');
pause(0.1);
end;
function closeHandler (src,evnt)
delete(hFig);
stop=1;
end
end
Try the return statement. It will push you out of a function.
If you want to terminate it completely you need to use ERROR.
You could always use EXIT if its really that disastrous.
I have just recently started to use MATLAB to acquire data off of a data acquisition board and was in need of a function to acquire data continuously (i.e. until I ctrl^C out of the function). To do this I am using the data acquisition toolbox on a 32-bit windows OS.
Based on the documentation in matlab help and a few of the answers on this site, I found that after adding channels to my input handle I should:
set my 'SamplesPerTrigger' to Inf
set the 'TimerPeriod' to some value to trigger the 'TimerFcn'
set the 'TimerFcn' to some subfunction callback which appends data to a persistent variable
Is this a correct way to do this?
My code is as follows:
function acquire_arena_test(samprate,daq_device ,device_ID ,channels, saveroot)
setup.SampleRate = samprate;
setup.DAQdevice = {daq_device, device_ID};
setup.AIChannels = channels;
setup.SaveRoot = {saveroot};
ai = analoginput(setup.DAQdevice{1},setup.DAQdevice{2});
addchannel(ai,[setup.AIChannels]);
set(ai,'SamplesPerTrigger',Inf);
set(ai,'TimerPeriod',0.5);
set(ai,'TimerFcn',{#AcquireData,ai});
start(ai);
while(strcmpi(get(ai,'Running'),'On'))
pause(1)
end
stop(ai);
time = datestr(now,30);
save([saveroot time], 'data');
delete(ai);
clear ai;
function AcquireData(hObject, ~)
persistent totalData;
data = getdata(hObject);
if isempty(totalData)
totalData =data;
else
totalData = [totalData; data];
end
The initial analog input is definitely working properly. I have tried many permutations of giving the AcquireData callback to 'TimerFcn'. The error I receive is
`??? Error using ==> acquire_arena_test>AcquireData
Too many input arguments.
Warning: The TimerFcn callback is being disabled.
To enable the callback, set the TimerFcn property. `
Thanks in advance for any help.
I think the syntax you use for setting up your TimerFcn is wrong. You write
set(ai,'TimerFcn',{#AcquireData,ai});
but this means that your function AcquireData will be called with tree parameters: AcquireData(ai, event, ai) as explained here, which then of course triggers the error message since your AcquireData function only accepts two parameters. Just change your code to
set(ai,'TimerFcn',#AcquireData);
and it should work; the ai object is automatically passed as the first parameter (see the link to the MATLAB documentation above).
Sorry about answering my own question, but I figured it out. The trigger was not needed after all. Using a national instruments board (or a sound card, as it turns out) you can just change the LoggingMode to 'disk' and specify a file to save the .daq (data acquisition toolbox) file to save as with LogFileName. If you want to use the memory on your board, change the mode to disk&Memory. Helpful document:
http://www.mathworks.com/help/toolbox/daq/f12-16658.html
The script below acquires data during the pause, which is as long as you want it to be..
daqreset;
clear all;
ai = analoginput('nidaq','Dev1');
chans = addchannel(ai,0:6);
set(ai,'SamplesPerTrigger',Inf);
set(ai,'SampleRate',1000)
set(ai,'LogToDiskMode','Overwrite')
set(ai,'LogFileName','log.daq')
set(ai,'LoggingMode', 'disk')
start(ai)
pause()
stop(ai)
data = daqread('log.daq');
delete(ai);
Note that you still need to set 'SamplesPerTrigger' to Inf for this to work properly. Thank you to Jonas for his help as well.