Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add libiio support #366

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
101 changes: 101 additions & 0 deletions Modelica_DeviceDrivers/Blocks/Examples/TestHardwareIIO.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
within Modelica_DeviceDrivers.Blocks.Examples;
model TestHardwareIIO "Example to access the Inertial Measurement Unit of a Pinephone via InternetIO"
import Modelica_DeviceDrivers;
extends Modelica.Icons.Example;

Modelica_DeviceDrivers.Blocks.HardwareIO.IIO.IIOConfig iio(deviceName="mobian.local")
annotation (Placement(transformation(extent={{-80,60},{-60,80}})));
Modelica_DeviceDrivers.Blocks.HardwareIO.IIO.PhysicalDataRead dataRead_x(
sampleTime=0.05,
iio=iio.dh,
devicename="mpu6050",
channelname="accel_x") annotation (Placement(transformation(extent={{-80,-10},{-60,10}})));
Modelica_DeviceDrivers.Blocks.OperatingSystem.RealtimeSynchronize
realtimeSynchronize(
enable=true,
sampled=true,
sampleTime=0.05)
annotation (Placement(transformation(extent={{60,60},{80,80}})));
Modelica_DeviceDrivers.Blocks.HardwareIO.IIO.PhysicalDataRead dataRead_y(
sampleTime=0.05,
iio=iio.dh,
devicename="mpu6050",
channelname="accel_y") annotation (Placement(transformation(extent={{-80,-40},{-60,-20}})));
Modelica_DeviceDrivers.Blocks.HardwareIO.IIO.PhysicalDataRead dataRead_z(
sampleTime=0.05,
iio=iio.dh,
devicename="mpu6050",
channelname="accel_z") annotation (Placement(transformation(extent={{-80,-70},{-60,-50}})));
Modelica.Blocks.Routing.Multiplex3 a annotation (Placement(transformation(extent={{-40,-40},{-20,-20}})));

BullsEyeLevel bullsEyeLevel(theta(fixed=true, start=0), psi(fixed=true, start=0))
annotation (Placement(transformation(extent={{10,-70},{90,10}})));

model BullsEyeLevel
extends Modelica.Blocks.Interfaces.MIMO(nin=3,nout=2);

parameter Modelica.Units.SI.Length d = 0.02 "Diameter of the virtual detection sphere";

Modelica.Units.SI.Length r[3] "Position of the ball";
Modelica.Units.SI.Velocity v[3] "Velocity of the ball";
Modelica.Units.SI.Acceleration a[3] "Acceleration of the ball";

Real theta "Polar angle from the origin to the ball" annotation (Dialog(showStartAttribute=true));
Real psi "Azimuth angle from the origin to the ball" annotation (Dialog(showStartAttribute=true));

Modelica.Mechanics.MultiBody.Types.Axis e_r "Normalized vector from the origin to the ball";
Modelica.Mechanics.MultiBody.Types.Axis e_theta "Normalized vector in azimuth direction on the sphere";
Modelica.Mechanics.MultiBody.Types.Axis e_psi "Normalized vector in altitude direction on the sphere";

Real x2D[2] "Coordinates of the ball center in 2D representation";

equation
e_r[1] = sin(theta)*cos(psi);
e_r[2] = sin(theta)*sin(psi);
e_r[3] = cos(theta);

e_theta[1] = cos(theta)*cos(psi);
e_theta[2] = cos(theta)*sin(psi);
e_theta[3] = -sin(theta);

e_psi = cross(e_r,e_theta);

r = d/2*e_r;
der(r) = v;
a = u;

der(theta) = a*e_theta;
der(psi) = a*e_psi/max(Modelica.Constants.eps,d/2*sin(theta));

y = {theta,psi};

x2D[1] = -80*sin(theta)*sin(psi);
x2D[2] = 80*sin(theta)*cos(psi);

annotation (Icon(graphics={
Ellipse(extent={{-80,80},{80,-80}}, lineColor={0,0,0}),
Ellipse(extent={{-40,40},{40,-40}}, lineColor={0,0,0}),
Line(
points={{0,-90},{0,90}},
color={0,0,0},
pattern=LinePattern.None),
Line(points={{0,-90},{0,90}}, color={0,0,0}),
Line(points={{-90,0},{90,0}}, color={0,0,0}),
Ellipse(
extent=DynamicSelect({{-10,10},{10,-10}},{{-10,10}+x2D,{10,-10}+x2D}),
pattern=LinePattern.None,
fillColor={0,0,0},
fillPattern=FillPattern.Solid)}), Documentation(info="<html>
<p><span style=\"font-size: 9pt;\">This model implements a virtual ball hinged with a fixed radius to a central fixation resctricting its path to a sphere. The input accelerations act on that ball. The animation is a top view of the sphere with the current position of the ball.</span></p>
</html>"));
end BullsEyeLevel;
equation
connect(dataRead_x.y, a.u1[1]) annotation (Line(points={{-59,0},{-50,0},{-50,-23},{-42,-23}}, color={0,0,127}));
connect(dataRead_y.y, a.u2[1]) annotation (Line(points={{-59,-30},{-42,-30}}, color={0,0,127}));
connect(dataRead_z.y, a.u3[1]) annotation (Line(points={{-59,-60},{-50,-60},{-50,-37},{-42,-37}}, color={0,0,127}));
connect(a.y, bullsEyeLevel.u) annotation (Line(points={{-19,-30},{2,-30}}, color={0,0,127}));
annotation (Documentation(info="<html>
<p>This example was tested with a Mobian installation on a Pinephone. The package <span style=\"font-family: Courier New;\">iiod</span> has to be installed on the phone. It works out-of-the-box without further configuration.</p>
<p>Any other linux device supporting IIO (i. e. a Raspberry Pi connected to a MPU6050 chip) can be used. Only the IIO deamon has to be installed and configured.</p>
</html>"));
end TestHardwareIIO;
1 change: 1 addition & 0 deletions Modelica_DeviceDrivers/Blocks/Examples/package.order
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ TestInputJoystick
TestInputKeyboard
TestInputKeyboardKey
TestHardwareIOComedi
TestHardwareIIO
TestSerialPackager_TCPIP
TestSerialPackager_LCM
TestSerialPackager_MQTT
Expand Down
75 changes: 75 additions & 0 deletions Modelica_DeviceDrivers/Blocks/HardwareIO.mo
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,79 @@ Enumeration that defines the available reference channels used in a DAQ-card
</html>"));
end Types;
end Comedi;

package IIO "Support for the linux device communication library 'libiio'"
extends Modelica.Icons.Package;

record IIOConfig "Configuration for the linux device communication library 'libiio'"
extends Modelica_DeviceDrivers.Utilities.Icons.ComediRecordIcon;

import Modelica_DeviceDrivers.HardwareIO.IIO;
parameter String deviceName = "" "Network address of IIO device. Leave empty for local device (Linux only)";

final parameter IIO dh = IIO(deviceName) "Handle to comedi device";

annotation (defaultComponentName="iio",
preferredView="info",
Icon(graphics={
Text(
extent={{-98,72},{94,46}},
textString="%deviceName"),
Bitmap(extent={{-96,-92},{10,20}}, fileName=
"modelica://Modelica_DeviceDrivers/Resources/Images/Icons/gears.png")}),
Documentation(info="<html>
<p>Record for configuring a IIO device. At initialization time the IIO device given by the parameter <span style=\"font-family: Courier New;\">deviceName </span>will be opened and a handle to that device will be assigned to the final parameter<span style=\"font-family: Courier New;\"> dh.</span>This handle needs to be passed as parameter to the remaining IIO read and write blocks<span style=\"font-family: Courier New;\">.</span></p>
<h4>Note</h4>
<p>On Windows, the code should work fine with the provided <span style=\"font-family: Courier New;\">libiio.lib</span> file from the libiio Release (<a href=\"https://github.com/analogdevicesinc/libiio\">https://github.com/analogdevicesinc/libiio</a>).</p>
<p>For linux, the IIO library has to be compiled first. Best practice is to run <span style=\"font-family: Courier New;\">cmake</span> with the <span style=\"font-family: Courier New;\">BUILD_SHARED_LIBS=OFF</span> parameter. This will create <span style=\"font-family: Courier New;\">libiio.a</span> in the build directory, which you can place in <span style=\"font-family: Courier New;\">Resources/library/linux64</span>.</p>
<p>If accessing a local linux device, it is required that the simulation process has sufficient privileges to access the intended device (usually that requires &quot;root&quot; privileges).</p>
</html>"));
end IIOConfig;

block PhysicalDataRead "Read Real value from IIO channel"
extends Modelica_DeviceDrivers.Utilities.Icons.ComediBlockIcon;
import Modelica_DeviceDrivers.HardwareIO.IIO;
import Modelica_DeviceDrivers.HardwareIO.IIOchannel;

parameter Modelica.Units.SI.Period sampleTime=0.01 "Sample time of block";
parameter IIO iio "Handle to comedi device";
parameter String devicename "Device name";
parameter String channelname "Channel name";
Modelica.Blocks.Interfaces.RealOutput y
annotation (Placement(transformation(extent={{100,-10},{120,10}})));
protected
final parameter IIOchannel channel = IIOchannel(iio, devicename, channelname);
Real scaleData "Scale value read from channel";
Real rawData "Raw value read from channel";

equation
when initial() then
scaleData = Modelica_DeviceDrivers.HardwareIO.IIO_.data_read(channel, "scale");
end when;
when sample(0,sampleTime) then
rawData = Modelica_DeviceDrivers.HardwareIO.IIO_.data_read(channel, "raw");
y = scaleData*rawData;
end when;

annotation (defaultComponentName="dataRead",
preferredView="info",
Icon(graphics={Text(extent={{-222,
88},{222,58}},
textColor={0,0,0},
textString="Device: %devicename"), Text(extent={{-222,
54},{222,24}},
textString="channel: %channelname",
textColor={0,0,0}), Text(extent={{-220,
20},{224,-10}},
textString="Ts: %sampleTime",
textColor={0,0,0}), Text(extent={{-220,
-104},{224,-134}},
textString="Device: %iio",
textColor={0,0,0}), Text(extent={{-152,142},{148,102}},
textString="%name")}), Documentation(info="<html>
<p>The parameter <span style=\"font-family: Courier New;\">iio</span> needs to be set to a valid IIO context handle, i.e., needs to be set to the record member <span style=\"font-family: Courier New;\">dh</span> of a <span style=\"font-family: Courier New;\">IIOConfig</span> record instance.</p>
<p>Uses the Comedi function<span style=\"font-family: Courier New;\"> iio_channel_attr_read_double(..)</span> to read the a <span style=\"font-family: Courier New;\">raw</span> and <span style=\"font-family: Courier New;\">scale</span> attribute of a IIO channel and multiplies them to get the value reading.</p>
</html>"));
end PhysicalDataRead;
end IIO;
end HardwareIO;
25 changes: 25 additions & 0 deletions Modelica_DeviceDrivers/HardwareIO/IIO.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
within Modelica_DeviceDrivers.HardwareIO;
class IIO
"Interface to the Industrial I/O (http://analogdevicesinc.github.io/libiio/), a linux subsystem to communicate with ICs"
extends ExternalObject;

encapsulated function constructor "Open device"
import Modelica;
extends Modelica.Icons.Function;
import Modelica_DeviceDrivers.HardwareIO.IIO;
input String targetname "Network address of IIO device. Leave empty for local device (Linux only)";
output IIO iio "File handle to IIO context";
external "C" iio = MDD_iio_open(targetname)
annotation (Include="#include \"MDDIIO.h\"", Library="libiio");
end constructor;

encapsulated function destructor "Close device"
import Modelica;
extends Modelica.Icons.Function;
import Modelica_DeviceDrivers.HardwareIO.IIO;
input IIO iio "File handle to IIO context";
external "C" MDD_iio_close(iio)
annotation (Include="#include \"MDDIIO.h\"", Library="libiio");
end destructor;

end IIO;
12 changes: 12 additions & 0 deletions Modelica_DeviceDrivers/HardwareIO/IIO_/data_read.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
within Modelica_DeviceDrivers.HardwareIO.IIO_;
encapsulated function data_read "Read from analog channel"
import Modelica;
extends Modelica.Icons.Function;
import Modelica_DeviceDrivers.HardwareIO.IIO;
import Modelica_DeviceDrivers.HardwareIO.IIOchannel;
input IIOchannel channel "Channel handle";
input String attrname "Device name";
output Real data "Value that is read from channel";
external "C" data = MDD_iio_data_read(channel, attrname)
annotation (Include="#include \"MDDIIO.h\"", Library="libiio");
end data_read;
5 changes: 5 additions & 0 deletions Modelica_DeviceDrivers/HardwareIO/IIO_/package.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
within Modelica_DeviceDrivers.HardwareIO;
package IIO_ "Accompanying functions for the IIO object"
extends Modelica_DeviceDrivers.Utilities.Icons.DriverIcon;

end IIO_;
1 change: 1 addition & 0 deletions Modelica_DeviceDrivers/HardwareIO/IIO_/package.order
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data_read
26 changes: 26 additions & 0 deletions Modelica_DeviceDrivers/HardwareIO/IIOchannel.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
within Modelica_DeviceDrivers.HardwareIO;
class IIOchannel
"Interface to a Industrial I/O device channel"
extends ExternalObject;

encapsulated function constructor "Open channel"
import Modelica;
extends Modelica.Icons.Function;
import Modelica_DeviceDrivers.HardwareIO.IIO;
import Modelica_DeviceDrivers.HardwareIO.IIOchannel;
input IIO iio "File handle to IIO context";
input String devicename "Device name";
input String channelname "Channel name";
output IIOchannel channel "File handle to IIO channel";
external "C" channel = MDD_iio_open_channel(iio, devicename, channelname)
annotation (Include="#include \"MDDIIO.h\"", Library="libiio");
end constructor;

encapsulated function destructor "Close channel"
import Modelica;
extends Modelica.Icons.Function;
import Modelica_DeviceDrivers.HardwareIO.IIOchannel;
input IIOchannel channel "Channel context";
end destructor;

end IIOchannel;
3 changes: 3 additions & 0 deletions Modelica_DeviceDrivers/HardwareIO/package.order
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
Comedi
Comedi_
IIO
IIOchannel
IIO_
68 changes: 68 additions & 0 deletions Modelica_DeviceDrivers/Resources/Include/MDDIIO.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/** Linux Internet-I/O support (header-only library).
*
* @file
* @author m-kormann
* @since 2023-04-13
* @copyright see accompanying file LICENSE_Modelica_DeviceDrivers.txt
*/

#ifndef MDDIIO_H_
#define MDDIIO_H_

#include <stdlib.h>
#include <../thirdParty/libiio/iio.h>

#include "ModelicaUtilities.h"

#define IIO_ENSURE(expr, message, context) { \
if (!(expr)) { \
(void) ModelicaFormatError("%s %s (%s:%d)\n", message, context, __FILE__, __LINE__); \
} \
}

void* MDD_iio_open(const char* targetname) {
struct iio_context *ctx = NULL;
if (targetname[0] != '\0') {
IIO_ENSURE(ctx = iio_create_network_context(targetname), "Could not open IIO host", targetname);
}
else {
IIO_ENSURE(ctx = iio_create_local_context(), "Could not open IIO host", "locally");
}
IIO_ENSURE(iio_context_get_devices_count(ctx) > 3, "No devices found at host", targetname);

return (void*) ctx;
}

void MDD_iio_close(void* p_ctx) {
static struct iio_context *ctx;
ctx = (struct iio_context *) p_ctx;
tbeu marked this conversation as resolved.
Show resolved Hide resolved
if (ctx) {
iio_context_destroy(ctx);
}
}

void* MDD_iio_open_channel(void *p_ctx, const char* devicename, const char* channelname) {
static struct iio_context *ctx;
ctx = (struct iio_context *) p_ctx;
tbeu marked this conversation as resolved.
Show resolved Hide resolved

static struct iio_device *dev;
tbeu marked this conversation as resolved.
Show resolved Hide resolved
IIO_ENSURE(dev = iio_context_find_device(ctx, devicename), "Device not found: ", devicename);

struct iio_channel *chn;
IIO_ENSURE(chn = iio_device_find_channel(dev, channelname, false), "Channel not found: ", channelname);

return (void *) chn;
}
tbeu marked this conversation as resolved.
Show resolved Hide resolved

double MDD_iio_data_read(void* p_chn, const char* attrname) {
struct iio_channel *chn = (struct iio_channel *) p_chn;

double val = 0;

int ret = iio_channel_attr_read_double(chn, attrname, &val);
IIO_ENSURE(ret == 0, "Attribute not found: ", attrname);

return val;
}

#endif /* MDDIIO_H_ */
Binary file not shown.
Loading