Red Lion DA30D, parsing binary string to (u)INT16/32/48, Float32, Bit16

When you use the way I showed the Manipulate drop down is available, it lets you reverse Bits, Bytes or Words
This.

Also, I am confusing this thread with another recent thread. I suspect the word swapping will not be necessary. Even if it was, and the Manipulate drop-down was not available, it could be done like this:
Code:
                        tmp  = PortRead(port, 0) << 16;
                        tmp |= PortRead(port, 0) << 24;
                        tmp |= PortRead(port, 0) << 0;
                        tmp |= PortRead(port, 0) << 8;

But @BryanG is right: put the bytes into an integer array, and use the Data Source options to create a "mapped" Data Tag; that is the Crimson equivalent of *(float*)(&intejer).
 
I decided to experiment, maybe I have too much time on my hands :)

Tag1 to Tag1_3 are Integers in Crimson, as is End Integer.
Then I used the method below:
// StartFloat = 6.189;
// used IEEE-754 Floating Point Converter
// to convert that to HEX Integers
Tag1 = 0x4A; // 01001010
Tag1_1 = 0x0C; // 00001100
Tag1_2 = 0xC6; // 11000110
Tag1_3 = 0x40; // 01000000

// Moved the HEX Integers in to EndInteger
EndInteger = (Tag1);
EndInteger |= (Tag1_1) << 8;
EndInteger |= (Tag1_2) << 16;
EndInteger |= (Tag1_3) << 24;

// And used the method a couple of posts above to use that as the source for EndFloat
// EndFloat = 6.189
 

Attachments

  • 6 189 converted to 32 bit.png
    6 189 converted to 32 bit.png
    22 KB · Views: 2
Hi guys,

Both @drbitboy's mathematical approach and @BryanG's translation method with two sets of data works - Good! Using the translation method, I do not need to set any Manipulation at all, I just set the raw tag as Integer and the "slave" tag as Floating point and it converts correct.

None of the above solutions is very elegant, could there be a better way out there?

Next question is how to get the binary bits decoded correctly... it is two bytes that should decode into 16 binary bits.

My current tag reading the Int16 displays 65, but should be presented as 0000000001000001 - Any ideas?

Thanks for all help, priceless :)
 
[...] @BryanG's translation method with two sets of data works - Good! Using the translation method, I do not need to set any Manipulation at all, I just set the raw tag as Integer and the "slave" tag as Floating point and it converts correct.

None of the above solutions is very elegant, could there be a better way out there?

I think @BryanG 's method extremely elegant i.e. zero code; it's functionally the same as **\*(float\*)(&intejer)**
 
My current tag reading the Int16 displays 65, but should be presented as 0000000001000001 - Any ideas?
You are reading it a byte at a time, correct?

Why not two arrays of 8-character strings:
Code:
bits[0] = '00000000';
bits[1] = '00000001';
bits[2] = '00000010';
bits[3] = '00000011';
bits[4] = '00000100';
...
bits[255] := '11111111';
And then

Code:
status = bits[PortRead(port, 0)];
status = bits[PortRead(port, 0)] + status;

Or however Crimson declares, assigns, and concatenates strings.
 
...
Next question is how to get the binary bits decoded correctly... it is two bytes that should decode into 16 binary bits.

My current tag reading the Int16 displays 65, but should be presented as 0000000001000001 - Any ideas?

Thanks for all help, priceless :)
You can set a Crimson integer numeric tag format to display the value as binary and even group the digits if you like.

On the tag Format tab, make sure the Format Type is Numeric, then under Fixed Data Format - Number Base: pick binary, set digits before DP to 16 and optionally set Group Digits to Yes. When you enable "Group Digits" on a Binary formatted numeric tag, there will be a space added between every 4 bits and I usually like it that way for most purposes.

Under the hood the bits are just bits, and nothing changes, there are just different ways of interpreting those bit patterns for display. Also, you can change the format of a tag at the tag level itself and it will propagate to every page object that references that tag unless the the format is overridden locally by unchecking the "Get from Tag: Format" tickbox where available on individual objects and setting a different format on that object.

So your value can be displayed multiple ways if needed.

All that is useful just for viewing the data.

If you want to use one of those bits in an expression, you can access them by referencing the tagname followed by a period and the bit number.

So lets say I have a folder called "Pump_1" and in it is an integer tag called "VFD_Status" and bit 3 is a warning I want to cause a block of text to appear on a display page. My indicator "Show" tag would be Pump_1.VFD_Status.3.

Maybe I want that bit to trigger an alarm. I can just create a new tag flag called Pump_1.VFD_Warn and assign its Source as the tag "VFD_Status.3" then set up the Alarms tab as needed.
 
Last edited:
Hi @OkiePC, thanks for this - I've implemented this and it seems like a great way to handle the Bits!

Unfortunately, another problem just appeared in the testing phase. It seems like RedLion decodes my 4 byte integers as signed but my 2 byte integers as unsigned?

I do have test data which looks like this:
INT32: 43 DE 67 FF >> -9970109
INT16: EB FF >> -21

The INT16 above does instead decode as 65515, which is true if treated as Unsigned Integer - But not what I want. How come the 4 byte integer is treated as signed but not the 2 byte?

To come arount this, I need to apply a check if the value is higher than the max of a Signed 2 byte integer, if so, substract the max of a Unsigned 2 byte integer to get the correct negative value, see below.

I'm sure you have a more elegant bit magic way of handling this? :)

C#:
// DECODING INT32
tmp  = PortRead(port, 0) << 0;
tmp |= PortRead(port, 0) << 8;
tmp |= PortRead(port, 0) << 16;
tmp |= PortRead(port, 0) << 24;
ROV_NAV.Lon = tmp*headingScale;

// DECODING INT16
tmp  = PortRead(port, 0) << 0;
tmp |= PortRead(port, 0) << 8;
if (tmp > 32767) {tmp = tmp - 65536;}
ROV_NAV.Pitch = tmp*pitchScale;
 
In additon, is it possible to make function in the Crimson scripting? I'd like to do some functions to read Int32, Int16 etc, to clean up the code a bit... I cant get the below or anything similar to work - Do you guys know?

C#:
void readInt16()
{
    tmp  = PortRead(port, 0) << 0;
    tmp |= PortRead(port, 0) << 8;
    if (tmp > 32767) {tmp = tmp - 65536;}
    return tmp;
}

ROV_NAV.Pitch = readInt16()*pitchScale;
 
In additon, is it possible to make function in the Crimson scripting? I'd like to do some functions to read Int32, Int16 etc, to clean up the code a bit... I cant get the below or anything similar to work - Do you guys know?
When you create a program there is a Prototype section at the top, edit that and you can send up to 6 Parameters and get back one result. A new program can be created which is essentially a Function which can be called by other Programs.
 
In additon, is it possible to make function in the Crimson scripting? I'd like to do some functions to read Int32, Int16 etc, to clean up the code a bit... I cant get the below or anything similar to work - Do you guys know?

C#:
int readInt16(portarg)
{
    int lcltmp;
    lcltmp  = PortRead(portarg, 0) << 0;
    lcltmp |= PortRead(portarg, 0) << 8;
    if (lcltmp > 32767) {lcltmp -= 65536;}
    return lcltmp;
}

ROV_NAV.Pitch = readInt16()*pitchScale;
Functions declared as a void types cannot return a value. We need to declare the function as an int data type; see above.

Also, the integer inside this function should probably have a function-local scope i.e. it should not depend on the tmp variable that has global scope, in order to make this routine self-contained (e.g. say this was a threaded process, with several execution threads executing in parallel and all working in the same memory; if two threads modify the same variable (memory) at the same time but for different purposes, it could get very messy). So in the code above I have declared the temporary int variable with the value to be returned within (i.e. with a scope local i.e. limited to) the function, and also given it different name just to make the point that it is different from the global int variable "tmp."

Finally, the port argument to PortRead should probably be passed to this function; I made that change as well.
 
Last edited:
Hi @OkiePC, thanks for this - I've implemented this and it seems like a great way to handle the Bits!

Unfortunately, another problem just appeared in the testing phase. It seems like RedLion decodes my 4 byte integers as signed but my 2 byte integers as unsigned?

I do have test data which looks like this:
INT32: 43 DE 67 FF >> -9970109
INT16: EB FF >> -21

The INT16 above does instead decode as 65515, which is true if treated as Unsigned Integer - But not what I want. How come the 4 byte integer is treated as signed but not the 2 byte?

To come arount this, I need to apply a check if the value is higher than the max of a Signed 2 byte integer, if so, substract the max of a Unsigned 2 byte integer to get the correct negative value, see below.

I'm sure you have a more elegant bit magic way of handling this? :)

C#:
// DECODING INT32
tmp  = PortRead(port, 0) << 0;
tmp |= PortRead(port, 0) << 8;
tmp |= PortRead(port, 0) << 16;
tmp |= PortRead(port, 0) << 24;
ROV_NAV.Lon = tmp*headingScale;

// DECODING INT16
tmp  = PortRead(port, 0) << 0;
tmp |= PortRead(port, 0) << 8;
if (tmp > 32767) {tmp = tmp - 65536;}
ROV_NAV.Pitch = tmp*pitchScale;

No, this is the right way to handle this using unsigned INT32s; the issue is that the left-shift (<<) operator shifts all of the bits, and since the PortRead(...) results are always less than 256, their high 24 bits are always 0, so the sign bit (bit 7) of the << 8-shifted PortRead(...) result ends up in bit 15 of the INT32, which is 16 bit positions short of the INT32 sign bit (bit 31).

If you could declare a signed INT16 variable named tmp16, and shift two PortRead(...) results into that, then the << 8 operation would shift bit 7 of the PortRead(...) result into the sign bit (bit 15) of the INT16.

Another solution would be this:
Code:
tmp = PortRead(port,0) << 16;
tmp |= PortRead(port,0) << 24;  /* Shift bit 7 of this second PortRead(...) to the INT32 sign bit */
tmp /= 65536;                   /* Use division by 0x10000 as a proxy for right-shift back 16 bits with sign extension */

but I don't know if you would consider that more elegant or more obfuscated.
 
When you create a program there is a Prototype section at the top, edit that and you can send up to 6 Parameters and get back one result. A new program can be created which is essentially a Function which can be called by other Programs.
That worked great, thanks, all tidy now :)
 
No, this is the right way to handle this using unsigned INT32s; the issue is that the left-shift (<<) operator shifts all of the bits, and since the PortRead(...) results are always less than 256, their high 24 bits are always 0, so the sign bit (bit 7) of the << 8-shifted PortRead(...) result ends up in bit 15 of the INT32, which is 16 bit positions short of the INT32 sign bit (bit 31).

If you could declare a signed INT16 variable named tmp16, and shift two PortRead(...) results into that, then the << 8 operation would shift bit 7 of the PortRead(...) result into the sign bit (bit 15) of the INT16.

Another solution would be this:
Code:
tmp = PortRead(port,0) << 16;
tmp |= PortRead(port,0) << 24;  /* Shift bit 7 of this second PortRead(...) to the INT32 sign bit */
tmp /= 65536;                   /* Use division by 0x10000 as a proxy for right-shift back 16 bits with sign extension */

but I don't know if you would consider that more elegant or more obfuscated.

Great, I think I'll go for the later version :)
 

Similar Topics

I need a CQM1H-CPU51 to talk to my Red lion Da30D i just need to read the status of some I/O and maybe read some data registers but I cannot...
Replies
7
Views
1,160
good morning all I have several red lion da30d using crimson 3.0 on the controls network in the plant. I am thinking about getting the AB power...
Replies
3
Views
2,168
We have two Red Lion DA30D units that keep dropping off the network. They are configured as 10.4.7.1 and 10.4.7.2 they work for so long then just...
Replies
24
Views
12,454
While they came up quickly with a fix for the alarm date issue quickly I will have to drive around for a week or so, burning up a lot of fuel...
Replies
4
Views
267
From the Red Lion website, after some customer enquiries in the last week or so... Rev. March 25, 2024 [18:30] Just thought it might help a...
Replies
9
Views
279
Back
Top Bottom