2020-11-05 17:01:47 +00:00
/ * *
* @author Martin Karkowski
* @email m . karkowski @zema . de
* @create date 2020 - 07 - 16 10 :52 : 32
2020-12-01 12:05:35 +00:00
* @modify date 2020 - 11 - 25 07 :37 : 04
2020-11-05 17:01:47 +00:00
* @desc [ description ]
* /
export const LOGIC_TEMPLATES : {
[ index : string ] : string ;
} = {
// Template to define the Places.
//
// Requires the following Input:
// {
// places: [ {id: string} ]
// options.nameOfStatesType: string
// }
statesStructTemplate : ` <?xml version="1.0" encoding="utf-8"?>
< TcPlcObject Version = "1.1.0.1" ProductVersion = "3.1.4024.2" >
< DUT Name = "{{options.nameOfStatesType}}" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ TYPE { { options . nameOfStatesType } } :
STRUCT
{ { # each places } }
{ { id } } : INT ; ( * Element containing the Tokens of the Place { { id } } * )
{ { / e a c h } }
END_STRUCT
END_TYPE
] ] > < / Declaration >
< / DUT >
< / TcPlcObject >
` ,
transitionStructTemplate : ` <?xml version="1.0" encoding="utf-8"?>
< TcPlcObject Version = "1.1.0.1" ProductVersion = "3.1.4024.2" >
< DUT Name = "{{options.nameOfTransitionType}}" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ TYPE { { options . nameOfTransitionType } } :
STRUCT
iMaxTime : LWORD ; ( * Configured Max Time * )
iCurrentMaxTime : LWORD ; ( * Determined Max Time during the Runtime . This will be adapted automatically * )
iMinTime : LWORD ; ( * Configured Min Time * )
iCurrentMinTime : LWORD ; ( * Determined Min Time during the Runtime . This will be adapted automatically * )
bTimeParamsValid : BOOL ; ( * Flag indicating whether the Time Parameters are Valid or not * )
bUseMaxTime : BOOL ; ( * Flag to toggle on / off the Time Constraints for this Transition * )
bRelease : BOOL ; ( * Flag to toggle on Enable the Release of the Transition * )
END_STRUCT
END_TYPE
] ] > < / Declaration >
< / DUT >
< / TcPlcObject > ` ,
transitionVariableTemplate : ` <?xml version="1.0" encoding="utf-8"?>
< TcPlcObject Version = "1.1.0.1" ProductVersion = "3.1.4024.2" >
< DUT Name = "{{options.nameOfUsedTransitionsVariable}}" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ TYPE { { options . nameOfUsedTransitionsVariable } } :
STRUCT
{ { # each transitions } }
{ { id } } : { { options . nameOfTransitionType } } ; ( * Element containing the Parameters for the Trantision { { id } } * )
{ { / e a c h } }
END_STRUCT
END_TYPE
] ] > < / Declaration >
< / DUT >
< / TcPlcObject > ` ,
2020-12-01 12:05:35 +00:00
ifHeaderTemplate : "IF ({{> testConsumedPlaces}}{{> testRequiredPlaces}}{{> testAvoidedPlaces}}{{> testPostPlaces}}{{> testGuard}} {{>testTime}} {{#if isAction}}aTransitions.{{id}}.bRelease AND{{/if}} iRecursionCounter < {{options.maxRecursion}}) THEN" ,
testConsumedPlaces : "{{#each consumed}} ((aTokens.{{placeId}}{{#if minTokens}} - {{minTokens}}{{/if}}) >= {{tokensToRemove}}) AND{{/each}}" ,
testRequiredPlaces : "{{#each required}} (aTokens.{{placeId}} > 0) AND{{/each}}" ,
testAvoidedPlaces : "{{#each avoided}} (aTokens.{{placeId}} = 0) AND{{/each}}" ,
testPostPlaces : "{{#if hasTestOutputs}}{{#each testOutputs}} ((aTokens.{{placeId}} + {{tokensToAdd}}) <= {{maxTokens}}) AND{{/each}}{{/if}}" ,
testGuard : " {{{ externalGuard }}}" ,
testTime : "AND (aTransitions.{{id}}.bTimeParamsValid AND iDeltaTime >= aTransitions.{{id}}.iCurrentMinTime AND (NOT(aTransitions.{{id}}.bUseMaxTime) OR iDeltaTime <= aTransitions.{{id}}.iCurrentMinTime)) AND" ,
removeTokens : "{{#each consumed}}aTokens.{{placeId}} := aTokens.{{placeId}} - {{tokensToRemove}};{{/each}}" ,
addTokens : "{{#each produced}}aTokens.{{placeId}} := aTokens.{{placeId}} + {{tokensToAdd}};{{/each}}" ,
ifLogicalHeaderTemplate : "IF ({{> testConsumedPlaces}}{{> testRequiredPlaces}}{{> testAvoidedPlaces}}{{> testPostPlaces}} TRUE) THEN" ,
2020-11-05 17:01:47 +00:00
// Template to define a Method on a Function-Block.
//
// Requires the following Input:
// {
// functionName: string,
// // Contains the Returnvalue.
// functionReturnValue: string,
// // Containing the Inputs
// functionInputs: string,
// // Containing the Implementation
// functionImplementation: string
// }
2020-12-01 12:05:35 +00:00
fbTransitionFunctionTemplate : "" + ` <Method Name="{{methodName}}" Id="{{#uuid}}{{/uuid}}">
2020-11-05 17:01:47 +00:00
< Declaration > < ! [ CDATA [ METHOD { { methodName } } : BOOL
VAR_INPUT
iRecursionCounter : UINT ; ( * Counter preventing endless recursions * )
bTriggered : BOOL ; ( * Flag , indicating whether a check should be performed or not * )
iCurrentTime : LWORD ; ( * Current Time Pointer * )
END_VAR
VAR
sId : STRING ; ( * Variable containing the MQTT - Content string . * )
bTempTriggered : BOOL ; ( * Flag , indicating whether a check should be performed or not * )
iTempRecursionCounter : UINT ; ( * Counter preventing endless recursions . Internally used * )
END_VAR ] ] > < / Declaration >
< Implementation >
< ST > < ! [ CDATA [ bTempTriggered : = FALSE ;
// Test if the Transition is able to Fire.
{ { > ifHeaderTemplate } }
{ { # if hasInputs } }
// Removing Tokens from Pre-Places.
{ { > removeTokens } }
{ { # each consumed } }
{ { # timeAdaption this . placeId } } { { / t i m e A d a p t i o n } }
{ { / e a c h } }
{ { / i f } }
{ { # if hasOutputs } }
// Adding Tokens to the Post-Places.
{ { > addTokens } }
{ { # each produced } }
{ { # timeAdaption this . placeId } } { { / t i m e A d a p t i o n } }
{ { / e a c h } }
{ { / i f } }
{ { # if functionName } }
// Execute the desired Function
{ { # getFunctionTriggerCode this } } { { / g e t F u n c t i o n T r i g g e r C o d e } }
{ { / i f } }
IF bEnableMQTT THEN
// If MQTT is enabled just forward the fired Transition.
sId : = '{{id}}' ;
fbMqttClient . Publish ( '{{options.nameOfPlc}}/fired' , ADR ( sID ) , LEN ( sID ) , 1 , FALSE , FALSE ) ;
END_IF
{ { # if isAction } }
// Remove the Release
aTransitions . { { id } } . bRelease : = FALSE ;
{ { / i f } }
// Mark the Transition as Triggered
bTempTriggered : = TRUE ;
{ { # if hasTriggers } }
// Prepare Triggering Elements.
iTempRecursionCounter : = iRecursionCounter + 1 ;
{ { # each triggered } }
// Trigger Transition {{{label}}}
{ { methodName } } ( iTempRecursionCounter , TRUE , iCurrentTime ) ;
{ { / e a c h } }
{ { / i f } }
{ { # if hasReleases } }
{ { # each releases } }
// Set a Release to Transition {{{label}}}
aTransitions . { { this } } . bRelease : = TRUE ;
{ { / e a c h } }
{ { / i f } }
{ { # if hasLocks } }
{ { # each locks } }
// Lock the Transition {{{label}}}
aTransitions . { { this } } . bRelease : = FALSE ;
{ { / e a c h } }
{ { / i f } }
END_IF
// Transmit the Result.
{ { methodName } } : = bTempTriggered ; ] ] > < / ST >
< / Implementation >
< / Method >
` ,
2020-12-01 12:05:35 +00:00
fbTransitionAdaptTimesFunctionTemplate : "" + ` <Method Name="{{methodName}}_ADAPT_TIMES" Id="{{#uuid}}{{/uuid}}">
2020-11-05 17:01:47 +00:00
< Declaration > < ! [ CDATA [ METHOD { { methodName } } _ADAPT_TIMES : BOOL
VAR_INPUT
iCurrentTime : LWORD ; ( * Current Time Pointer * )
END_VAR
VAR
bTempEnabled : BOOL ; ( * Flag , indicating whether the Transition is logically enabled or not * )
END_VAR ] ] > < / Declaration >
< Implementation >
< ST > < ! [ CDATA [ // Toggle the Flag, that the Transition isnt able to fire.
bTempEnabled : = False ;
// Test, if the Transition is logically able to Fire.
{ { > ifLogicalHeaderTemplate } }
// The Transtion is logically able to Fire.
bTempEnabled : = TRUE ;
// Determine the Valid-Timestamp.
aTransitions . { { id } } . iCurrentMinTime : = aTransitions . { { id } } . iMinTime + iCurrentTime ;
aTransitions . { { id } } . iCurrentMaxTime : = aTransitions . { { id } } . iMaxTime + iCurrentTime ;
// Mark the Element as Enabled.
aTransitions . { { id } } . bTimeParamsValid : = TRUE ;
ELSE
// Mark the Element as Enabled.
aTransitions . { { id } } . bTimeParamsValid : = FALSE ;
END_IF
// Transmit the Result.
{ { methodName } } _ADAPT_TIMES : = bTempEnabled ; ] ] > < / ST >
< / Implementation >
< / Method >
` ,
// Template to define a logic based on a Petri-net.
//
// Requires the following Input:
// {
// uuid: '{uuid}',
// fbName: string,
// // Contains the Returnvalue.
// functionReturnValue: string,
// // Containing the Inputs
// functionInputs: string,
// // Containing the Implementation
// functionImplementation: string
// }
mainTemplate : ` <?xml version="1.0" encoding="utf-8"?>
< TcPlcObject Version = "1.1.0.1" ProductVersion = "3.1.4024.2" >
< POU Name = "{{options.nameOfMainFb}}" Id = "{{#uuid}}{{/uuid}}" SpecialFunc = "None" >
< Declaration > < ! [ CDATA [ FUNCTION_BLOCK { { options . nameOfMainFb } }
VAR_INPUT
bEnableLogic : BOOL : = FALSE ; ( * Flag to Enable / Disable the Main - Logic * )
bEnableMQTT : BOOL : = FALSE ; ( * Flag to Enable / Disable publishing Fired Transitions * )
sHostName : STRING ( 255 ) : = '127.0.0.1' ; ( * Hostname of the MQTT - Broker * )
nHostPort : UINT : = 1883 ; ( * Port of the MQTT - Broker * )
END_VAR
VAR_IN_OUT
bResetLogic : BOOL ; ( * Set to True to Reset the Logic . * )
END_VAR
VAR
bRunTestLoop : BOOL : = FALSE ;
iIterationCounter : INT : = 0 ;
iTimeLoPart : UDINT ; ( * Low Bytes of the Current Time * )
iTimeHiPart : UDINT ; ( * High Bytes of the Current Time * )
iTimeLo64 : LWORD ; ( * Low Bytes of the Current Time * )
iTimeHi64 : LWORD ; ( * Low Bytes of the Current Time * )
iCurrentTime : LWORD ; ( * Flag containing the current Time . Should be LWORD , which isnt supported on the PLC * )
iDeltaTime : LWORD ; ( * Time Containing the Delta , between start and now . * )
// MQTT Related Stuff
fbMqttClient : FB_IotMqttClient ; ( * An MQTT - Client * )
fbMessageQueue : FB_IotMqttMessageQueue ; ( * MQTT - Message - Queue * )
fbMessage : FB_IotMqttMessage ; ( * MQTT - Message * )
bSubscribedRelease : BOOL ;
sMQTTTopicRelease : STRING ( 255 ) : = '{{options.nameOfPlc}}/release' ; ( * MQTT - Topic on which messages are expected to Release an Action * )
bSubscribedLock : BOOL ;
sMQTTTopicLock : STRING ( 255 ) : = '{{options.nameOfPlc}}/locks' ; ( * MQTT - Topic on which messages are expected to Lock an Action * )
bSubscribedTrigger : BOOL ;
sMQTTTopicTrigger : STRING ( 255 ) : = '{{options.nameOfPlc}}/trigger' ; ( * MQTT - Topic on which messages are expected to Trigger an Action * )
{ attribute 'TcEncoding' : = 'UTF-8' }
sTopicRcv : STRING ( 255 ) ; ( * Received Topic * )
{ attribute 'TcEncoding' : = 'UTF-8' }
sPayloadRcv : STRING ( 255 ) ; ( * Received Payload * )
// MQTT Stuff to Send the State of the Net.
fbTONUpdateStates : TON ;
fbJson : FB_JsonSaxWriter ; ( * JSON - Writer * )
fbJsonDataType : FB_JsonReadWriteDataType ; ( * JSON - Object - Parser * )
{ attribute 'TcEncoding' : = 'UTF-8' }
sState : STRING ( 8192 ) ; ( * String containing the JSON * )
iStateLength : UDINT ; ( * Length of the Parsed Content * )
END_VAR
VAR_STAT
fbTime : GETSYSTEMTIME ; ( * FB for getting the time * )
bFirstRun : BOOL : = TRUE ; ( * Flag , used to mark the initial Run of the Petri - Net * )
bLogicEnabled : BOOL : = FALSE ; ( * Internal Flag to Enable / Disable the Logic * )
iStartTime : LWORD ; ( * Start Timestamp * )
aTokens : { { options . nameOfStatesType } } ; ( * Struct containing the Tokens of the Net * )
aTransitions : { { options . nameOfUsedTransitionsVariable } } ; ( * Array containing all Time Constrains of the Transitions in the Net * )
{ { ! List all Variables below } }
{ { # each variables } }
{ { name } } : { { type } } : = { { value } } ; ( * Accessor for Variable { { name } } . This Variable is used in the Logic * )
{ { / e a c h } }
{ { ! List all Subscribed Variables below } }
{ { # each subscribedVariables } }
{ { adaptedName } } : { { type } } ; ( * Accessor for Variable { { name } } . This Variable is used in the Logic * )
{ { / e a c h } }
// Section for Creating Instances:
{ { # each instances } }
{ { instanceName } } : { { fBName } } ; ( * Accessor for the required Instance for the Transition { { instanceName } } * )
{ { # each inputs } }
{ { name } } : { { type } } ; ( * Accessor for the Input { { name } } of { { fBName } } * )
{ { / e a c h } }
{ { # each outputs } }
{ { name } } : { { type } } ; ( * Accessor for the Output { { name } } of { { fBName } } * )
{ { / e a c h } }
{ { / e a c h } }
END_VAR
VAR_OUTPUT
bError : BOOL ;
hrErrorCode : HRESULT ;
END_VAR
] ] > < / Declaration >
< Implementation >
< ST > < ! [ CDATA [
// If the Programm runs the First time, and MQTT Should be used.
// Make shure the Client is using the correct Connection-Params
IF bEnableMQTT AND bFirstRun THEN
fbMqttClient . sHostName : = sHostName ;
fbMqttClient . nHostPort : = nHostPort ;
fbMqttClient . sTopicPrefix : = '' ;
fbMqttClient . nKeepAlive : = 60 ;
fbMqttClient . ipMessageQueue : = fbMessageQueue ;
END_IF
// Enable the MQTT Connection
IF bEnableMQTT THEN
fbMqttClient . Execute ( bEnableMQTT ) ;
handle_mqtt_messages ( iDeltaTime ) ;
IF fbMqttClient . bError THEN
// add your error logging here
hrErrorCode : = fbMqttClient . hrErrorCode ;
END_IF
// If MQTT is connected Subscribe to the Topics
IF fbMqttClient . bConnected THEN
// Subscribe to Messages
IF NOT bSubscribedRelease THEN
bSubscribedRelease : = fbMqttClient . Subscribe ( sTopic : = sMQTTTopicRelease , eQoS : = TcIotMqttQos . AtMostOnceDelivery ) ;
END_IF
IF NOT bSubscribedRelease THEN
bSubscribedRelease : = fbMqttClient . Subscribe ( sTopic : = sMQTTTopicLock , eQoS : = TcIotMqttQos . AtMostOnceDelivery ) ;
END_IF
IF NOT bSubscribedRelease THEN
bSubscribedRelease : = fbMqttClient . Subscribe ( sTopic : = sMQTTTopicTrigger , eQoS : = TcIotMqttQos . AtMostOnceDelivery ) ;
END_IF
// Test if the Timer is elapsed
IF fbTONUpdateStates . Q THEN
// Reset Timer
fbTONUpdateStates ( IN : = FALSE , PT : = T # 1000 MS ) ;
// Create the JSON Document
fbJson . ResetDocument ( ) ;
fbJson . StartObject ( ) ;
fbJsonDataType . AddJsonKeyValueFromSymbol ( fbJson , 'marking' , 'STATES_DUT' , SIZEOF ( aTokens ) , ADR ( aTokens ) ) ;
fbJson . EndObject ( ) ;
// Parse the Object => Returns the Length
iStateLength : = fbJson . CopyDocument ( sState , SIZEOF ( sState ) ) ;
// Publish the State
IF iStateLength > 0 THEN
fbMqttClient . Publish ( 'plc-0003/logic' , ADR ( sState ) , iStateLength , 1 , FALSE , FALSE ) ;
END_IF
ELSE
// Call the Timer
fbTONUpdateStates ( IN : = TRUE , PT : = T # 1000 MS ) ;
END_IF
END_IF
END_IF
// Determine if the Logic is allowed to execute
IF bEnableMQTT AND bEnableLogic THEN
// Only allow the Logic to go one, if the MQTT-Client is connected
bLogicEnabled : = fbMqttClient . bConnected ;
ELSE
// MQTT is disabled => Use the Enable Flag.
bLogicEnabled : = bEnableLogic ;
END_IF
// The Main Loop. This Loop contains the compiled Petri-Net
IF bLogicEnabled THEN
// Update the Inputs
read_inputs ( ) ;
// Get the Current Time
fbTime ( timeLoDW = > iTimeLoPart , timeHiDW = > iTimeHiPart ) ;
// Convert The Time to an LWORD Value.
iTimeLo64 : = UDINT_TO_LWORD ( iTimeLoPart ) ;
iTimeHi64 : = UDINT_TO_LWORD ( iTimeHiPart ) ;
// Assemble the current Time. (Shift the Higher one by 2**32)
iCurrentTime : = ( iTimeHi64 * 4294967296 + iTimeLo64 ) ;
// The Resolution is 1 ms (Originally 100ns => Resolution)
iCurrentTime : = iCurrentTime / ( 1000 * 1000 / 100 ) ;
// If the Programm runs the First time or the Logic should be
// resetted => Reset the Tokens of the Petri-Net.
IF bFirstRun OR bResetLogic THEN
// Resetting the State of the Petri-Net
reset_tokens ( ) ;
// Turn Off logic Reset.
bResetLogic : = FALSE ;
bFirstRun : = FALSE ;
// During the First Run Assing the Start-Time
iStartTime : = iCurrentTime ;
// Upadte the Time-Parameters.
reset_transtions ( ) ;
END_IF
// Determine the Delta of the time.
iDeltaTime : = iCurrentTime - iStartTime ;
// Flag, indicating whether the System should test for other Transitions or not.
bRunTestLoop : = TRUE ;
// Reset the Iteration iIterationCounter
iIterationCounter : = 0 ;
WHILE bRunTestLoop AND iIterationCounter < { { options . maxIterations } } DO
// Mark the Loop as tested.
bRunTestLoop : = FALSE ;
// Update and Call the Instances
updateInstances ( ) ;
callInstances ( ) ;
// Rise the Iteration Counter.
iIterationCounter : = iIterationCounter + 1 ;
{ { # each transitionsSortedByPriority } }
{ { # if isFirst } } IF { { / i f } } { { # u n l e s s i s F i r s t } } E L S I F { { / u n l e s s } } { { m e t h o d N a m e } } ( 0 , F A L S E , i D e l t a T i m e ) T H E N
// Transition "{{{label}}}" fired!
bRunTestLoop : = TRUE ;
{ { # if isLast } }
END_IF
{ { / i f } }
{ { / e a c h } }
END_WHILE
END_IF
] ] > < / ST >
< / Implementation >
{ { # each transitions } }
{ { > fbTransitionFunctionTemplate } }
{ { > fbTransitionAdaptTimesFunctionTemplate } }
{ { / e a c h } }
< Method Name = "updateInstances" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ METHOD updateInstances : BOOL ] ] > < / Declaration >
< Implementation >
< ST >
< ! [ CDATA [ { { # each instances } } // Call Signature for {{instanceName}} (related to {{transitionName}} and using {{fbName}})
{ { { callCode } } }
{ { / e a c h } } ] ] >
< / ST >
< / Implementation >
< / Method >
< Method Name = "callInstances" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ METHOD callInstances : BOOL ] ] > < / Declaration >
< Implementation >
< ST > < ! [ CDATA [ callInstances : = TRUE ; ] ] >
< / ST >
< / Implementation >
< / Method >
< Method Name = "reset_transtions" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ METHOD reset_transtions : BOOL ] ] > < / Declaration >
< Implementation >
< ST > < ! [ CDATA [ // Function to Reset the Times of the Net.
reset_transtions : = TRUE ;
{ { # each transitions } }
// Set the Initial Static Parameters for Transition {{id}}
// Time is provided in [ms]. Add Additional {{options.additionalDelay}} ms. This will be based on the Implementation
aTransitions . { { id } } . iMaxTime : = { { # if useMaxTime } } { { maxTime } } + { { options . additionalDelay } } { { else } } 0 { { / i f } } ;
aTransitions . { { id } } . iMinTime : = { { minTime } } ;
// aTransitions.{{id}}.bUseMaxTime:= {{#if useMaxTime}}TRUE{{else}}FALSE{{/if}};
aTransitions . { { id } } . bUseMaxTime : = FALSE ;
// Test if Transition {{id}} is enabled and adapt the dynamic Times-Parameters used in the Logic.
{ { methodName } } _ADAPT_TIMES ( 0 ) ;
{ { / e a c h } }
] ] >
< / ST >
< / Implementation >
< / Method >
< Method Name = "reset_tokens" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ METHOD reset_tokens : BOOL ] ] > < / Declaration >
< Implementation >
< ST > < ! [ CDATA [ // Function to Reset the Tokens of the Net.
reset_tokens : = TRUE ;
{ { # each places } }
aTokens . { { id } } : = { { tokens . length } } ;
{ { / e a c h } } ] ] >
< / ST >
< / Implementation >
< / Method >
< Method Name = "read_inputs" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ METHOD read_inputs : BOOL ] ] > < / Declaration >
< Implementation >
< ST > < ! [ CDATA [ // Function to Update the Variables Used in the Logic.
read_inputs : = TRUE ;
{ { # each subscribedVariables } }
{ { adaptedName } } : = { { # getAccessorOfGuardVariable this } } { { / g e t A c c e s s o r O f G u a r d V a r i a b l e } } ;
{ { / e a c h } }
] ] >
< / ST >
< / Implementation >
< / Method >
< Method Name = "handle_mqtt_messages" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ METHOD handle_mqtt_messages : BOOL
VAR_INPUT
iCurrentTime : LWORD ; ( * Current Time Pointer * )
END_VAR ] ] > < / Declaration >
< Implementation >
< ST > < ! [ CDATA [ // Function to Update the Variables Used in the Logic.
handle_mqtt_messages : = TRUE ;
// If MQTT is connected Subscribe to the Topics
IF fbMessageQueue . nQueuedMessages > 0 THEN
IF fbMessageQueue . Dequeue ( fbMessage : = fbMessage ) THEN
// Assign the Message handling based on the Topic:
fbMessage . GetTopic ( pTopic : = ADR ( sTopicRcv ) , nTopicSize : = SIZEOF ( sTopicRcv ) ) ;
sPayloadRcv : = '' ;
fbMessage . GetPayload ( pPayload : = ADR ( sPayloadRcv ) , nPayloadSize : = SIZEOF ( sPayloadRcv ) , bSetNullTermination : = TRUE ) ;
IF sTopicRcv = sMQTTTopicRelease THEN
{ { # each actions } }
{ { # if isFirst } } IF { { / i f } } { { # u n l e s s i s F i r s t } } E L S I F { { / u n l e s s } } b E n a b l e L o g i c A N D s P a y l o a d R c v = ' " { { i d } } " ' T H E N
// Release the Transition {{label}}
aTransitions . { { id } } . bRelease : = TRUE ;
{ { # if isLast } }
END_IF
{ { / i f } } { { / e a c h } }
ELSIF sTopicRcv = sMQTTTopicLocK THEN
{ { # each actions } }
{ { # if isFirst } } IF { { / i f } } { { # u n l e s s i s F i r s t } } E L S I F { { / u n l e s s } } b E n a b l e L o g i c A N D s P a y l o a d R c v = ' " { { i d } } " ' T H E N
// Lock the Transition {{label}}
aTransitions . { { id } } . bRelease : = FALSE ;
{ { # if isLast } }
END_IF
{ { / i f } } { { / e a c h } }
ELSIF sTopicRcv = sMQTTTopicTrigger THEN
{ { # each actions } }
{ { # if isFirst } } IF { { / i f } } { { # u n l e s s i s F i r s t } } E L S I F { { / u n l e s s } } b E n a b l e L o g i c A N D s P a y l o a d R c v = ' " { { i d } } " ' T H E N
// Trigger Transition {{label}}
{ { methodName } } ( 0 , FALSE , iCurrentTime ) ;
{ { # if isLast } }
END_IF
{ { / i f } } { { / e a c h } }
END_IF
END_IF
END_IF
] ] >
< / ST >
< / Implementation >
< / Method >
< / POU >
< / TcPlcObject > ` ,
plcProject : ` <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
< PropertyGroup >
< FileVersion > 1.0 . 0.0 < / FileVersion >
< SchemaVersion > 2.0 < / SchemaVersion >
< ProjectGuid > { d052bc74 - 6748 - 44 e9 - ab97 - c76a5465eacb } < / ProjectGuid >
< SubObjectsSortedByName > True < / SubObjectsSortedByName >
< DownloadApplicationInfo > true < / DownloadApplicationInfo >
< WriteProductVersion > true < / WriteProductVersion >
< GenerateTpy > false < / GenerateTpy >
< Name > Testcode < / Name >
< ProgramVersion > 3.1 . 4023.0 < / ProgramVersion >
< Application > { bbff2287 - a113 - 4 d28 - 8 f6d - efcabdf5d264 } < / Application >
< TypeSystem > { b24aea9d - 6 e67 - 48 f8 - a831 - 3 bc6f2342ea4 } < / TypeSystem >
< Implicit_Task_Info > { da805644 - 4748 - 448 f - b5b2 - 6 ca842e9030d } < / Implicit_Task_Info >
< Implicit_KindOfTask > { 56 ede67f - e61e - 4 c59 - 92 de - 6 e963a28d9bb } < / Implicit_KindOfTask >
< Implicit_Jitter_Distribution > { cd90ab99 - 2020 - 4094 - a370 - afc280347629 } < / Implicit_Jitter_Distribution >
< LibraryReferences > { 114 fa4ae - 03 f9 - 4200 - addb - a4bf60a385a9 } < / LibraryReferences >
< / PropertyGroup >
< ItemGroup >
{ { # each codeFiles } }
< Compile Include = "{{path}}" >
< SubType > Code < / SubType >
< / Compile >
{ { / e a c h } }
< / ItemGroup >
< ItemGroup >
< Folder Include = "DUTs" / >
< Folder Include = "GVLs" / >
< Folder Include = "VISUs" / >
< Folder Include = "POUs" / >
< / ItemGroup >
< ItemGroup >
< PlaceholderReference Include = "Tc2_Standard" >
< DefaultResolution > Tc2_Standard , * ( Beckhoff Automation GmbH ) < / DefaultResolution >
< Namespace > Tc2_Standard < / Namespace >
< / PlaceholderReference >
< PlaceholderReference Include = "Tc2_System" >
< DefaultResolution > Tc2_System , * ( Beckhoff Automation GmbH ) < / DefaultResolution >
< Namespace > Tc2_System < / Namespace >
< / PlaceholderReference >
< PlaceholderReference Include = "Tc2_Utilities" >
< DefaultResolution > Tc2_Utilities , * ( Beckhoff Automation GmbH ) < / DefaultResolution >
< Namespace > Tc2_Utilities < / Namespace >
< / PlaceholderReference >
< PlaceholderReference Include = "Tc3_IotBase" >
< DefaultResolution > Tc3_IotBase , * ( Beckhoff Automation GmbH ) < / DefaultResolution >
< Namespace > Tc3_IotBase < / Namespace >
< / PlaceholderReference >
< PlaceholderReference Include = "Tc3_Module" >
< DefaultResolution > Tc3_Module , * ( Beckhoff Automation GmbH ) < / DefaultResolution >
< Namespace > Tc3_Module < / Namespace >
< / PlaceholderReference >
< / ItemGroup >
< ProjectExtensions >
< PlcProjectOptions >
< XmlArchive >
< Data >
< o xml : space = "preserve" t = "OptionKey" >
< v n = "Name" > "<ProjectRoot>" < / v >
< d n = "SubKeys" t = "Hashtable" ckt = "String" cvt = "OptionKey" >
< v > { 192 FAD59 - 8248 - 4824 - A8DE - 9177 C94C195A } < / v >
< o >
< v n = "Name" > "{192FAD59-8248-4824-A8DE-9177C94C195A}" < / v >
< d n = "SubKeys" t = "Hashtable" / >
< d n = "Values" t = "Hashtable" / >
< / o >
< v > { 8 F99A816 - E488 - 41 E4 - 9 FA3 - 846536012284 } < / v >
< o >
< v n = "Name" > "{8F99A816-E488-41E4-9FA3-846536012284}" < / v >
< d n = "SubKeys" t = "Hashtable" / >
< d n = "Values" t = "Hashtable" / >
< / o >
< v > { 40450 F57 - 0 AA3 - 4216 - 96 F3 - 5444 ECB29763 } < / v >
< o >
< v n = "Name" > "{40450F57-0AA3-4216-96F3-5444ECB29763}" < / v >
< d n = "SubKeys" t = "Hashtable" / >
< d n = "Values" t = "Hashtable" ckt = "String" cvt = "String" >
< v > ActiveVisuProfile < / v >
< v > IR0whWr8bwfwBwAAhiaVXgAAAABVAgAAWdTSaQAAAAABAAAAAAAAAAEaUwB5AHMAdABlAG0ALgBTAHQAcgBpAG4AZwACTHsAZgA5ADUAYgBiADQAMgA2AC0ANQA1ADIANAAtADQAYgA0ADUALQA5ADQAMAAwAC0AZgBiADAAZgAyAGUANwA3AGUANQAxAGIAfQADCE4AYQBtAGUABDBUAHcAaQBuAEMAQQBUACAAMwAuADEAIABCAHUAaQBsAGQAIAA0ADAAMgA0AC4AMAAFFlAAcgBvAGYAaQBsAGUARABhAHQAYQAGTHsAMQA2AGUANQA1AGIANgAwAC0ANwAwADQAMwAtADQAYQA2ADMALQBiADYANQBiAC0ANgAxADQANwAxADMAOAA3ADgAZAA0ADIAfQAHEkwAaQBiAHIAYQByAGkAZQBzAAhMewAzAGIAZgBkADUANAA1ADkALQBiADAANwBmAC0ANABkADYAZQAtAGEAZQAxAGEALQBhADgAMwAzADUANgBhADUANQAxADQAMgB9AAlMewA5AGMAOQA1ADgAOQA2ADgALQAyAGMAOAA1AC0ANAAxAGIAYgAtADgAOAA3ADEALQA4ADkANQBmAGYAMQBmAGUAZABlADEAYQB9AAoOVgBlAHIAcwBpAG8AbgALBmkAbgB0AAwKVQBzAGEAZwBlAA0KVABpAHQAbABlAA4aVgBpAHMAdQBFAGwAZQBtAE0AZQB0AGUAcgAPDkMAbwBtAHAAYQBuAHkAEAxTAHkAcwB0AGUAbQARElYAaQBzAHUARQBsAGUAbQBzABIwVgBpAHMAdQBFAGwAZQBtAHMAUwBwAGUAYwBpAGEAbABDAG8AbgB0AHIAbwBsAHMAEyhWAGkAcwB1AEUAbABlAG0AcwBXAGkAbgBDAG8AbgB0AHIAbwBsAHMAFCRWAGkAcwB1AEUAbABlAG0AVABlAHgAdABFAGQAaQB0AG8AcgAVIlYAaQBzAHUATgBhAHQAaQB2AGUAQwBvAG4AdAByAG8AbAAWFHYAaQBzAHUAaQBuAHAAdQB0AHMAFwxzAHkAcwB0AGUAbQAYGFYAaQBzAHUARQBsAGUAbQBCAGEAcwBlABkmRABlAHYAUABsAGEAYwBlAGgAbwBsAGQAZQByAHMAVQBzAGUAZAAaCGIAbwBvAGwAGyJQAGwAdQBnAGkAbgBDAG8AbgBzAHQAcgBhAGkAbgB0AHMAHEx7ADQAMwBkADUAMgBiAGMAZQAtADkANAAyAGMALQA0ADQAZAA3AC0AOQBlADkANAAtADEAYgBmAGQAZgAzADEAMABlADYAMwBjAH0AHRxBAHQATABlAGEAcwB0AFYAZQByAHMAaQBvAG4AHhRQAGwAdQBnAGkAbgBHAHUAaQBkAB8WUwB5AHMAdABlAG0ALgBHAHUAaQBkACBIYQBmAGMAZAA1ADQANAA2AC0ANAA5ADEANAAtADQAZgBlADcALQBiAGIANwA4AC0AOQBiAGYAZgBlAGIANwAwAGYAZAAxADcAIRRVAHAAZABhAHQAZQBJAG4AZgBvACJMewBiADAAMwAzADYANgBhADgALQBiADUAYwAwAC0ANABiADkAYQAtAGEAMAAwAGUALQBlAGIAOAA2ADAAMQAxADEAMAA0AGMAMwB9ACMOVQBwAGQAYQB0AGUAcwAkTHsAMQA4ADYAOABmAGYAYwA5AC0AZQA0AGYAYwAtADQANQAzADIALQBhAGMAMAA2AC0AMQBlADMAOQBiAGIANQA1ADcAYgA2ADkAfQAlTHsAYQA1AGIAZAA0ADgAYwAzAC0AMABkADEANwAtADQAMQBiADUALQBiADEANgA0AC0ANQBmAGMANgBhAGQAMgBiADkANgBiADcAfQAmFk8AYgBqAGUAYwB0AHMAVAB5AHAAZQAnVFUAcABkAGEAdABlAEwAYQBuAGcAdQBhAGcAZQBNAG8AZABlAGwARgBvAHIAQwBvAG4AdgBlAHIAdABpAGIAbABlAEwAaQBiAHIAYQByAGkAZQBzACgQTABpAGIAVABpAHQAbABlACkUTABpAGIAQwBvAG0AcABhAG4AeQAqHlUAcABkAGEAdABlAFAAcgBvAHYAaQBkAGUAcgBzACs4UwB5AHMAdABlAG0ALgBDAG8AbABsAGUAYwB0AGkAbwBuAHMALgBIAGEAcwBoAHQAYQBiAGwAZQAsEnYAaQBzAHUAZQBsAGUAbQBzAC1INgBjAGIAMQBjAGQAZQAxAC0AZAA1AGQAYwAtADQAYQAzAGIALQA5ADAANQA0AC0AMgAxAGYAYQA3ADUANgBhADMAZgBhADQALihJAG4AdABlAHIAZgBhAGMAZQBWAGUAcgBzAGkAbwBuAEkAbgBmAG8AL0x7AGMANgAxADEAZQA0ADAAMAAtADcAZgBiADkALQA0AGMAMwA1AC0AYgA5AGEAYwAtADQAZQAzADEANABiADUAOQA5ADYANAAzAH0AMBhNAGEAagBvAHIAVgBlAHIAcwBpAG8AbgAxGE0AaQBuAG8AcgBWAGUAcgBzAGkAbwBuADIMTABlAGcAYQBjAHkAMzBMAGEAbgBnAHUAYQBnAGUATQBvAGQAZQBsAFYAZQByAHMAaQBvAG4ASQBuAGYAbwA0MEwAbwBhAGQATABpAGIAcgBhAHIAaQBlAHMASQBuAHQAbwBQAHIAbwBqAGUAYwB0ADUaQwBvAG0AcABhAHQAaQBiAGkAbABpAHQAeQDQAAIaA9ADAS0E0AUGGgfQBwgaAUUHCQjQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtDtAPAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAFQAAANAMC60BAAAA0A0BLRHQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0S0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAUAAAA0AwLrQIAAADQDQEtE9APAS0Q0AAJGgRFCgsEAwAAAAUAAAANAAAAAAAAANAMC60CAAAA0A0BLRTQDwEtENAACRoERQoLBAMAAAAFAAAADQAAAAAAAADQDAutAgAAANANAS0V0A8BLRDQAAkaBEUKCwQDAAAABQAAAA0AAAAAAAAA0AwLrQIAAADQDQEtFtAPAS0X0AAJGgRFCgsEAwAAAAUAAAANAAAAFQAAANAMC60EAAAA0A0BLRjQDwEtENAZGq0BRRscAdAAHBoCRR0LBAMAAAAFAAAADQAAAAAAAADQHh8tINAhIhoCRSMkAtAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAAAAANADAS0n0CgBLRHQKQEtENAAJRoFRQoLBAMAAAADAAAAAAAAAAoAAADQJgutAQAAANADAS0n0CgBLRHQKQEtEJoqKwFFAAEC0AABLSzQAAEtF9AAHy0t0C4vGgPQMAutAQAAANAxC60XAAAA0DIarQDQMy8aA9AwC60CAAAA0DELrQMAAADQMhqtANA0Gq0A0DUarQA = < / v >
< / d >
< / o >
< / d >
< d n = "Values" t = "Hashtable" / >
< / o >
< / Data >
< TypeList >
< Type n = "Hashtable" > System . Collections . Hashtable < / Type >
< Type n = "OptionKey" > { 54 dd0eac - a6d8 - 46 f2 - 8 c27 - 2 f43c7e49861 } < / Type >
< Type n = "String" > System . String < / Type >
< / TypeList >
< / XmlArchive >
< / PlcProjectOptions >
< / ProjectExtensions >
< / Project >
` ,
plcTask : `
< ? xml version = "1.0" encoding = "utf-8" ? >
< TcPlcObject Version = "1.1.0.1" >
< Task Name = "PlcTask" Id = "{8b15b34f-602d-4143-a3e1-d8fe7e6a9a07}" >
<!-- CycleTime in micro seconds . -- >
< CycleTime > 10000 < / CycleTime >
< Priority > 20 < / Priority >
< PouCall >
< Name > { { nameOfMainFb } } < / Name >
< / PouCall >
< TaskFBGuid > { 40 b78878 - 0487 - 47 d4 - ba7d - 2 f596fd0f0fe } < / TaskFBGuid >
< Fb_init > { bf297dd4 - 78 e5 - 43 f2 - b98d - 3899 ae75bf54 } < / Fb_init >
< Fb_exit > { 9 e24ead9 - 19 c2 - 4 f25 - b930 - d7c9fbcaf678 } < / Fb_exit >
< CycleUpdate > { 94 c51f5d - cf3e - 4304 - 857 a - 330 e87fa21ab } < / CycleUpdate >
< PostCycleUpdate > { a9235a07 - fbb3 - 4457 - 81 e0 - 1 ff81b29917f } < / PostCycleUpdate >
< ObjectProperties / >
< / Task >
< / TcPlcObject >
` ,
gvlLogic : `
< ? xml version = "1.0" encoding = "utf-8" ? >
< TcPlcObject Version = "1.1.0.1" ProductVersion = "3.1.4024.2" >
< GVL Name = "GVL_Logic" Id = "{{#uuid}}{{/uuid}}" >
< Declaration > < ! [ CDATA [ { attribute 'qualified_only' }
VAR_GLOBAL
fbLogic01 : FB_MAIN ;
END_VAR ] ] > < / Declaration >
< / GVL >
< / TcPlcObject > `
} ;