Opened 7 years ago
Last modified 7 years ago
#4678 new enhancement
Allow passing external objects as parameters to a class
Reported by: | Bernhard Thiele | Owned by: | somebody |
---|---|---|---|
Priority: | high | Milestone: | Future |
Component: | *unknown* | Version: | v1.13.0-dev-nightly |
Keywords: | Cc: | Martin Sjölund, Volker Waurich |
Description
There are cases there passing external objects as parameters to a class is very handy. An example is in the Modelica_DeviceDrivers library where an external object holding the handle to a Comedi-device is used as a parameter for ADC and DAC device blocks. The MLS 3.4 doesn't allow this construction, but it is supported by some other tools and I think the MLS 3.4 is overly restrictive in this respect.
OpenModelica seems to almost support it. The two examples below show the principle.
Test_EO
creates an external object namedeo
and uses it directly. This (standard conform) model works.Test_BlockWithEOParameter
is almost the same except that the logic is outsourced in a block which is instantiated and the block receives the external object as an argument. This (non standard conform) model doesn't work.
OpenModelica translates example 2. to C code without error, but during C code compilation one gets the error:
EOsAsParameter.Test_BlockWithEOParameter.c:90:48: error: use of undeclared identifier '$PblockEO$Peo' omc_EOsAsParameter_doSthWithEO(threadData, $PblockEO$Peo)
blockEO.eo
is just an alias for eo
. It seems that not much is missing to have it working and I think it would be a fine enhancement if one could actually make it work.
package EOsAsParameter "Using external objects as parameter" model Test_EO EO eo=EO("handlepath"); equation when sample(0,0.2) then doSthWithEO(eo); end when; end Test_EO; model Test_BlockWithEOParameter EO eo=EO("handlepath"); BlockWithEOParameter blockEO(eo=eo); end Test_BlockWithEOParameter; block BlockWithEOParameter "Block with ExternalObject as parameter" parameter EO eo; equation when sample(0,0.2) then doSthWithEO(eo); end when; end BlockWithEOParameter; class EO "External object" extends ExternalObject; function constructor "Open device" input String devicename = "/dev/comedi0" "Device name"; output EO eo "Handle to external object"; external "C" eo = my_eo_create(devicename) annotation (Include=" void* my_eo_create(const char* devicename) { int dummy = 0; return (void*)&dummy; } "); end constructor; function destructor "Close device" input EO eo "Handle to external object"; external "C" my_eo_free(eo) annotation (Include="void my_eo_free(void* eo) {}"); end destructor; end EO; function doSthWithEO input EO eo; external "C" doSthWithEO(eo) annotation (Include=" #include <ModelicaUtilities.h> void doSthWithEO(void* eo) { ModelicaFormatMessage(\"Called doSthWithEO\\n\"); } "); end doSthWithEO; end EOsAsParameter;
Change History (2)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
The goal is that the original code creates exactly one external object and the blockEO
uses exactly this object, just using an alias name.
What I tried to explain in the motivation, is that there are several blocks that need to access the same external object. The proposed workaround creates an external object for blockEO
, but this object can't be shared. To clarify, what I want is something like:
model Test_BlockWithEOParameter EO eo=EO("handlepath"); BlockWithEOParameter b1(eo=eo); BlockWithEOParameter b2(eo=eo); end Test_BlockWithEOParameter;
where b1
and b2
share the same external object eo
. This could be done by using inner/outer, but that is less flexible, because I would also like to do things like:
model Test_BlockWithEOParameter EO eo1=EO("path1"); EO eo2=EO("path2"); BlockWithEOParameter b1(eo=eo1); BlockWithEOParameter b2(eo=eo1); BlockWithEOParameter b3(eo=eo2); BlockWithEOParameter b4(eo=eo2); end Test_BlockWithEOParameter;
As a standard conform workaround one can try using an inner/outer array, resulting in something which resembles
model Test_BlockWithEOParameter inner EO eo[2]= {EO("path1"), EO("path2")}; BlockWithEOParameter b1(index=1); BlockWithEOParameter b2(index=1); BlockWithEOParameter b3(index=2); BlockWithEOParameter b4(index=2); end Test_BlockWithEOParameter;
However, I don't think this is as elegant and explicit as simply "passing" the external object to the block. I also find it not intuitive to allow passing external objects to functions, but forbid "passing" them to blocks.
A workaround is to pass the constructor as a modifier instead of passing an object:
This way you'd also create only one EO object, while the original code will create two which could be an issue since the device will be opened twice.
Also, BlockWithEOParameter.eo is declared as parameter, so giving it a continuous binding like in the original code is invalid. I'm not entirely sure whether it even makes sense to allow specifying the variability of an external object though, any reason why you declared that one as parameter?