Simulink mex s-function: rename in/output port from c-code?

Hi
I'm struggeling with a problem: to rename scalar in/output signals of a custom mex-s-function block during initialization time (mdlInitializeSize() for example).
Is this possible? I tried several hacks so far, but got nothing but a bunch of MATLAB crashes... alas, we reached 2012, so at least web2.0 has to be good for something ;-)
My first try was to execute normal matlab code from the C-side using mexEvalString(). So something equivalent to:
p = get_param(gcb, 'PortHandles')
l = get_param(p.Outport, 'Line')
set_param(l, 'Name', 'myname')
But the "gcb" statement may choose some other blocks, and not always the block where the C-code is residing in... Is there some other possibility to access the current S-Function block at this stage?
In the documentation I found the suggestion to be at least able to check the name of an "Bus Port" (and only after certain things are applied, so this just may go in a kind of right direction and not solve my problem):
DTypeId dType = ssGetOutputPortDataType(S, 0);
int numElems = ssGetNumBusElements(S, dType);
const char *elemName = (char*)ssGetBusElementName(S, dType, 0);
std::cout << elemName << std::endl;
...which will crash during execution. probably because i dont have a bus but a single port... Since I found no field named "name" or typed "char*" in the SimStruct*-argument i suppose there is no such information on the C-side.
Whatever. Do you pros have an idea what I could or should do?
Thanks a lot!

 채택된 답변

Kaustubha Govind
Kaustubha Govind 2012년 3월 6일

1 개 추천

Try ssGetPath to get the block path instead of gcb.

추가 답변 (1개)

marvin
marvin 2012년 3월 6일
Hm, thanks for the idea... ssGetPath returns the path to the block as a string. nice. after making some mistakes (have to edit my complete answer...) i figured out how this works. "find_system" is the wrong call to get the handle, "get_param('bla','Handle')" does this. So my complete code looks like this:
h = get_param('modell/helloworld', 'Handle')
p = get_param(h, 'PortHandles')
l = get_param(p.Outport, 'Line')
set_param(l, 'Name', 'myname')
so now let's say I have more than one output port to work on: then the last call to "get_param()" will return a cell-array... I can't squeeze everything in one line.
is there an obvious way to code this in C? I one solution would be to use several calls to "mexCallMATLAB()" to prevent cluttering of users worksspace... however this is much coding work ;-) The other would be to rely on variables in the MATLAB workspace and code this as a "poor-mans-m-script"...
edit again: yay it works... but i have to say: i hate plain c... i probably leaked more memory than i allocated...
last edit: for the sake of completeness and for educational purposes, here my CC-BY-SA'ed over-verbose memory leaking solution:
/* this is an awfull lot of c-code... which does essentially the same as the following:
* at first (only possible/neccessary on the c-side) getting the block-path of _this_ block
path = ssGetPath(S);
* then setting the name after obtaining the correct data-structures. the corresponding m-code is as
* follows:
h = get_param(path, 'Handle')
p = get_param(h, 'PortHandles')
l = get_param(p.Outport, 'Line')
set_param(l(portId+1), 'Name',name)
* note that this only works error-less if the port is connected!
*/
bool setOutputPortName(SimStruct* S, unsigned int portNr, const char* name)
{
/* at first get the handle to our simulink function block */
mxArray* h;
{
mxArray *right[2];
right[0] = mxCreateString(ssGetPath(S));
right[1] = mxCreateString("Handle");
mexCallMATLAB(1,&h,2,right,"get_param");
mxDestroyArray(right[0]);
mxDestroyArray(right[1]);
}
mxArray* p;
/* now obtain the 'PortHandles' struct-field "Outport" of the given port-id... */
{
mxArray *left[1];
mxArray *right[2];
right[0] = h;
right[1] = mxCreateString("PortHandles");
mexCallMATLAB(1,left,2,right,"get_param");
mxDestroyArray(h);
mxDestroyArray(right[1]);
/* get string inside a struct-field named "Outport" */
if (!mxIsStruct(left[0]))
{
std::cerr << "setOutputPortName() no stuct returned" << std::endl;
return false;
}
/* in field "field_num", there resides an array with all Outport-handles. we need the one
* indexd by "portNr" */
mxArray* temp = mxGetField(left[0], 0, "Outport");
p = mxCreateDoubleScalar(mxGetPr(temp)[portNr]);
/* i am allowed to destroy the return-array myself */
mxDestroyArray(left[0]);
}
/* finally we have to get the last param "Line" */
mxArray* l;
{
mxArray *right[2];
right[0] = p;
right[1] = mxCreateString("Line");
mexCallMATLAB(1,&l,2,right,"get_param");
mxDestroyArray(p);
mxDestroyArray(right[1]);
}
/* and now, we can set out payload, finally... i hate plain-c */
{
mxArray *right[3];
right[0] = l;
right[1] = mxCreateString("Name");
right[2] = mxCreateString(name);
mexCallMATLAB(0,NULL,3,right,"set_param");
mxDestroyArray(l);
mxDestroyArray(right[1]);
mxDestroyArray(right[2]);
}
}

Community Treasure Hunt

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

Start Hunting!

Translated by