Scripting
For automated test environments the RT Box can be controlled via external scripts using an RPC interface. RPC is a lightweight protocol for executing functions on a remote machine. The RT Box acts as an RPC server, which processes requests sent from scripts running on another computer. Many scripting languages support RPC out of the box, for example Python or Ruby.
For Python, extensions for XML/JSON-RPC support are available. XML-RPC is an RPC protocol that uses XML to encode its calls. JSON-RPC is an RPC protocol that uses JSON-encoded messages. They both use HTTP as a transport mechanism.
In the following examples, Python 3.x syntax and script excerpts are used.
Establishing an XML/JSON-RPC Connection to the RT Box
The RT Box listens to RPC connections on TCP port 9998. The following Python code initiates an XML/JSON-RPC connection to the RT Box:
import socket
ip = socket.gethostbyname("examplebox.local")
For XML format:
import xmlrpc.client server = xmlrpc.client.ServerProxy("http://" + ip + ":9998/RPC2")
For JSON format:
import jsonrpc_requests server = jsonrpc_requests.Server("http://" + ip + ":9998/RPC2")
Note that the URL must end with “/RPC2”, which is an XML/JSON-RPC convention.
Overview of XML-RPC Commands
Commands for RT Box start with rtbox followed by a dot. In Python they are invoked on the server object, for example
server.rtbox.start()
Loading, starting and stopping a real-time simulation
The command
rtbox.load(binaryObject)
loads a new executable (ELF file) on the RT Box. The parameter binaryObject must be a base64 encoded RPC binary object. For XML format in Python, this object can be directly created using the Binary object from xmlrpc.client. The following code shows how to read an ELF executable file and load it on the RT Box using Python.
For XML format:
with open("TestModel_codegen/TestModel.elf", "rb") as f: server.rtbox.load(xmlrpc.client.Binary(f.read()))
For JSON format:
import base64 # deserialise MAT-file contents for JSON-RPC with open("TestModel_codegen/TestModel.elf", "rb") as f: server.rtbox.load(base64.b64encode(f.read()).decode())
The command
rtbox.start()
starts the execution of the real-time simulation.
The command
rtbox.stop()
stops the execution of the real-time simulation.
The command
rtbox.reboot('reboot')
stops the execution of the real-time simulation and reboots the RT Box.
The command
rtbox.querySimulation()
returns a struct with (at least) the following fields:
- modelName
The name of the model or subsystem that is currenty executed.
- sampleTime
The base discretization step size of the model.
- status
The current execution state of the simulation. Possible values are “stopped”, “running” and “error”.
The command
rtbox.getApplicationLog()
returns the log messages from the running simulation.
Sending data to the real-time simulation
The command
rtbox.setProgrammableValue('componentPath', valueList)
sets the output of the Programmable Value indicated by componentPath. The parameter componentPath is the path of the block relative to the code generation subsystem. The parameter valueList must be an XML-RPC array where the number of elements corresponds to the width of the output signal. If the Programmable Value Block has an output signal with a width of 1 a scalar value may be used as parameter. The example code below changes an output of width 2 to the values 5 and 7:
rtbox.setProgrammableValue('Value1', [5.0, 7.0])
Another example shows setting an output of width 1 to the value 7:
rtbox.setProgrammableValue('Value1', [7])
or
rtbox.setProgrammableValue('TestModel/Value1', 7)
Getting data from the real-time simulation
The command
rtbox.getCaptureData('componentPath')
returns the last filled data buffer from the Data Capture indicated by componentPath. The parameter componentPath is the path of the block relative to the code generation subsystem.The returned value is a struct with the following fields:
- data
The data as a two-dimensional array. The inner dimension corresponds to the width of the input signal, the outer dimension corresponds to the number of samples.
- triggerCount
Specifies how many times the sample buffer has been filled.
- sampleTime
Specifies the time between two samples, in seconds.
The command
rtbox.getCaptureTriggerCount('componentPath')
returns how many times the sample buffer of the Data Capture indicated by componentPath has been filled. The parameter componentPath is the path of the block relative to the code generation subsystem.
The command
rtbox.getDataCaptureBlocks()
returns a list of all Data Capture blocks in the current model, with path.
The command
rtbox.getProgrammableValueBlocks()
returns a list of all Programmable Value blocks in the current model, with path.
Example Script
This Python script loads a new executable on the RT Box and starts it. It sets a value and reads some values back from the model after the corresponding data block has captured sufficient data. The Data Capture block “Capture1” and the Programmable Value block “Value1” must be placed in the root schematic of the model. Finally, the real-time simulation is stopped.
import socket
import xmlrpc.client
import random
import time
ip = socket.gethostbyname("examplebox.local")
server = xmlrpc.client.ServerProxy("http://" + ip + ":9998/RPC2")
with open("TestModel_codegen/TestModel.elf", "rb") as f:
print("Uploading executable")
server.rtbox.load(xmlrpc.client.Binary(f.read()))
print("Starting executable")
server.rtbox.start()
print("Simulation running")
val = random.random()
print("Setting value %.7f" % val)
server.rtbox.setProgrammableValue('Value1', [val])
while server.rtbox.getCaptureTriggerCount('Capture1') == 0:
print("Waiting for data")
time.sleep(1)
data = server.rtbox.getCaptureData('Capture1')
print("Got value %.7f" % data['data'][0][0])
print("Stopping executable")
server.rtbox.stop()