Function and Custom Script Mapping

Function Mapping

Function Mapping is very similar to Custom Script Mapping. However, Function Mapping calls upon a function from a library instead of providing Lua code directly.

On the Message Configuration object, navigate to the Message Description Properties and set the Mapping Type property to "Function Mapping". This will reveal the Function Mapping options subsection below.

Mapping Type - Function
Figure 1. Mapping Type - Function Mapping

Function Library is the library used for the mapping. This library must be directly inherited from "esi-msi-function" ("EXTEND") in order to prevent misuse of this configuration.

Input Function is the name of the function which processes incoming data (similar to Input Script).

Input Options is a JSON string, which is passed as an additional Lua table to the input function.

Input Function and Input Options are only used if the Communication mode is 'Send' or 'Bidirection'.

Output Function is the name of the function which processes outgoing data (similar to Output Script).

Output Options is a JSON string, which is passed as an additional Lua table to the output function.

The requirement to inherit the library from "esi-msi-function" prevents an accidental configuration and the triggering of random library functions. It also allows the provision of some interface documentation together with the "esi-msi-function" library documentation.

The two additional …​ Option strings (JSON format)permit a flexible configuration of potentially generic functions. Both functions have to be part of the same library.

A simple example of a library with an input and output function
-- MSI_FUNC_EXAMPLE
local JSON = require('rapidjson')
local MSI = require("esi-msi-function")

local funcT = MSI:__EXTEND__("MSI_FUNC_EXAMPLE",{})

function funcT:INPUT(content, optTable, mesgId, mapTable)
     -- mapTable allows access to the central mapping but is not used here
     local dataInPath = optTable.base.."/integrationTest/MProF/DataIn"
     content.msgId = msgId    -- there is no msgId field in the content, so no name clash
     local jsonData = JSON.encode(content)
     local res = syslib.setvalue(dataInPath, jsonData)
     return res
end

function funcT:OUTPUT(optTable, mapTable)
     -- mapTable allows access to the central mapping but is not used here
     local dataOutPath = optTable.base.."/integrationTest/MProF/DataOut"
     local dataAbortPath = optTable.base.."/integrationTest/MProF/DataAbort"
     local jsonData = syslib.getvalue(dataOutPath)
     local jsonAbort = syslib.getvalue(dataAbortPath)
     if jsonAbort then
          local abort = JSON.decode(jsonAbort)
          syslib.setvalue(dataAbortPath, "")
          return nil, abort, abort.msgId
     elseif jsonData then
          local data = JSON.decode(jsonData)
          syslib.setvalue(dataOutPath, "")
          return data, nil, data.msgId
     else
          return
     end
end
return funcT

The output table for data needs to be of this form:

{parameter=[{ name=ObjectName1, value=Value1},{name= ObjectName2, value=Value2}]}

"ObjectName1" and "ObjectName2" need to match the object names defined in the Tag List table. "Value1" and "Value2" are the values assigned to these object names in the response. Be aware that these values must match the type defined in the Tag List table.

A response example
{"parameter":[ {"name":"RecipeName","value":"Recipe1"},
               {"name":"OrderNumber","value":"orno_0101"},
               {"name":"MaterialName","value":"matname_0101"},
               {"name":"BatchID_basic","value":"Batch_b_01"},
               {"name":"MaterialNumber","value":"matno_0101"}
          ]}

The output table for abort must be of the following form:

{parameter= {{ name=Qualifier1, value=Value1},{name= Qualifier2, value=Value2}},
    errors= {{ code= "101",  text = "something went wrong..." }} }

The qualifiers are the MES qualifiers required to assign the abort message to the correct EBR in the MES. The errors-code and errors-text are code and text of the error leading to the abort.

In addition to the content and the abortContent, a Message ID can be provided, which allows the MSI interface to process several pending messages for the same 'Message Configuration' in parallel. Providing a Message ID will remove the message with a corresponding ID from the list of pending messages. If no ID is provided, all pending messages for this 'Message Configuration' will be removed instead.

All values are automatically converted into a string format during XML encoding, which complies with the interface definition of MSI Interface. However, if problems should occur during this string conversion, the values can also be provided as strings in the corresponding format, e.g., Double being represented as "3.41" and Boolean being "true" or "false".

In addition to the parameter section of the message, all other information needed to generate the message is taken from the configuration above. This includes qualifier information, Message ID, etc.

Custom Script Mapping

Custom Script Mapping is a mapping type that is carried out by custom Lua scripts.

In the Message Description Properties, set the Mapping Type property to "Custom Script". This will display the Custom Script Options below.

Mapping Type - Custom
Figure 2. Mapping Type - Custom Script

The first script is the Input Script. This script needs to return a function, which is executed whenever a message is received. The input parameter of this function is the content of the message in the form of a Lua table. This script can return true or false.

A simple input script example
local dataInPath = "/System/Core/integrationTest/MProC/DataIn"
local JSON = require('rapidjson')
local fun = function(content, msgId, mapTable)
     -- mapTable allows access to the central mapping but is not used here
     content.msgId = msgId  -- there is no msgId field in the content, so no name clash
     local jsonData = JSON.encode(content)
     local res = syslib.setvalue(dataInPath, jsonData)
     return res
end
return fun

The second script is the Output Script. This script is executed every second to check for available transmission data. If no message is sent, this script should return nil. Otherwise, it must return the data matching the Message Configuration.

A simple output script example, only returning data read from an I/O-Item
local dataOutPath = "/System/Core/integrationTest/MProC/DataOut"
local dataAbortPath = "/System/Core/integrationTest/MProC/DataAbort"
local JSON = require('rapidjson')
local fun = function(mapTable)
     -- mapTable allows access to the central mapping but is not used here
     local jsonAbort = syslib.getvalue(dataAbortPath)
     local jsonData = syslib.getvalue(dataOutPath)
     if jsonAbort then
          local abort = JSON.decode(jsonAbort)
          syslib.setvalue(dataAbortPath, "")
          return nil, abort, abort.msgId
     elseif jsonData then
          local data = JSON.decode(jsonData)
          syslib.setvalue(dataOutPath, "")
          return data, nil, data.msgId
     else
          return
     end
end

The output data table needs to be of the following format:

{parameter= { { name=ObjectName1, value=Value1},{name= ObjectName2, value=Value2}} }

"ObjectName1" and "ObjectName2" must match the object names defined in the Tag List table. "Value1" and "Value2" are the values assigned to these object names in the response. Be aware that "Value1" and "Value2" must match the type defined in the Tag List table.

A response example
{parameter={ {name="RecipeName",     value="Recipe1"},
             {name="OrderNumber",    value="orno_0101"},
             {name="MaterialName",   value="matname_0101"},
             {name="BatchID_basic",  value="Batch_b_01"},
             {name="MaterialNumber", value="matno_0101"}
}}

The output table for abort must be of the following format:

{parameter= {{ name=Qualifier1, value=Value1},{name= Qualifier2, value=Value2}},
    errors= {{ code= "101",  text = "something went wrong..." }} }

The qualifiers are the MES qualifiers required to assign the abort message to the correct EBR in the MES. The errors-code and errors-text are code and text of the error leading to the abort.

In addition to the content and the abortContent, a Message ID can be provided, which allows the MSI interface to process several pending messages for the same 'Message Configuration' in parallel. Providing a Message ID will remove the message with a corresponding ID from the list of pending messages. If no ID is provided, all pending messages for this 'Message Configuration' will be removed instead.

All values are automatically converted into string format during XML encoding, which complies with the interface definition of the MSI interface. However, if problems should occur during this string conversion, the values can also be provided as strings in the corresponding format, e.g., Double being represented as "3.41" and Boolean being "true" or "false".

In addition to the parameter section of the message, all other information needed to generate the message is taken from the configuration above. This includes qualifier information, Message ID, etc.

Using Central Mapping

Use cases of Function Mapping and Custom Script Mapping that are not Tag-based do not require Central Mapping.

However, there might also be use cases which rely on the availability of a Central Mapping between EquipmentId+Tag and a system path. Therefore, the function calls have been extended to include the Mapping Table from the Message Processor object, so that the Input Script/Input Function and the Output Script/Output Function can read the Central Mapping Table.