This example shows how to implement a communication channel for Processor-in-the-Loop (PIL) simulation.
This communication channel enables exchange of data between different processes. This supports capabilities such PIL simulation that require exchange of data between the Simulink® software environment (running on your host machine) and deployed code (running on target hardware).
You will learn about the rtiostream interface and how it provides a generic communication channel that you can implement in the form of target connectivity drivers for a range of different connection types. This example explains how to use the default implementation via TCP/IP.
You will learn how two entities, Station A and Station B can use the rtiostream interface to set up a communication channel and exchange data. For the purposes of this example, both Station A and Station B are configured within the same process on your desktop computer.
You will learn how to use the target connectivity drivers to support an on-target PIL simulation. For on-target simulation, Station A and Station B represent the target and host computers that exchange data via the communication channel. On the host side, the target connectivity driver is implemented as a shared library that is loaded and called from within the MATLAB® product. On the target side, the driver must be source code or a library that is linked into the application that runs on the target.
Additionally, this example explains the steps required to:
Configure your own target-side driver for TCP/IP to operate with the default host-side TCP/IP driver
Configure the supplied host-side driver for serial communications
Implement custom target connectivity drivers, e.g. using CAN or USB for both host and target sides of the communication channel.
|On this page…|
The file rtiostream_tcpip.c implements both client-side and server-side TCP/IP communication; a startup parameter is used to configure the driver to operate in either client or server mode. You may use this source file as a starting point for a custom implementation. Note that, in general, each side of the communication channel only requires one or other of the server or client implementations; if the client and server drivers will run on different architectures, it may be convenient to place the driver code for each architecture in a separate source file.
The header file rtiostream.h contains prototypes for the functions rtIOStreamOpen/Send/Recv/Close. Include it (using #include) for custom implementations.
% Location of TCP/IP driver source code rtiostreamtcpip_dir=fullfile(matlabroot,'rtw','c','src','rtiostream',... 'rtiostreamtcpip'); % View rtiostream_tcpip.c edit(fullfile(rtiostreamtcpip_dir,'rtiostream_tcpip.c')); % View rtiostream.h edit(fullfile(matlabroot,'rtw','c','src','rtiostream.h'));
To access the target connectivity drivers from the MATLAB product they must be compiled to a shared library. The shared library must be located on your system path. A shared library for the default TCP/IP drivers is located in matlabroot/bin/$ARCH (where $ARCH is your system architecture, e.g. win64)
% The shared library filename extension and location depends on your operating % system. sharedLibExt=system_dependent('GetSharedLibExt'); % Shared library for both Station A and Station B libTcpip = ['libmwrtiostreamtcpip' sharedLibExt]; disp(libTcpip)
If you are implementing a custom target connectivity driver, it is helpful to be able to test it from within the MATLAB product. The following example shows how to load the default TCP/IP target connectivity drivers and use them for data exchange between Station A and Station B.
To access the drivers you can use the MEX-file rtiostream_wrapper. This MEX-file allows you to load the shared library and access the rtiostream functions to open/close an rtiostream channel and send/receive data.
In this example, both Station A and Station B are running on the host computer. Station A is configured as a TCP/IP server and Station B as a TCP/IP client. For host to target communication, the host is typically configured as a TCP/IP client and the target as a TCP/IP server.
% Choose a port number for TCP if usejava('jvm') % Find a free port tempSocket = java.net.ServerSocket(0); port = num2str(tempSocket.getLocalPort); tempSocket.close; else % Resort to a hard-coded port port = '14646'; end % Open the Station A rtiostream as a TCP/IP server stationA = rtiostream_wrapper(libTcpip,'open',... '-client', '0',... '-blocking', '0',... '-port',port); % If the communication channel opens, the return value is a % handle to the connection; a return value of -1 indicates an error. assert(stationA~=(-1)) % Test for expected return value % Open the Station B rtiostream as a TCP/IP client stationB = rtiostream_wrapper(libTcpip,'open',... '-client','1',... '-blocking', '0',... '-port',port,... '-hostname','localhost'); % If the communication channel opens, the return value is a % handle to the connection; a return value of -1 indicates an error. assert(stationB~=(-1)) % Test for expected return value
The target connectivity drivers are designed to send a stream of data in 8-bit bytes. For processors that are not byte-addressable the data is sent in the smallest addressable word size.
% Send Some Data from Station B to Station A msgOut = uint8('Station A, this is Station B. Are you there? OVER'); [retVal, sizeSent] = rtiostream_wrapper(libTcpip,... 'send',... stationB,... msgOut,... length(msgOut)); assert(retVal==0); % A return value of zero indicates success assert(sizeSent==length(msgOut)); % Check that bytes in the message were sent % Allow time for data transmission to complete pause(0.2) % Receive data on the Station A [retVal, msgRecvd, sizeRecvd] = rtiostream_wrapper(libTcpip,... 'recv',... stationA,... 100); assert(retVal==0); % A return value of zero indicates success assert(sizeRecvd==sizeSent); % Check that bytes in the message were received % Display the received data disp(char(msgRecvd))
Station A, this is Station B. Are you there? OVER
% Send data from Station A to Station B msgOut = uint8('Station B, this is Station A. Yes, I''m here! OVER.'); [~, sizeSent] = rtiostream_wrapper(libTcpip,... %#ok 'send',... stationA,... msgOut,... length(msgOut)); % Allow time for data transmission to complete pause(0.2) % Receive data on Station B [~, msgRecvd, sizeRecvd] = rtiostream_wrapper(libTcpip,... %#ok 'recv',... stationB,... 100); % Display the received data disp(char(msgRecvd))
Station B, this is Station A. Yes, I'm here! OVER.
% Close rtiostream on the Station B retVal = rtiostream_wrapper(libTcpip,'close',stationB); assert(retVal==0); % A return value of zero indicates success % Close rtiostream on the Station A retVal = rtiostream_wrapper(libTcpip,'close',stationA); assert(retVal==0) % A return value of zero indicates success % Unload the shared library rtiostream_wrapper(libTcpip, 'unloadlibrary');
You can use the supplied host-side driver for serial communications as an alternative to the drivers for TCP/IP. You can configure the serial driver using a similar approach to the TCP/IP driver. For details, see rtiostream_wrapperrtiostream_wrapper in the Embedded Coder® reference documentation.
If your target has an ethernet connection and you have a TCP/IP stack available, follow these steps:
1. Write a wrapper for your TCP/IP stack that makes it available via the rtiostream interface defined in rtiostream.h. 2. Write a test application for your target that sends and receives some data, similar to the example above. 3. You can use the rtiostream_wrapper MEX-file and host-side TCP/IP driver to test your driver software running on the target. 4. When you have a working target-side driver you must include these driver source files in the build for your automatically generated code.
Note that the default host-side driver used by PIL mode is configured as a TCP/IP client; this means that your target-side driver need only be configured to operate as a TCP/IP server.
If you need to use a communications channel that is not already supported on the host-side, you will have to write drivers for both host and target. In this case you can still use the rtiostream_wrapper MEX-file for testing your rtiostream drivers.
You can implement the target connectivity drivers using many different communication channels. For example, you may need to implement host-target communications via a special serial connection. In this case you must provide drivers for both the host and target.
On the host-side, you can test the drivers using the rtiostream_wrapper MEX-file. Note that if your driver includes diagnostic output using printf these must be replaced with mexPrintf if the shared library is being loaded by rtiostream_wrapper.
When you have a working host-side device driver you must make it available within the Simulink software environment. For PIL simulation, you can do this by registering the shared host-side shared library via sl_customization.