Red Lion Crimson 3.1 complex expressions

Wootts

Member
Join Date
Oct 2017
Location
Manitoba
Posts
13
Hello all,
I am fairly new to programming HMI's and am working with Crimson 3.1 for the first time. I am trying to recreate an annunciator of general messages for the HMI. Currently I have half the screen displaying active alarms (ie Stop faults and failures) by using the 'alarm viewer' primitive and the lower half of the screen I have a data box that I want to display general messages.


I have single bits that I have tied to flags in crimson and I need those to generate messages in my data box. I am able to use an 'if' statement to 'return' my desired message. But my program will only display one message at a time. I can not seem to find a way to display multiple messages at once. I have some 40 bits coming from the PLC that I would like to be able to annunciate.


Any ideas on how I can accomplish this?
 
So if a bit is true, you want the display to show its associated text, and if the bit is false, it will show nothing, correct? And you probably want the box to just list the active (true) bits from top to bottom with no wasted space for bits that are false...that about right?
 
So if a bit is true, you want the display to show its associated text, and if the bit is false, it will show nothing, correct? And you probably want the box to just list the active (true) bits from top to bottom with no wasted space for bits that are false...that about right?



Yes that's what I'm trying to accomplish
 
This is what I currently have programmed. The data box will display a message if one of the tags is active but will not display more than one at a time.

20200428_134336.jpg 20200428_134322.jpg
 
I tested this in the 3.0 emulator and it works. I created a retentive cstring tag called "Message" and set its length (arbitrarily) to 400 characters. For its data value, I chose complex and wrote this code:

Code:
cstring t;
if (Msg_1) t := t + Msg_1.AsText + "|";
if (Msg_2) t := t + Msg_2.AsText + "|";
if (Msg_3) t := t + Msg_3.AsText + "|";
if (Msg_4) t := t + Msg_4.AsText + "|";
if (Msg_5) t := t + Msg_5.AsText + "|";
if (Msg_6) t := t + Msg_6.AsText + "|";
if (Msg_7) t := t + Msg_7.AsText + "|";
if (Msg_8) t := t + Msg_8.AsText + "|";

return t;

Msg_1 through Msg_8 are flag tags with the ON State set to whatever text you want displayed when the tag is on.
On the display page, I dragged and dropped the Message tag, and changed its properties to show data only, set the vertical alignment to Top and I put a single pixel border around it.

I tested this in the emulator by putting all the bit tags Msg_1 through Msg_8 on the screen and adding a toggle action to them. In my test, they are not tied to a PLC, just internal flag tags.

Your real world case will have 32 more lines in the complex code for the source of the Message tag and your flags will be tied to PLC addresses, but I expect it will work the same.

In the complex code, the "|" added to the end of each true message is a carriage return symbol. When found within most text locations in Crimson, it will force a new line, so each true message will start on a new line and they won't all run together.

EDIT: Attached two versions, one for 3.0 which can be run in the emulator and a version imported into 3.1 in case you don't want ot mess with installing 3.0
 
Last edited:
[Whoops, OkiePC gave you the correct answer, roughly equivalent to my option 2 below; the "|" is the line terminator (new line and/or carriage return) for the message window. Make sure you get rid of your current else; statements!]



The way your code is now, from the screen image you sent, that routine will only return one message, and that for the first expression (bit) that it finds True (1)*.


So you want to return multiple messages from that routine, specifically every one for which its bit is 1.


I don't know Red Lion, but I can think of two likely ways to accomplish this:

  1. If Red Lion supports arrays or lists of strings, and the message window is expecting a list of strings,
    • initialize an empty array at the start of the routine, before the first {if (bit)...} statement
      • Probably something like array = [];
    • Remove the else; statements*
    • Instead of return "string";, do something like
      • array.append("string"]; or
      • array = array + ["string"];
      • or whatever is the equivalent in the Red Lion script language to append an item to an array
    • At the end of all the if (bit) array.append(...); statements, return the list of strings
    • In the code that called that routine, clear the message window and create a loop to process each string in the returned list and add each into the message window.
  2. If there are no arrays, perhaps you can concatenate strings together. If that is the case, concatenating strings, with a new line and/or a carriage return between each pair of string might give you a single string that will display as you like in the message window. The steps would be similar to those above for the list:
    • initialize an empty string at the start of the routine, before the first if (bit)...; statement
      • Probably something like return_string = "";
    • remove all of the else; statements*
    • Instead of return "string";, do something like
      • return_string = return_string + "string\n";
      • Note the \n at the end of the string; that is a new line; it may need to be a carriage return (\r) or both "string\n\r"; - check your Red Lion programming guide to determine which may be required.
    • At the end of all the if (bit) ...; statements, return the list of strings:
      • return return_string;



* As a side note, you do not want the [else;] statements, because the routine will hit a return after any if (VAR) that evaluates True, which return will cause the program flow to exit that routine, so any following else; clause will never be checked.
 
Last edited:
Wow, thanks so much guys. I'm a fairly novice programmer (maintenance electrician by trade) and have been beating me head against the wall with this one.

OkiePC, I just tested your code and it is working exactly how i want it, just have to finish adjusting all my tags and I'll be finished.

drbitboy, thanks for all that info, i will be slowing trying to doggest it now for a while.

You guys have been a HUGE help!! Thanks again!!!🍺
 
If you can get there and create Msg_array as an array of flag tags, an approach that separates the data from the code is this:


Code:
int i = 0;
cstring t = "";
cstring sep = "";
do {
   if (Msg_array[i]) {
     t := t + sep + Msg_array[i].AsText;
     sep := "|";
   }
} while (++i < 40);
 return t;
That saves writing forty if statements, and it also makes it easier to add, remove or re-order flag tags.



You may be able to replace 40 with Msg_array.Extent or something similar.


Also, this does not add an extra line terminator at the end of t.
 
Last edited:
If you can get there and create Msg_array as an array of flag tags, an approach that separates the data from the code is this:


Code:
int i = 0;
cstring t = "";
cstring sep = "";
do {
   if (Msg_array[i]) {
     t := t + sep + Msg_array[i].AsText;
     sep := "|";
   }
} while (++i < 40);
 return t;
That saves writing forty if statements, and it also makes it easier to add, remove or re-order flag tags.



You may be able to replace 40 with Msg_array.Extent or something similar.


Also, this does not add an extra line terminator at the end of t.

The drawback to this is that all of the elements of the boolean array will have the same text assigned the Data Format fields, so you would have to get creative and use some other means to come up with the unique text for each member of the array.

In other words, Msg_array[0].AsText would look identical to Msg_Array[39].AsText making all the messages in your list the same. I am pretty sure you can't write to those individual tag members' elemental data to make them unique...seems I tried something similar many years ago and hit a wall.

The other drawback, which might not even be noticeable, is the addition of the overhead of having a loop and indirection inside the definition of the data source.

I have used arrays of tag strings that are separate from the PLC bit arrays to derive text, so you could do something inside your loop like:

Code:
If (Msg_Array[i]) t := t + Msg_Text[i];

Where Msg_Text was an array of cstrings and you used a startup program to put the words in each of its members that you wanted.
I have some HMI code that lets you set up scaling for analog inputs on a machine with 11 analog signals, so I organized the tags so that the raw, scaled, raw_min, raw_max, scaled_min and scaled_max are each contiguous blocks of Micrologix addresses. Then I have in Crimson those tags set as arrays and one display page to let you cycle through each analog input and view/edit its associated scaling data. Additionally in the Crimson file I have a title[] and units[] cstring array so that you know the name and units of the analog signal you are scaling, but I didn't have to make 11 pages to show them all.

For the OP situation brute force like my original example is much less elegant, but more efficient.

One last detail: Putting the Data Format 'ON State' and 'OFF State' text for a flag (boolean) tag right on the tag itself means that anywhere you drop that tag on a page, that text will be used to show its value (by default). This helps keep development time down and the look and feel throughout the HMI application consistent.
 
Last edited:
Code:
If (Msg_Array[i]) t := t +Msg_Text[i];
Where Msg_Text was an array of cstrings and you used a startup program to put the words in each of its members that you wanted. Brute force like my original example is much less elegant, but more efficient.


Thanks for coming back and cleaning up my mess.


Too bad about the array of flag tags behavior.


Separating the bit and the text (Msg_Array[] and Msg_Text[]) is no better than the brute force if statements: with so much copy-paste it may take months to even notice all the typos.
 
Thanks for coming back and cleaning up my mess.


Too bad about the array of flag tags behavior.


Separating the bit and the text (Msg_Array[] and Msg_Text[]) is no better than the brute force if statements: with so much copy-paste it may take months to even notice all the typos.

If he had like 60 or more bits, I'd probably switch to the loop method.

The Crimson editor uses a fixed width font so it is pretty easy to copy and paste a line of code 40 times and then use the arrow and backspace keys to go through each line to edit one or two numbers...

I say that as a guy who has been editing text based code with a fixed width font since the Atari 400 days, so what I find easy might be ridiculous to others.
 
I say that as a guy who has been editing text based code with a fixed width font since the Atari 400 days, so what I find easy might be ridiculous to others.



I hear you: I am a VI guy.


I cannot stand the standard "TextBox" UI (like what I am typing in now;)).
 
Something to watch out for, the Alarm Viewer only shows current alarms, as soon as they are cleared they disappear. To see what happened you need to use the Event Viewer, this keeps a log of Alarms, when they happened, when they cleared and when they were accepted. Below I use the Alarm Viewer (top box) and Events Viewer (bottom box) together.

Alarm and Event Viewer.JPG
 

Similar Topics

How do you install update on Red Lion Crimson ver 3.1. Do I just need to run the exe file on the host server?
Replies
1
Views
107
Hi, I am trying to increase the size of the user login pop up using a Red Lion CR1000 7” HMI with Crimson 3.1 software. The login pop up is very...
Replies
2
Views
668
Hello, We are currently running a bunch of g310's connected to their SLC5 PLCs through ethernet. I've attempted to upgrade the program from 2.0...
Replies
1
Views
1,121
Hi I have been using Red Lion products for some time, I had a thought over the bank holiday weekend, As you do. It would be nice if whenever a...
Replies
4
Views
1,015
Well, I have yet another question for the great minds on this forum! We have a red lion HMI for one of our machines and every time I hook my...
Replies
11
Views
1,670
Back
Top Bottom