How to validate user input versus a named set

There are several places in our process phases where a user is prompted for string input, and that input needs to match an entry in a named set. In one case, there are over 40 possible legitimate responses, so a drop-down is not practical. So far, we've been doing essentially:

'^/NAMED_SET.CVS' := '^/USER_RESPONSE_STRING.CV';

and then verify the CVI isn't zero. While this does weed out any string input that isn't in the list, we recently discovered that entering an integer is silently accepted! Looks like, despite assigning to the .CVS component of the named set, a string made up of integer characters (like "44") is silently converted to an integer data type and assigned, even if that integer doesn't have an entry in the named set.

What is a good way of weeding out integer input (which will always be invalid, as named sets can't contain integer-character names)?

  • For reference, here's a few things I tried:
    1. In an Action block, assigning the user input to an integer and checking for BLOCK_ERR (no error would mean they entered an integer, right?) No error was generated for strings or integers.
    2. In an Action block, assigning 1+[the user input] to an integer and then doing if (result >= 2) then... (if >2 should mean it's an integer, so reject it). Strangely, it follows the ELSE side of that statement as if it was a string, even when an integer is given.
    3. After assigning the user input to the named set, assign the named set's string to a temporary string variable, then compare that variable to the original prompt response. SHOULD have failed (if entry #44="abcde" and the user entered "44", should say "44" != "abcde") - nope, the temporary string was assigned "44". (That might be an optimizing compiler mistake.)
  • In reply to Andy Hairston:

    Are you using Operate or Live?

    You are making selection from graphic? You can build the combobox to only have the valid selections from the NS parameter by reading the NAME_SET.OPSEL which will be a comma delimited string of all the NS User Selectable choices.
  • In reply to Matt Stoner:

    As mentioned in the original post, there are over 40 valid selections; a combobox would not be practical.
  • In reply to Andy Hairston:

    The controller can't do any string comparisons or manipulations so you will have to do all that verification at the graphic scripting before writing the value to check the entered text is a valid selection.
  • In reply to Matt Stoner:

    As we're using DeltaV Live prompts (phase request 3501), there is no scripting; DeltaV itself sets PROMPT_STRING to whatever the operator typed.

    There's really no way of, for example, seeing if NAMED_SET.CVS is equal to USER_RESPONSE_STRING.CV? Just checking them with = seems to have the integer-version of USER_RESPONSE be compared to the integer-version of NAMED_SET, even though NAMED_SET is specified with .CVS and USER_RESPONSE has to be cast to an integer. Preventing that cast would be ideal.
  • In reply to Andy Hairston:

    Controller has very very limit string manipulation ability (more just combining) and no Upper case, Lower case type functions. You will have to engineer a solution where the prompt tells them to go select something on the screen and then you do the entry this way so the graphics can check if the entered selection is in the OPSEL (Operate) and Live can do more as it can interrogate the NS configuration more than operate but reading the OPSEL comma delimited and verify that entered text is in there would keep it simple. After they ack the prompt you can check that they entered a value to move forward. Hopefully all the entries of the NS are all Uppercase and this would simplify some of the user entry issues by doing a UserEntry.toUpperCase() in case they entered all lowercase.

    Lots of people have been asking (for a long time too) for the selection type prompt for phases but it is still not on the radar...
  • In reply to Matt Stoner:

    Instead of comparing NAMED_SET.CVI not equal to zero, could you compare NAMED_SET.CVS to a null string? (Null means not valid)
  • In reply to Matt Stoner:

    I managed to do this entirely in the phase, without having to have something on the graphics do the checking.
    1. Set the named set variable (let's call it NAMED_SET) to 0 (NONE). Prompt the user for the named set entry. Copy the prompt string to a phase variable (let's call it RESPONSE).
    2. Have the transitions from that step be the "good" result (RESPONSE = "NONE" and NAMED_SET != NONE and NAMED_SET != UNKNOWN), and the "bad" result (NAMED_SET = UNKNOWN). (NONE=0, UNKNOWN=255), with the "bad" result causing the step to repeat.
    3. On the failure monitor, have an action block that copies the phase variable to the named set, and also copies it to a temporary string, appending an extra character ('^/TEMPSTRING.CV := "x" + '^/RESPONSE.CV';)
    4. Have a condition block checking for BLOCK_ERR on the first action block - if there is one, it's because the user entered something that doesn't match the named set. This triggers an action block to set NAMED_SET := 255 (UNKNOWN) and RESPONSE := "NONE". (Which triggers the prompt step to repeat.)
    5. Have another action block:
    IF (RESPONSE != "NONE") and (NAMED_SET != "NONE") THEN
    IF (TEMPSTRING != ("x" + NAMED_SET.CVS)) THEN /* Assigned the named set value, but its string doesn't match what the operator typed, so it must have been an integer. Reject it. */
    NAMED_SET := 255 (UNKNOWN);
    ENDIF;
    RESPONSE := "NONE";
    ENDIF;

    Note: These **MUST** be separate actions; it looks like there's some kind of optimizing compiler that effectively negates the check if they're combined. (Ex. If you do NAMED_SET := RESPONSE; TEMPSTRING := NAMED_SET.CVS, then enter a string that isn't in the named set, you can end up with TEMPSTRING being the string that was entered even though it isn't valid in the named set!)

    Thus:
    1. If they entered a string that isn't in the named set, the first action block has an error, so the condition block's action block causes the prompt step to repeat.
    2. If they entered an integer, the third action block will detect that what they typed isn't the same as the named set's string, so it causes the prompt step to repeat.
    3. If they entered a valid string, the named set will stay as a known value and the response will be set to NONE, allowing the phase to proceed.

    I've thoroughly tested this myself, and had someone else try what they could think of - it seems to work perfectly. If you can spot any holes in it, please let me know.