Open Test Framework  
OTX-Mapping Scripting Support

Although OTX is Turing-complete, practical experience shows that not every task should actually be implemented in OTX. In particular, for computationally intensive algorithms or functions that lie outside the actual diagnostic processes, the use of a specialized scripting language is often significantly more efficient without compromising process reliability.

Introduction

Using the Scripting Support, a script can be invoked from OTX via ExecuteDeviceService. The following scripting languages are supported:

  1. Lua When compactness and performance are important, especially when using OTX in embedded systems, Lua is the best choice. Since the OTX runtime already uses Lua, no additional system requirements are necessary.
  2. Python Due to the large ecosystem of libraries, complex calculations can be implemented efficiently in Python.

OTX Mapping

The script is bound via the OTX mapping to a DeviceServiceSignature, see the figure below.

The functions to be used in the script file must be marked using comments. The following comment describes the parameters of the QuickSort function:

--[[OtxDeviceService: in List<Integer> arr, in Integer left, in Integer right, out List<Integer>]]
function OtxScriptingSupportExample.QuickSort(arr, left, right)
--...
end
Comment Description
--[[OtxDeviceService Bound to DeviceServiceSignature
in List<Integer> arr Input parameter named arr of type List<Integer>
in Integer left Input parameter named left of type Integer
in Integer right Input parameter named right of type Integer
out List<Integer> Return value of type List<Integer>

Supported Data Types

All OTX mapping data types and their automatic conversions are supported, except for Enumeration.

Note: Lua does not support enumerations!

OTX Scripting Example

The following examples demonstrates the execution of a Lua function inside OTX. The executable PTX file can be downloaded:

Executable example PTX

Lua code example

local OtxScriptingSupportExample = {}
--[[OtxDeviceService: in Integer length, out List<Integer>]]
function OtxScriptingSupportExample.RandomList(n)
local t = {}
for i = 1, n do
t[i] = math.random(1, 1000000)
end
return t
end
--[[OtxDeviceService: in List<String> arr, out String]]
function OtxScriptingSupportExample.StringConcat(arr)
return table.concat(arr, "")
end
--[[OtxDeviceService: in List<Integer> arr, in Integer left, in Integer right, out List<Integer>]]
function OtxScriptingSupportExample.QuickSort(arr, left, right)
left = left or 1
right = right or #arr
if left == 0 then
left = 1
right = right + 1
end
if left >= right then
return arr
end
local pivot = arr[math.floor((left + right) / 2)]
local i, j = left, right
while i <= j do
while arr[i] < pivot do i = i + 1 end
while arr[j] > pivot do j = j - 1 end
if i <= j then
arr[i], arr[j] = arr[j], arr[i]
i = i + 1
j = j - 1
end
end
if left < j then
OtxScriptingSupportExample.QuickSort(arr, left, j)
end
if i < right then
OtxScriptingSupportExample.QuickSort(arr, i, right)
end
return arr
end
--[[OtxStructure: String Type, Map<String, Float> Props]]
local Shape = {
Type = "",
Props = {}
}
-- constructor
function Shape:new(o)
o = o or {}
local obj = {}
-- copy default values if not provided
for k,v in pairs(self) do
-- skip functions
if type(v) ~= "function" then
obj[k] = o[k] or v
end
end
obj.Props = o.Props or {}
setmetatable(obj, { __index = self })
return obj
end
--[[OtxDeviceService: in Float width, in Float height, out Shape]]
function OtxScriptingSupportExample.CreateRectangle(width, height)
local r = Shape:new({
Type = "Rectangle",
Props = {
Width = width or 0.0,
Height = height or 0.0
}
})
return r
end
--[[OtxDeviceService: in Shape shape, out Float]]
function OtxScriptingSupportExample.ComputeArea(shape)
if shape.Type == "Circle" then
return 3.14 * shape.Props.Radius * shape.Props.Radius
elseif shape.Type == "Rectangle" then
return shape.Props.Width * shape.Props.Height
else
error("Unknown shape type")
end
end
--[[OtxDeviceService: in Float radius, out BlackBox]]
function OtxScriptingSupportExample.CreateCircle(radius)
local c = Shape:new({
Type = "Circle",
Props = {
Radius = radius or 0.0
}
})
return c
end
--[[OtxDeviceService: in BlackBox shape, out Float]]
function OtxScriptingSupportExample.ComputePerimeter(shape)
if shape.Type == "Circle" then
-- Perimeter = 2 * π * r
return 2 * 3.14 * shape.Props.Radius
elseif shape.Type == "Rectangle" then
-- Perimeter = 2 * (w + h)
return 2 * (shape.Props.Width + shape.Props.Height)
else
error("Unknown shape type: " .. tostring(shape.Type))
end
end
--[[OtxDeviceService: in Map<String, Float> map, out Map<String, Shape>]]
function OtxScriptingSupportExample.CreateShapes(map)
local result = {}
for key, value in pairs(map) do
if type(value) ~= "number" then
error("Value for key '" .. tostring(key) .. "' must be float")
end
if key == "Circle" then
result[key] = Shape:new({
Type = "Circle",
Props = {
Radius = value or 0.0
}
})
elseif key == "Rectangle" then
result[key] = Shape:new({
Type = "Rectangle",
Props = {
Width = value or 0.0,
Height = value or 0.0
}
})
else
error("Shape '" .. tostring(key) .. "' not supported")
end
end
return result
end
return OtxScriptingSupportExample

OTX/OTL code example which calls functions inside the Lua code

namespace OtxScriptingSupportExamplePackage1
{
package DataType.StructureSignature Shape(String Type, Map<String, Float> Props);
package Measure.DeviceSignature OtxScriptingSupportExample
{
Measure.DeviceServiceSignature RandomList(in Integer length, out List<Integer> Result);
Measure.DeviceServiceSignature QuickSort(
in List<Integer> arr,
in Integer left,
in Integer right,
out List<Integer> Result
);
Measure.DeviceServiceSignature CreateRectangle(in Float width, in Float height, out Shape Result);
Measure.DeviceServiceSignature ComputeArea(in Shape shape, out Float Result);
}
public procedure main(in Integer listLength = 1000)
{
List<Integer> randomList;
List<Integer> sortedList;
Integer time;
Measure.ExecuteDeviceService(OtxScriptingSupportExample, RandomList, {length = listLength, Result = randomList}, false, false);
time = DateTime.GetTimestamp();
Measure.ExecuteDeviceService(OtxScriptingSupportExample, QuickSort, {arr = randomList, left = 1, right = ListGetLength(randomList), Result = sortedList}, false, false);
time = DateTime.GetTimestamp() - time;
HMI.ConfirmDialog(ToString(sortedList), StringUtil.StringConcatenate({"List sorted via Lua in ", ToString(time), " ms"}));
time = DateTime.GetTimestamp();
QuickSort(ref randomList, 0, ListGetLength(randomList) - 1);
time = DateTime.GetTimestamp() - time;
HMI.ConfirmDialog(ToString(sortedList), StringUtil.StringConcatenate({"List sorted via OTX in ", ToString(time), " ms"}));
}
private procedure QuickSort(ref List<Integer> arr, in Integer left, in Integer right)
{
Integer pivot;
Integer i;
Integer j;
Integer mem;
pivot = arr[(left + right) / 2];
i = left;
j = right;
while (i <= j) : w1
{
while (arr[i] < pivot) : w2
{
i = i + 1;
}
while (arr[j] > pivot) : w3
{
j = j - 1;
}
if (i <= j)
{
mem = arr[j];
arr[j] = arr[i];
arr[i] = mem;
i = i + 1;
j = j - 1;
}
}
if (left < j)
{
QuickSort(ref arr, left, j);
}
if (i < right)
{
QuickSort(ref arr, i, right);
}
}
}