685 lines
29 KiB
TypeScript
685 lines
29 KiB
TypeScript
/**
|
|
* @author Martin Karkowski
|
|
* @email m.karkowski@zema.de
|
|
* @create date 2020-07-16 10:52:32
|
|
* @modify date 2020-11-25 07:37:04
|
|
* @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}} *)
|
|
{{/each}}
|
|
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}} *)
|
|
{{/each}}
|
|
END_STRUCT
|
|
END_TYPE
|
|
]]></Declaration>
|
|
</DUT>
|
|
</TcPlcObject>`,
|
|
|
|
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",
|
|
|
|
// 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
|
|
// }
|
|
fbTransitionFunctionTemplate: "" + `<Method Name="{{methodName}}" Id="{{#uuid}}{{/uuid}}">
|
|
<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}}{{/timeAdaption}}
|
|
{{/each}}
|
|
{{/if}}
|
|
|
|
{{#if hasOutputs}}
|
|
// Adding Tokens to the Post-Places.
|
|
{{> addTokens}}
|
|
{{#each produced}}
|
|
{{#timeAdaption this.placeId}}{{/timeAdaption}}
|
|
{{/each}}
|
|
{{/if}}
|
|
|
|
{{#if functionName}}
|
|
// Execute the desired Function
|
|
{{#getFunctionTriggerCode this}}{{/getFunctionTriggerCode}}
|
|
{{/if}}
|
|
|
|
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;
|
|
{{/if}}
|
|
|
|
// Mark the Transition as Triggered
|
|
bTempTriggered := TRUE;
|
|
|
|
{{#if hasTriggers}}
|
|
// Prepare Triggering Elements.
|
|
iTempRecursionCounter := iRecursionCounter + 1;
|
|
|
|
{{#each triggered}}
|
|
// Trigger Transition {{{label}}}
|
|
{{methodName}}(iTempRecursionCounter, TRUE, iCurrentTime);
|
|
{{/each}}
|
|
{{/if}}
|
|
|
|
{{#if hasReleases}}
|
|
{{#each releases}}
|
|
// Set a Release to Transition {{{label}}}
|
|
aTransitions.{{this}}.bRelease := TRUE;
|
|
{{/each}}
|
|
{{/if}}
|
|
|
|
{{#if hasLocks}}
|
|
{{#each locks}}
|
|
// Lock the Transition {{{label}}}
|
|
aTransitions.{{this}}.bRelease := FALSE;
|
|
{{/each}}
|
|
{{/if}}
|
|
END_IF
|
|
|
|
// Transmit the Result.
|
|
{{methodName}} := bTempTriggered;]]></ST>
|
|
</Implementation>
|
|
</Method>
|
|
`,
|
|
fbTransitionAdaptTimesFunctionTemplate: "" + `<Method Name="{{methodName}}_ADAPT_TIMES" Id="{{#uuid}}{{/uuid}}">
|
|
<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 *)
|
|
{{/each}}
|
|
{{! List all Subscribed Variables below}}
|
|
{{#each subscribedVariables}}
|
|
{{adaptedName}} : {{type}}; (* Accessor for Variable {{name}}. This Variable is used in the Logic *)
|
|
{{/each}}
|
|
|
|
// 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}} *)
|
|
{{/each}}
|
|
{{#each outputs}}
|
|
{{name}}: {{type}}; (* Accessor for the Output {{name}} of {{fBName}} *)
|
|
{{/each}}
|
|
{{/each}}
|
|
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#1000MS);
|
|
|
|
// 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#1000MS);
|
|
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{{/if}}{{#unless isFirst}}ELSIF{{/unless}} {{methodName}}(0, FALSE, iDeltaTime) THEN
|
|
// Transition "{{{label}}}" fired!
|
|
bRunTestLoop := TRUE;
|
|
{{#if isLast}}
|
|
END_IF
|
|
{{/if}}
|
|
{{/each}}
|
|
END_WHILE
|
|
END_IF
|
|
]]></ST>
|
|
</Implementation>
|
|
{{#each transitions}}
|
|
{{> fbTransitionFunctionTemplate}}
|
|
{{> fbTransitionAdaptTimesFunctionTemplate}}
|
|
{{/each}}
|
|
<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}}}
|
|
{{/each}}]]>
|
|
</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{{/if}};
|
|
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);
|
|
|
|
{{/each}}
|
|
]]>
|
|
</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}};
|
|
{{/each}}]]>
|
|
</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}}{{/getAccessorOfGuardVariable}};
|
|
{{/each}}
|
|
]]>
|
|
</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{{/if}}{{#unless isFirst}}ELSIF{{/unless}} bEnableLogic AND sPayloadRcv = '"{{id}}"' THEN
|
|
// Release the Transition {{label}}
|
|
aTransitions.{{id}}.bRelease := TRUE;
|
|
{{#if isLast}}
|
|
END_IF
|
|
{{/if}}{{/each}}
|
|
ELSIF sTopicRcv=sMQTTTopicLocK THEN
|
|
{{#each actions}}
|
|
{{#if isFirst}}IF{{/if}}{{#unless isFirst}}ELSIF{{/unless}} bEnableLogic AND sPayloadRcv = '"{{id}}"' THEN
|
|
// Lock the Transition {{label}}
|
|
aTransitions.{{id}}.bRelease := FALSE;
|
|
{{#if isLast}}
|
|
END_IF
|
|
{{/if}}{{/each}}
|
|
ELSIF sTopicRcv=sMQTTTopicTrigger THEN
|
|
{{#each actions}}
|
|
{{#if isFirst}}IF{{/if}}{{#unless isFirst}}ELSIF{{/unless}} bEnableLogic AND sPayloadRcv = '"{{id}}"' THEN
|
|
// Trigger Transition {{label}}
|
|
{{methodName}}(0, FALSE, iCurrentTime);
|
|
{{#if isLast}}
|
|
END_IF
|
|
{{/if}}{{/each}}
|
|
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-44e9-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-4d28-8f6d-efcabdf5d264}</Application>
|
|
<TypeSystem>{b24aea9d-6e67-48f8-a831-3bc6f2342ea4}</TypeSystem>
|
|
<Implicit_Task_Info>{da805644-4748-448f-b5b2-6ca842e9030d}</Implicit_Task_Info>
|
|
<Implicit_KindOfTask>{56ede67f-e61e-4c59-92de-6e963a28d9bb}</Implicit_KindOfTask>
|
|
<Implicit_Jitter_Distribution>{cd90ab99-2020-4094-a370-afc280347629}</Implicit_Jitter_Distribution>
|
|
<LibraryReferences>{114fa4ae-03f9-4200-addb-a4bf60a385a9}</LibraryReferences>
|
|
</PropertyGroup>
|
|
<ItemGroup>
|
|
{{#each codeFiles}}
|
|
<Compile Include="{{path}}">
|
|
<SubType>Code</SubType>
|
|
</Compile>
|
|
{{/each}}
|
|
</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>{192FAD59-8248-4824-A8DE-9177C94C195A}</v>
|
|
<o>
|
|
<v n="Name">"{192FAD59-8248-4824-A8DE-9177C94C195A}"</v>
|
|
<d n="SubKeys" t="Hashtable" />
|
|
<d n="Values" t="Hashtable" />
|
|
</o>
|
|
<v>{8F99A816-E488-41E4-9FA3-846536012284}</v>
|
|
<o>
|
|
<v n="Name">"{8F99A816-E488-41E4-9FA3-846536012284}"</v>
|
|
<d n="SubKeys" t="Hashtable" />
|
|
<d n="Values" t="Hashtable" />
|
|
</o>
|
|
<v>{40450F57-0AA3-4216-96F3-5444ECB29763}</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">{54dd0eac-a6d8-46f2-8c27-2f43c7e49861}</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>{40b78878-0487-47d4-ba7d-2f596fd0f0fe}</TaskFBGuid>
|
|
<Fb_init>{bf297dd4-78e5-43f2-b98d-3899ae75bf54}</Fb_init>
|
|
<Fb_exit>{9e24ead9-19c2-4f25-b930-d7c9fbcaf678}</Fb_exit>
|
|
<CycleUpdate>{94c51f5d-cf3e-4304-857a-330e87fa21ab}</CycleUpdate>
|
|
<PostCycleUpdate>{a9235a07-fbb3-4457-81e0-1ff81b29917f}</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>`
|
|
}; |