TIME_TO_STR: Error when using single CALC block. No error when code is split across two CALC blocks

I have the following code in a single CALC block:

'^/TIME.CV' := time_to_str("%h", time('$time_format:Local'));

IF '^/TIME.CV' < '^/STOP.CV' OR '^/TIME.CV' >= '^/START.CV' THEN
'^/PARAM1.CV' := "OK";
ELSE
'^/PARAM1.CV' := "NOT OK";
ENDIF;

The code basically checks if the time is within a range and sets a parameter based on this using the IF statement.

TIME, START and START are all 32 bit unsigned integers. The hour value is getting written to the TIME parameter but the block is showing an error and not executing the IF statement.

BUT

If I split the code across two CALC blocks as below:

CALC Block 1:

'^/TIME.CV' := time_to_str("%h", time('$time_format:Local'));

CALC Block 2:

IF '^/TIME.CV' < '^/STOP.CV' OR '^/TIME.CV' >= '^/START.CV' THEN
'^/PARAM1.CV' := "OK";
ELSE
'^/PARAM1.CV' := "NOT OK";
ENDIF;

the code works with no issues.

Any idea why this may be?

  • So, not more than 2 mins after I posted this I found a solution! :-D

    By putting the IF statement before the TIME statement in a single CALC block it works without issue. That said, I have no idea why this is the case. If anyone has any ideas I'd be happy to hear them!

    IF '^/TIME.CV' < '^/STOP.CV' OR '^/TIME.CV' >= '^/START.CV' THEN
    '^/PARAM1.CV' := "OK";
    ELSE
    '^/PARAM1.CV' := "NOT OK";
    ENDIF;

    '^/TIME.CV' := time_to_str("%h", time('$time_format:Local'));
  • In reply to Trevor Osborne:

    Trevor, when you write a value to a parameter inside the CALC block, the parameter is not updated until the expression completes. By placing the assign statement at the end, the TIME parameter is updated and then used on the next scan. Having the code in different Calc blocks also allows the first block to set parameter values that are then used in a second block.

    Using an internal parameter in the expression allows a value to be stored and used in the same scan of the expression. However, internal parameters are float numbers. You cannot set the type of parameter. In the case of low order integer, the float value is accurate and a number of 0 to 23 (1 to 24) would be accurately processed, especially in your greater than/Less then expressions.

    So if you added an internal variable of Time := time_to_str("%h", time('$time_format:Local')); and then IF statement using internal paramater of Time, that would work.

    In your expression that worked above, the IF statement evaluates the value of ^/TIME.CV on the next module execution after it changes.

    Another way would be to use the time_to_str function directly in the IF statement to have the expression resolve immediately. The Assign statement to ^/TIME.CV is simply to display this value in the module, or to use it else where.

    Andre Dicaire

  • In reply to Andre Dicaire:

    Fantastic, thanks Andre! Blush
  • In reply to Andre Dicaire:

    Andre, followup question:

    Based on what you said above, if the TIME parameter is updated at the end of the scan and then used on the next scan why does it matter if it's set at the start or end of the CALC block?

    Would it not execute as per the below?:

    Scan 1: The IF statement does not work as the TIME parameter does not yet have a value.
    Time value is set at the end of the first scan.

    Scan 2: TIME parameter has a value from scan 1 so IF statement can now execute.

    NOTE: TIME is an integer.

  • In reply to Trevor Osborne:

    In your example the TIME parameter will always have a value and the IF statement will run on the first scan using the configured default value of TIME parameter. After this execution it will be using what the value was the last time the logic was executed.

    Here is a quick test config I did to help show how execution of this works:

    • The TIME parameter is different than all the other values
    • OUT3 is always 0 on the execution but being set by TIME....Thinking
    • OUT1 is using the same TIME parameter and it is changing
    • TIME1 and OUT2 are always the same value and updated on the same scan.
    • This shows the values are getting written on the same execution of CALC with the exception of the OUT3 which is always 0.
    • Writes in the same controller are instantaneous (attempted that is - there are checks to insure that values can be written but "typically" they occur but there are some cases where writes are not allowed)
    • Only explanation I have for OUT3 being 0 is that the String Value being written to TIME hasn't been converted to a number yet and when trying to set OUT3 it can't convert the String value read to a Number
      • No Errors, No Abort on Errors on this test module
    • Based on your original configuration the String to Number conversion seems to be occurring after the CALC block where the String Value was written has executed.