I have this code that is supposed to change the referenced subsystems in a model to normal subsystems, because I have another script that no longer works on matlab 2020, only on 2017, due to the change of the applications libraries to referenced subsystems. When I run it, I get multiple:
*** W02293: SIMULINK DATA TYPE RESTRICTIONS:
*** Could not perform min/max logging or overflow detection for signal.
*** The ufix1 Simulink data type is not supported.
Followed by:
Error using change (line 4)
Invalid Simulink object handle
Anybody know why? I use the version Matlab R2020b with TargetLink 5.1p1
refSubsystem = 'subsys20b';
modelName = 'modelRefSubsys20b';
open_system("Application Name");
oldBlock = [ modelName '/Subsystem Reference'];
newBlock = [ modelName '/subsystem'];
% create a copy of the referenced subsystem
add_block('built-in/Subsystem', newBlock)
Simulink.BlockDiagram.copyContentsToSubsystem(refSubsystem, newBlock)
% Retrieve useful info from the old block
t1 = get_param(oldBlock, 'Portconnectivity');
t2 = get_param(oldBlock, 'PortHandles');
t3 = get_param(newBlock, 'PortHandles');
% delete old lines
h = get_param(oldBlock, 'LineHandles');
ni = numel(h.Inport);
no = numel(h.Outport);
delete_line(h.Inport);
delete_line(h.Outport);
% create connections to new block
for i=1:numel(t2.Inport)
srcBkhdl = t1(i).SrcBlock; % source block handle
srcNm = getfullname(srcBkhdl); % source block name
srcBkPts = get_param(srcNm, 'PortHandles'); % source block port handles
srcPt = srcBkPts.Outport(t1(i).SrcPort+1); % source port
dstPt = t3.Inport(i); % destination port
add_line(modelName, srcPt, dstPt);
end
% create connections from new block
for i=1:numel(t2.Outport)
dstBkhdl = t1(ni+i).DstBlock; % dest block handle
dstNm = getfullname(dstBkhdl); % dest block name
dstBkPts = get_param(dstNm, 'PortHandles'); % dest block port handles
dstPt = dstBkPts.Inport(t1(ni+i).DstPort+1); % dest port
srcPt = t3.Outport(i); % src port
add_line(modelName, srcPt, dstPt);
end
% copy to same position
pos = get_param(oldBlock, 'position');
set_param(newBlock, 'position', pos);
% remove old block
delete_block(oldBlock);
% save changes
save_system(modelName);
I just had a similar error wanting to revert Referenced Subsystems to simple Subsystems. In my case however, I did not want to do that programmatically.
I use MATLAB2021a and had a project initializing the Search Paths.
Removing the Referenced Subsystem link from the Block Parameters raised:
Invalid Simulink object handle
and prevented me to save the model.
The workaround that I found was:
To open the model without loading my project. Not loading the project prevented the Referenced Subsystem from loading since it couldn't find its referenced file. In someone else's case, one could simply move the referenced file outside of your Search Path.
Remove the link to the referenced file. I found that doing this after failing to load did not cause the same error.
Once the link removed, it is safe to open said referenced file, copy its content and paste it in the now simple subsystem block.
Save
I am aware that you wanted to perform this programmatically and I hope this helps you or someone else. Keep in mind, I am no expert. I simply messed around and found something that worked for me.
I'm trying to receive a message sent over OSC from Pure Data (or Max/MSP) to MATLAB.
I'm able to send OSC messages from Pure Data to Pure Data
I can send messages from MATLAB to MATLAB
I can even send messages from MATLAB to Pure Data
...I'm really struggling to get Pure Data to talk back to MATLAB
Here's my code that sends messages from MATLAB (I'm using the oscmex protocol):
host = 'localhost'; % local host UDP address
sendPort = 3333; % UDP port number to send over
receivePort = 3333; % UDP port number to receive from
oscAddress = osc_new_address(host, sendPort); % open send address
oscServer = osc_new_server(receivePort); % open server
dataPacket = struct('path','/foo','tt','f','data',{num2cell([1.0])}); % create packet
osc_send(oscAddress, dataPacket); % write packet to OSC
oscMessage = osc_recv(oscServer, 0.1); % listen for packet on OSC
% check to see if anything is there...
if length(oscMessage) > 0
fprintf('Found something!')
else
fprintf('Failed to find anything')
end
osc_free_address(oscAddress);
osc_free_server(oscServer);
If I send using host 'localhost', everything works fine sending from MATLAB to MATLAB using the code above. If I set it to '127.0.0.1', MATLAB sends to Pure Data, but MATLAB then can't receive its own messages.
Now for the other end of things. Here's my Pure Data patch:
Again, running the above patch alone successfully sends and receives messages through Pure Data.
The problem lies when I try to talk from one program to another. If I set things so that MATLAB is sending on port 3333 and Pure Data is receiving on 3333, and that Pure Data is sending on 2222 and MATLAB is receiving on 2222, I can make Pure Data receive if MATLAB's host is '127.0.0.1'. But, with '127.0.0.1', MATLAB can't send to itself.
In any case, no matter what I try, I'm unable to make Pure Data send to MATLAB, despite being able to get it to send to itself. I suspect it has something to do with the 'host' address.
My actual IPv4 address (found using 'ipconfig' of the MS command prompt) is completely different from 127.0.0.1, and using the value specified here doesn't seem to make things work any better.
I'm aware that I can't have more than one OSC server with the same port open at any one time and so my current attempt at a solution involves sending from MATLAB on one port, and sending from Pure Data on another, with only a single server open at one time on either port.
Note I'm also aware that I use /foo for messages from MATLAB and /test from Pure Data. However, my MATLAB code indiscriminately receives everything sent over OSC, so this makes no difference.
Any help getting PD to talk to MATLAB would be appreciated.
Update: Ive solved the 'localhost' issue and that doesn't seem to fix things (i had to add localhost to my Windows 'hosts' file). So, I may have been barking up the wrong tree by worrying about the localhost thing. But, I still can't get PD to talk to MATLAB.
Update #2: Amro has posted an elegant solution below and I still can't get MATLAB to receive messages from Pure Data. I've installed CloseTheDoor to monitor my UDP connections and notice that when MATLAB sets up a server, it uses the 'Interface' [::0], whereas PD sets uses 'Interface' 0.0.0.0. Since PureData is the one that successfully receives messages, perhaps I need to make MATLAB listen on 0.0.0.0 as well?
Let me start by saying that I've never used PureData or OSC before, and I just duplicated the graph/patch you've shown to create the server/client.
1) server in PureData, client in MATLAB:
First lets create the server in PureData:
Now here is a simple client implemented as a GUI in MATLAB:
function example_osc_client()
handles = createGUI();
osc = [];
function h = createGUI()
h.fig = figure('Menubar','none', 'Resize','off', ...
'CloseRequestFcn',#onClose, ...
'Name','OSC Client', 'Position',[100 100 220 140]);
movegui(h.fig, 'center')
h.conn = uicontrol('Style','pushbutton', 'String','Connect', ...
'Callback',{#onClick,'connect'}, ...
'Parent',h.fig, 'Position',[20 20 80 20]);
h.disconn = uicontrol('Style','pushbutton', 'String','Disconnect', ...
'Callback',{#onClick,'disconnect'}, ...
'Parent',h.fig, 'Position',[120 20 80 20]);
h.slid = uicontrol('Style','slider', 'Callback',#onSlide, ...
'Min',-10, 'Max',10, 'Value',0, ...
'Parent',h.fig, 'Position',[30 60 160 20]);
h.txt = uicontrol('Style','text', 'String','0.0', ...
'Parent',h.fig, 'Position',[80 100 60 20]);
set([h.slid;h.disconn], 'Enable','off');
drawnow
end
function onClick(~,~,action)
switch lower(action)
case 'connect'
osc = osc_new_address('127.0.0.1', 2222);
set(handles.conn, 'Enable','off')
set(handles.disconn, 'Enable','on')
set(handles.slid, 'Enable','on')
case 'disconnect'
osc_free_address(osc); osc = [];
set(handles.conn, 'Enable','on')
set(handles.disconn, 'Enable','off')
set(handles.slid, 'Enable','off')
end
drawnow
end
function onSlide(~,~)
if isempty(osc), return; end
val = single(get(handles.slid,'Value'));
m = struct('path','/test', 'tt','f', 'data',{{val}});
osc_send(osc, m);
set(handles.txt, 'String',num2str(val))
drawnow
end
function onClose(~,~)
if ~isempty(osc)
osc_free_address(osc);
end
delete(handles.fig);
end
end
As you move the slider, messages are sent to the server (using OSC-MEX interface), and the values are displayed in the PureData model.
While testing this, I noticed that double type was not supported, as I saw the following message in the PD log window:
unpackOSC: PrintTypeTaggedArgs: [A 64-bit float] not implemented
So it was necessary to either manually cast values as single or explicitly specify the hint type in the structure passed to osc_send OSC-MEX function:
val = single(1);
m = struct('path','/test', 'tt','f', 'data',{{val}});
osc_send(osc, m);
2) server in MATLAB, client in PureData:
Similarly we create the client in PureData:
Again, here is the server implemented as a MATLAB GUI:
function example_osc_server()
handles = createGUI();
osc = [];
function h = createGUI()
h.fig = figure('Menubar','none', 'Resize','off', ...
'CloseRequestFcn',#onClose, ...
'Name','OSC Server', 'Position',[100 100 220 140]);
movegui(h.fig, 'center')
h.start = uicontrol('Style','pushbutton', 'String','Start', ...
'Callback',{#onClick,'start'}, ...
'Parent',h.fig, 'Position',[20 20 80 20]);
h.stop = uicontrol('Style','pushbutton', 'String','Stop', ...
'Callback',{#onClick,'stop'}, ...
'Parent',h.fig, 'Position',[120 20 80 20]);
h.txt = uicontrol('Style','text', 'String','', ...
'Parent',h.fig, 'Position',[60 80 100 20]);
set(h.stop, 'Enable','off');
drawnow expose
h.timer = timer('TimerFcn',#receive, 'BusyMode','drop', ...
'ExecutionMode','fixedRate', 'Period',0.11);
end
function onClick(~,~,action)
switch lower(action)
case 'start'
set(handles.start, 'Enable','off')
set(handles.stop, 'Enable','on')
osc = osc_new_server(2222);
start(handles.timer);
case 'stop'
set(handles.start, 'Enable','on')
set(handles.stop, 'Enable','off')
osc_free_server(osc); osc = [];
stop(handles.timer);
end
drawnow expose
end
function receive(~,~)
if isempty(osc), return; end
m = osc_recv(osc, 0.1);
if isempty(m), return; end
set(handles.txt, 'String',num2str(m{1}.data{1}))
drawnow expose
end
function onClose(~,~)
if ~isempty(osc)
osc_free_server(osc);
end
stop(handles.timer); delete(handles.timer);
delete(handles.fig);
clear handles osc
end
end
The server part was a bit trickier in MATLAB. The idea is that we don't want MATLAB to block indefinitely waiting for messages. So I created a timer which executes every 0.11 second. Inside the timer function we try to receive message in a blocking manner but with a timeout of 0.1 sec. This way both the GUI and MATLAB IDE stay responsive.
3) other combinations:
Using the above solutions, you could also open both client and server in PureData, or both client and server in MATLAB. It should work either way.
Finally I should say that it made no difference whether I'm using the hostname as localhost or specified the IP address directly 127.0.0.1.
HTH
EDIT:
I managed to compile the OSC-MEX package myself, here are the steps. First download osc-mex sources and its dependencies. This includes: liblo sources, pthreads-win32 binaries, premake4 executable.
1) We start by building the liblo library:
Copy "premake4.exe" into the "build" directory, and run: premake4 --platform=x32 vs2010
open the generated "liblo.sln" solution file in VS2010. Select the "liblo" project and go to "Project > Properties". Add the include folder containing pthreads header files in the "Additional Include Directories" field. Similarly add the lib folder for the linker, and specify pthreadVC2.lib as additional dependency.
Select the "ReleaseLib" Win32 target and build the project. This should create the final target: lib\ReleaseLib\liblo.lib
Note that by default, IPv6 support is disabled in liblo because OSC applications like Pd have problems with IPv6. If you still want to enable it, add the following line to config.h file:
#define ENABLE_IPV6 1
2) Next we compile the MEX-functions in MATLAB:
Go to the folder containing the C-sources of the MEX-functions
copy liblo.lib from the previous step into this directory. Also copy pthreadVC2.lib from the pthreads library.
compile each function using:
mex -largeArrayDims -I../path/to/liblo-0.27 xxxxxx.c pthreadVC2.lib liblo.lib -lwsock32 -lws2_32 -liphlpapi
You should end up with six *.mexw32 files for each of the xxxxxx.c source files
Finally copy the pthreads DLL into this same folder: pthreadVC2.dll
To save you some troubles, here are the compiled MEX-files built on WinXP 32-bit and Win8 64-bit both using VS2010. Here are the sources if you would like to compile it yourself (simply build the solution in VS2010, then run osc_make.m in MATLAB)
localhost is an alias for 127.0.0.1; they really are the same IP-address. so if matlab only receives something if it is sending to localhost but not if sending to 127.0.0.1, they probably have a buggy implementation of OSC.
as long as you have [udpreceive 2222] in your patch, Pd will block the port UDP/2222, and matlab will not be able to receive anything on that port.
so the simple solution is: remove [udpreceive 2222] before creating the matlab server using osc_new_server(2222);
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.