Label - Expression to conditionally format Hex value

I am extracting the PLC time. It is stored in registers where the 16 bit register represents 2 BCD numbers. In the example here it is for Day_Hour.
Problem is when the day or hour is less than 10decimal, Ignition only shows 1 digit. So Day of month = 07 returns 7, and not 07.
I am trying to have the Label show two digits for BCD regardless of what the value is. So regardless of the day, it will show 07, or 12, or 31 etc.
How can I do this in the expression for the Label or should I do this somewhere else?
In the attached screen shot, it shows how what I am currently doing in the expression is not working because all I’m getting back from the ‘toHex’ funcion is 707, whereas I need to display 07 07 (7th day and the 7th hour)


left(toHex({KasaTMMC/Final4/F4-TL/P1_S001A}),2) + " : " + right(toHex({KasaTMMC/Final4/F4-TL/P1_S001A}),2)



Hex datetime

This expression will do the trick:

stringFormat('%02X:%02X',
    ({KasaTMMC/Final4/F4-TL/P1_S001A} >> 8), 
    ({KasaTMMC/Final4/F4-TL/P1_S001A} & 255)
)

An explanation of how this works.

  1. The stringFormat expression accepts format strings which utilizes the Java String Format Syntax, found here. Esentially, this string is saying it will take 2 arguments and format them both as a Hexadecimal Integer with zero padding to a width of 2 characters.

  2. This: {tag} >> 8 performs a right bit shift to the value of tag 8 bits to the right. It helps to think of the numbers in binary. In this instance the binary value would be 0b0000 0111 0000 0111, following the bit shift the resultant value is 0b0000 0000 0000 0111.

  3. This: {tag} & 255 performs a bitwise AND operation between the value of tag and 255. Again it helps to think of the numbers in binary. In this instance:
    0b0000 0111 0000 0111 & 0b0000 0000 1111 1111 = 0b0000 0000 0000 0111

The resultant string will be 07:07

4 Likes

That did it, and thank you for the wonderful explanation!

I’m sorry but, why hex ?
If all you want is to pad the numbers with 0s, hex has nothing do to with it.

I’ve never used BCD (why does this even still exist ?) with ignition so I have no idea how the values are interpreted, if it’s built-in or if you need to interpret them yourself, but I’d probably try to convert your Min_Sec and Day_Hour into a datetime object, then use this with whatever date formatting you may need.
Using expressions, you’d be looking at getDate() and setTime(), maybe something like

setTime(getDate(0, 0, {Day_Hour} >> 8), {Day_Hour} & 0xff, {Min_Sec} >> 8, {Min_Sec} & 0xff)

If you don’t want to create a datetime object because you only ever need to display dd hh:mm:ss, then take @lrose’s expression. But I still don’t see the point of using hex conversion.

edit:
Wait, no, this is wrong. I forgot it was BCD, simply shifting 8 to the right won’t do the trick, as the 2 ‘nibbles’ (a nibble being half a byte) will be interpreted as an 8 bit integer.
Let me think about it and come back with a better solution.

re edit: Can you try lrose’s expression with numbers higher than 9 ? I’m expecting 07 to work fine because the 0 nibble is still 0, and 7 is still 7. But 11 (0001 0001) would be interpreted as 17, 12 as 18, etc…

re re edit: converting 4 BCD numbers encode into 16 bits to two 8 bits integers would look something like

left_byte = bcd >> 8
first_number = (left_byte >> 4) * 10 + (left_byte & 0x0F)

right_byte = bcd & 0xFF
second_number = (right_byte >> 4) * 10 + (right_byte & 0x0F)

Doing it with an expression would look quite ugly I think, so I’d make a function for this.
Then I still believe that using those to create a datetime object is not a bad idea.

It's a Japanese plc system and this is how they handle their time clocks. It is actually HEX, but we just 'view' the number displayed in the programming software, or on the HMI as a BCD number. I guess the word BCD shouldn't be used, it's just that through the plc software, these clock registers will never see a value beyond that what you would see in a 'BCD' clock.
My bad, I should have explained this a bit better.

As of 07:29AM this morning, the solution works (I applied it to the minutes_seconds plc registers as well.

image

So you’re getting two 8 bits integers at a time, encoded into a 16 bits value, from the plc ?

They are 2 x 8 bit integers yes, but from an interpretation stand point, they are to be viewed on any system, as HEX (but I think of these particular ones as BCD since I am old school and they are representing clock values)
image

Yes.

BCD is very wasteful because each nibble can only be 0-9.

However, just using the integer value won’t work because, in the PLC it is stored directly as HEX.

So for instance in the PLC a value might be stored as 0x2920 that value in Ignition would be 10528. As you can see not as readable.

I agree if you were going to try and store this value for use elsewhere in the view/application then it makes since to store it as a date/time. However if you only want to display it as a string no use converting it to a date just to convert it back to a string.

3 Likes

Ooooh so you mean 29 mins and 20 seconds is stored as 0x2920 ? That would make it actual BCD, and everything makes sense !

3 Likes

Omron, in particular, is fond of BCD.

2 Likes

Allen-Bradley PLC-2 used BCD, by default if I recall, although I think you could also use decimal.
ControlLogix still has TOD and FRD instructions to convert to/from BCD.

2 Likes