<?xml version="1.0" encoding="UTF-8"?>

<UserFunctionMgr>
   <UserFunction
       Expression="(*&#10;Computes the duration in seconds and nanoseconds that is the difference between the two timestamps. Return value is unused.&#13;&#10;*)&#10;&#10;FUNCTION TIME_DIFF : DINT&#10;&#9;VAR_INPUT&#10;&#9;&#9;T0_S&#9;&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;T0_NS&#9;&#9;&#9;&#9;: DINT;&#10;&#9;&#9;T1_S&#9;&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;T1_NS&#9;&#9;&#9;&#9;: DINT;&#10;&#9;END_VAR&#10;&#9;VAR_OUTPUT&#10;&#9;&#9;Duration_S&#9;&#9;: DINT;&#13;&#10;&#9;&#9;Duration_NS&#9;: DINT;&#10;&#9;END_VAR&#13;&#10;&#9;VAR&#13;&#10;&#9;&#9;Dur_S&#9;&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;Dur_NS&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;NSPerS&#9;&#9;&#9;: DINT := 1000000000;&#13;&#10;&#9;END_VAR&#13;&#10;&#13;&#10;&#9;(* Compute the simple difference *)&#10;&#9;Dur_S := T1_S - T0_S;&#13;&#10;&#9;Dur_NS := T1_NS - T0_NS;&#13;&#10;&#13;&#10;&#9;(* Handle signed/unsigned mismatch *)&#13;&#10;&#9;IF Dur_S &gt; 0 AND Dur_NS &lt; 0 THEN&#13;&#10;&#9;&#9;Dur_S := Dur_S - 1;&#13;&#10;&#9;&#9;Dur_NS := Dur_NS + NSPerS;&#13;&#10;&#9;ELSEIF Dur_S &lt; 0 AND Dur_NS &gt; 0 THEN&#13;&#10;&#9;&#9;Dur_S := Dur_S + 1;&#13;&#10;&#9;&#9;Dur_NS := Dur_NS - NSPerS;&#13;&#10;&#9;END_IF;&#10;&#13;&#10;&#9;(* Handle nanosecond overflow/underflow *)&#13;&#10;&#9;IF Dur_NS &gt;= NSPerS THEN&#13;&#10;&#9;&#9;Dur_S := Dur_S + 1;&#13;&#10;&#9;&#9;Dur_NS := Dur_NS - NSPerS;&#13;&#10;&#9;ELSEIF Dur_NS &lt;= -NSPerS THEN&#13;&#10;&#9;&#9;Dur_S := Dur_S - 1;&#13;&#10;&#9;&#9;Dur_NS := Dur_NS + NSPerS;&#13;&#10;&#9;END_IF;&#13;&#10;&#13;&#10;&#9;(* Store the output parameter values *)&#13;&#10;&#9;Duration_S := Dur_S;&#13;&#10;&#9;Duration_NS := Dur_NS;&#13;&#10;&#13;&#10;&#9;(* The return value is unused *)&#10;&#9;TIME_DIFF := 0;&#10;&#10;END_FUNCTION"/>
   <UserFunction
       Expression="(*&#10;Takes a duration in seconds and nanoseconds and returns the floating-point number of seconds.&#13;&#10;*)&#10;&#10;FUNCTION DURATION_SEC : REAL&#13;&#10;&#9;VAR_INPUT&#13;&#10;&#9;&#9;Dur_S&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;Dur_NS&#9;&#9;: DINT;&#13;&#10;&#9;END_VAR&#13;&#10;&#10;&#9;(* Merge seconds and nanoseconds to a REAL, which will lose some precision in the seconds fraction. *)&#13;&#10;&#9;DURATION_SEC := DINT_TO_REAL(Dur_S) + DINT_TO_REAL(Dur_NS) / 1000000000.0;&#10;&#10;END_FUNCTION"/>
   <UserFunction
       Expression="(*&#10;Returns the duration in seconds (REAL) that is the difference between the two timestamps.&#13;&#10;*)&#10;&#10;FUNCTION TIME_DIFF_SEC : REAL&#10;&#9;VAR_INPUT&#10;&#9;&#9;T0_S&#9;&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;T0_NS&#9;&#9;&#9;&#9;: DINT;&#10;&#9;&#9;T1_S&#9;&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;T1_NS&#9;&#9;&#9;&#9;: DINT;&#10;&#9;END_VAR&#10;&#9;VAR&#13;&#10;&#9;&#9;Dur_S&#9;&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;Dur_NS&#9;&#9;&#9;: DINT;&#13;&#10;&#9;END_VAR&#13;&#10;&#13;&#10;&#9;(* Compute the exact difference (duration) in seconds and nanoseconds *)&#13;&#10;&#9;TIME_DIFF(T0_S, T0_NS, T1_S, T1_NS, Dur_S, Dur_NS);&#13;&#10;&#13;&#10;&#9;(* Convert from seconds and nanoseconds to the number of seconds as a REAL with fraction *)&#10;&#9;TIME_DIFF_SEC := DINT_TO_REAL(Dur_S) + DINT_TO_REAL(Dur_NS) / 1000000000.0;&#10;&#10;END_FUNCTION"/>
   <UserFunction
       Expression="(*&#10;Returns the elapsed time in seconds (REAL) since the specified time (seconds and nanoseconds).&#13;&#10;*)&#10;&#10;FUNCTION TIME_ELAPSED_SEC : REAL&#13;&#10;&#9;VAR_INPUT&#13;&#10;&#9;&#9;T0_S&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;T0_NS&#9;&#9;&#9;: DINT;&#13;&#10;&#9;END_VAR&#13;&#10;&#13;&#10;&#9;(* Compute the elapsed time difference in seconds *)&#10;&#9;TIME_ELAPSED_SEC := TIME_DIFF_SEC(T0_S, T0_NS, _Controller.SysTime_sec, _Controller.SysTime_nsec);&#10;&#10;END_FUNCTION"/>
   <UserFunction
       Expression="(*&#10;Captures the current system time, both seconds and nanoseconds. Return value is unused.&#13;&#10;*)&#10;&#10;FUNCTION TIME_CAPTURE : DINT&#10;&#9;VAR_OUTPUT&#10;&#9;&#9;Time_S&#9;&#9;: DINT;&#13;&#10;&#9;&#9;Time_NS&#9;&#9;: DINT;&#10;&#9;END_VAR&#13;&#10;&#13;&#10;&#9;(* Capture the current system time in seconds and nanoseconds *)&#13;&#10;&#9;Time_S := _Controller.SysTime_sec;&#13;&#10;&#9;Time_NS := _Controller.SysTime_nsec;&#13;&#10;&#13;&#10;&#9;(* The return value is unused *)&#10;&#9;TIME_CAPTURE := 0;&#10;&#10;END_FUNCTION"/>
   <UserFunction
       Expression="(*&#10;Returns the duration in milliseconds (REAL) that is the difference between the two timestamps.&#13;&#10;*)&#10;&#10;FUNCTION TIME_DIFF_MSEC : REAL&#10;&#9;VAR_INPUT&#10;&#9;&#9;T0_S&#9;&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;T0_NS&#9;&#9;&#9;&#9;: DINT;&#10;&#9;&#9;T1_S&#9;&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;T1_NS&#9;&#9;&#9;&#9;: DINT;&#10;&#9;END_VAR&#10;&#9;VAR&#13;&#10;&#9;&#9;Dur_S&#9;&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;Dur_NS&#9;&#9;&#9;: DINT;&#13;&#10;&#9;END_VAR&#13;&#10;&#13;&#10;&#9;(* Compute the exact difference (duration) in seconds and nanoseconds *)&#13;&#10;&#9;TIME_DIFF(T0_S, T0_NS, T1_S, T1_NS, Dur_S, Dur_NS);&#13;&#10;&#13;&#10;&#9;(* Convert from seconds and nanoseconds to the number of milliseconds as a REAL with fraction without losing precision *)&#10;&#9;TIME_DIFF_MSEC := DINT_TO_REAL(Dur_S) * 1000.0&#13;&#10;&#9;&#9;+ DINT_TO_REAL(Dur_NS / 1000000)&#10;&#9;&#9;+ DINT_TO_REAL(Dur_NS MOD 1000000) / 1000000.0;&#13;&#10;&#10;END_FUNCTION"/>
   <UserFunction
       Expression="(*&#10;Returns the elapsed time in milliseconds (REAL) since the specified time (seconds and nanoseconds).&#13;&#10;*)&#10;&#10;FUNCTION TIME_ELAPSED_MSEC : REAL&#13;&#10;&#9;VAR_INPUT&#13;&#10;&#9;&#9;T0_S&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;T0_NS&#9;&#9;&#9;: DINT;&#13;&#10;&#9;END_VAR&#13;&#10;&#13;&#10;&#9;(* Compute the elapsed time difference in milliseconds *)&#10;&#9;TIME_ELAPSED_MSEC := TIME_DIFF_MSEC(T0_S, T0_NS, _Controller.SysTime_sec, _Controller.SysTime_nsec);&#10;&#10;END_FUNCTION"/>
   <UserFunction
       Expression="(*&#10;Takes a duration in seconds and nanoseconds and returns the floating-point number of milliseconds.&#13;&#10;*)&#10;&#10;FUNCTION DURATION_MSEC : REAL&#13;&#10;&#9;VAR_INPUT&#13;&#10;&#9;&#9;Dur_S&#9;&#9;&#9;: DINT;&#13;&#10;&#9;&#9;Dur_NS&#9;&#9;: DINT;&#13;&#10;&#9;END_VAR&#13;&#10;&#10;&#9;(* Treat seconds, milliseconds, and fractional milliseconds separately to preserve precision *)&#13;&#10;&#9;DURATION_MSEC := DINT_TO_REAL(Dur_S) * 1000.0&#13;&#10;&#9;&#9;+ DINT_TO_REAL(Dur_NS / 1000000)&#13;&#10;&#9;&#9;+ DINT_TO_REAL(Dur_NS MOD 1000000) / 1000000.0;&#13;&#10;&#10;END_FUNCTION"/>
</UserFunctionMgr>
