Expression to convert multiple digital signals to string

Hello,

I have created a UDT which stores 6 boolean values. The values represent hand, off, auto commands and indications. That is - auto command, auto indication, hand command, hand indication, etc.

The UDT also contains a member tag which attempts to look at the 3 indication tags and convert these into a string. The problem is - I don't know how to combine the 3 values into a single value which the case statement can look at to determine the string value.

Here is what the UDT structure looks like:
image

Here was my first attempt at writing an expression to accomplish the above:

First Attempt
// Inspect digital signals and create string format
case(

	// Off bit is high, hand bit is low, auto bit is low (OFF)
	{[.]DIND_OFF}&&!{[.]DIND_HAND}&&!{[.]DIND_AUTO}, "Off",
	
	
	// Off bit is low, hand bit is high, auto bit is low (HAND)
	!{[.]DIND_OFF}&&{[.]DIND_HAND}&&!{[.]DIND_AUTO}, "Hand",
	
	
	// Off bit is low, hand bit is low, auto bit is high (AUTO)
	!{[.]DIND_OFF}&&{[.]DIND_HAND}&&!{[.]DIND_AUTO}, "Auto",
	
	// Default Return
	forceQuality("!BAD STATE!", 0)
)

I think one possible solution could be:

Possible Solution
// Inspect digital signals and create string format
case(
	// Value to inspect
	toInt(concat({[.]DIND_OFF}&&{[.]DIND_HAND}&&{[.]DIND_AUTO}), -1)
	
	// Off bit is high, hand bit is low, auto bit is low (OFF)
	4, "Off",
	
	
	// Off bit is low, hand bit is high, auto bit is low (HAND)
	2, "Hand",
	
	
	// Off bit is low, hand bit is low, auto bit is high (AUTO)
	1, "Auto",
	
	// Default Return
	forceQuality("!BAD STATE!", 0)
)

But quite frankly I think this solution is kind of ugly... is there any other solutions you have used in the past?

Thank you!

if(
  {[.]DIND_HAND},
  "Hand",
  if(
    {[.]DIND_AUTO},
    "Auto",
    if(
      {[.]DIND_OFF},
      "Off",
      forceQuality("!BAD STATE!", 0)
      )
    )
  )

I tend to use nested if statements for stuff like this. It's not the prettiest, but formatted correctly you can troubleshoot it more easily, imo.

1 Like

Thank you for the quick response.

I suppose I was overcomplicating it by going for the case statement. I can also maintain looking at all three tags using this solution, so thank you!

// Inspect digital signals and create string format
case(
    //      bit 0          bit 1           bit 2
    binEnc({[.]DIND_OFF}, {[.]DIND_HAND}, {[.]DIND_AUTO}),
    1, "Off",
    2, "Hand",
    4, "Auto",
    "Error"
)

See case | Ignition User Manual and binEnc | Ignition User Manual.

I haven't sorted out your forceQuality as I'm not sure what you're doing there.

5 Likes

An alternative to @Transistor's binEnc method.

case(
    binEnum({[.]DIND_OFF},[.]DIND_HAND},{[.]DIND_AUTO}),
    1, "Off",
    2, "Hand",
    3, "Auto",
    forceQuality("!BAD STATE!", 0)
)
3 Likes

Thank you Transistor. This is exactly what I was looking for.

I'm new to Ignition and have seen this forceQuality used in other expressions across some of our projects. I hadn't really questioned the use of it. It seemed sort of nice that the expression would return glaringly obvious issues across the displays when used on components.

Be careful with this expression. Is it possible that the HAND tag can be high when in AUTO?

If you are using this on a display, is it for vision or for perspective. Because, generally speaking you don't want to convert data to a string until the point of use, and there are other methods which are specific to those applications.

Also:

Kudos on a well thought out, properly formatted, and clear question.

5 Likes

Thank you Irose.

This is also a very clean method.

The one issue I have with this is that if you ever had an error where say the hand and auto bit were high, then you would never come across it.

It really should never be an issue and is a viable solution, but it was just one thing I noticed which may be a drawback.

Two tags should never be high at the same time, but I'd like to check for that case if it ever did arise.

Fair, I would definitely insure in the device that it is not possible for equipment to be in more than one state at a time.

1 Like

This is for a Vision project. What is the reasoning for not converting data to strings until the point of use? I figured it would be nice to convert inside of the UDT as then I could use it across the project all coming from the same source, but I'm happy to use the best method.

Note if you come across this in the future: there's a missing comma after the "hand".

The fixed solution is:

// Inspect digital signals and create string format
case(
    //      bit 0          bit 1           bit 2
    binEnc({[.]DIND_OFF}, {[.]DIND_HAND}, {[.]DIND_AUTO}),
    1, "Off",	// 001 (Binary representation)
    2, "Hand",	// 010
    4, "Auto",	// 100
    "Error"
)

I fixed the missing comma in post #3, thanks.

One advantage with the case syntax is that you can accommodate all eight permutations or the likely ones.

case(
    //      bit 0          bit 1           bit 2
    binEnc({[.]DIND_OFF}, {[.]DIND_HAND}, {[.]DIND_AUTO}),
    1, "Off",
    2, "Hand",
    4, "Auto",
    5, "Auto",  // Maybe should be "Off" depending on PLC logic.
    6, "Auto"   // Auto overrides "Hand".
    "Error"
)

Tailor this to suit. I'm not sure of your hand off auto logic.

1 Like

Because it is always better to work with numbers as numbers, dates as dates, etc... This is especially important with things like dates where the conversion can result in data loss.

Another, not insignificant reason when scaled out, is avoiding data duplication. You already have tags which indicate the state of the thing, they're just not necessarily human readable. That's okay though, because they can be converted at runtime and displayed to the operator without the added overhead of an additional tag. The more tags you have like this the larger the impact to performance because they all take up space in the internal db.

For vision, I would do something like this: Here, I have created a label with a custom integer property "state".

image

On that same label, I have added a Style Customizer configuration using the State custom property as the driving property and customizing the text, and the background color.

Then I configured an expression binding on the custom property, with just a simple binEnc() function. I'm using checkboxes to simulate your three tags. Here is the finial result, obviously you could tailor this to fit the actual needs of your process and logic.

animatedLabel

Just another option.

3 Likes