Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Script PLCs and strings
#1
I have a couple of questions relating to how PowerPmac and the IDE handle string arrays.

The guys writing the HMI application (running on a separate host PC) for our machine have asked that I store the machine alarm message strings in the Pmac. Creating and saving the 'string array' seems simple enough, I plan on having a PLC run at startup that will populate the shared user memory with all the alarm strings needed. The script code would be as shown below.

local indexStart,strgLen;

indexStart=16000; // byte offset into share user memory
strgLen=72; // default length of alarm string

stringIndex=sprintf((indexStart+(1*strgLen)),"Alarm Message 01");
stringIndex=sprintf((indexStart+(2*strgLen)),"Alarm Message 02");
.
.
stringIndex=sprintf((indexStart+(96*strgLen)),"Alarm Message 96");


At this point I plan on having a total of 96 alarm messages, of 72 characters each, so I'll need 96 commands similar to what is shown above. When a particular alarm is active, the strncpy command will be used to copy the message for the alarm into a separate buffer in user shared memory that the HMI app will poll to read and display the active alarm to an operator.

My first question - Is this the best way to populate string arrays?
Second question - Is there a way to easily display a string that is stored in user shared memory, in the IDE? I don't see an option to format data in the watch window as a string.
Third question - I'd like to echo the active alarm string to a port using the send instruction; for example to the IDE Unsolicited Messages window. But...strings for the send instruction look like they need to be defined explicitly in the send command. Is there a way to have the send command 'point' to a string in user shared memory?

There may be ways to handle this better in CPLCs but my C programming skills are not so good, so...script PLCs for now.


Thanks,
Kmonroe
Reply
#2
A CPLC is definitely the way to go for this. Rather than preallocating hundreds of bytes of memory for all of your alarm codes, I suggest just dynamically forming the Alarm Code string in the background and then copying it to the register that the HMI reads whenever an alarm code is signaled. This way you do not use up so much user shared memory.

In C, you can use the Send() command, which can dynamically send your strings to the Send Ports.

The following example will form the alarm code string dynamically whenever the global alarm code P-Variable, GlobalAlarmCode, changes. You must first put these definitions into global definitions.pmh:

Code:
global GlobalAlarmCode,GlobalAlarmCodeLatch;

Then the BGCPLC can be implemented as such:

Code:
#include <gplib.h>
#include <stdio.h>
#include <dlfcn.h>
#include "../../Include/pp_proj.h"

void user_plcc()
{
    char SendBuffer[73]=""; // Allocate 73 characters (72 for the alarm code, one for the null character appended at the end)
    char* HMI_AlarmCode_Buffer = (char*)pushm + 16000/4;    // Address of buffer that the HMI reads for the Alarm Code - User Input
    int LocalAlarmCode; // Local variable for casting
    
    LocalAlarmCode = (int)pshm->P[GlobalAlarmCode];        // Cast Alarm Code P-Variable to int

    if(LocalAlarmCode != (int)pshm->P[GlobalAlarmCodeLatch])    // If the Alarm Code changed
    {
        sprintf(SendBuffer,"Alarm Code %0d",LocalAlarmCode);    // Create the string
        strcpy(HMI_AlarmCode_Buffer,SendBuffer);                // Copy the string to the buffer that the HMI reads for the Alarm Code
        Send(SEND1_PORT,SendBuffer);                            // Echo the Alarm Code to the Send1 Port
        pshm->P[GlobalAlarmCodeLatch] = LocalAlarmCode;            // Latch the Alarm Code Latch to prevent unnecessary rewriting of Alarm Code messages
    }
    
    return;
}
Reply
#3
The IDE has no abilty to see these strings as strings.

In the program commands manual of Jan 2011 under the SEND command there is this paragraph which explains how to use the string in a send.

For each formatted variable sequence in the string, there must be an {expression} that specifies the numerical value that is to be converted to text. Each expression can be as simple as a constant or a variable, but can include mathematical operators and expressions as well. For a string variable, the expression value (rounded down to the next integer if necessary) represents the starting index in user shared memory of the string variable to be used.
Reply
#4
Hello,

For what its worth, I have a different way of doing it. If you write a "background C program" you should be able to open a socket and write your alarm strings as they occurr, at least from the C programming environment. This may be possible from CPLCs too.

I am not suggesting that this is easier, in fact it is more complicated because you have to open a socket, etc. If your program is going to head that way eventually, you might consider this method.

We are using this basic method, but with a linux FIFO file writing to our HMI process that runs on the PPMAC CPU itself. Its really not any different in concept though than writing to a socket. The HMI software has a thread that waits for data to come into the FIFO and then it displays it to the screen. Our realtime code controls what gets displayed and when, the HMI just basically writes it to the screen.

In some ways the old method of having a global fault number, and storing your fault strings in the HMI is *alot* easier. From a machine programmer perspective I personally love the ability to type the error strings in my C code and download them to the PPMAC without modifying the HMI software *at all*. It all depends on what you are trying to do.

KEJR
Reply
#5
You can (if using bgcplc or capp) also set up to send this as an unsolicited message and see the output in the Unsolicited Messages window (Delta Tau->View->Unsolicited Messages) Sample code is:

//function
void DebugPrint(char *debugstr){
Send(SEND1_PORT,debugstr); // Send debug text
}

//DebugPrint call
char debugstr[255];

sprintf(debugstr,"\nLength of file array=%#x (dec %d)", strlen(cFile), strlen(cFile));
DebugPrint(debugstr);

Note: I am not showing all the stuff around the filestream object - this is just to illustrate formatting the string. If your string is declared in a char array you can obviously simply print that string or concatenate it with something like "Alarm message is:"
Reply
#6
I ended up using the send command in a script PLC, and it worked well enough. But...we found that if I had the IDE open then our HMI app wouldn't always get the message from the send buffer, so the message update was sporadic at best. Apparently the app (the IDE or our HMI) that read the buffer first was the one to get the message.

So, I wrote the message into user shared memory, and the HMI guy basically reads those 72 bytes and converts them to an Ascii string. Not the most efficient, since he has to query the Pmac 16 times (one time for each unsigned int) to get the whole message.

Thought about trying to write it out a TCP/IP port as described above, just haven't written too much in C yet.

(03-24-2011, 03:49 PM)DavisG Wrote: You can (if using bgcplc or capp) also set up to send this as an unsolicited message and see the output in the Unsolicited Messages window (Delta Tau->View->Unsolicited Messages) Sample code is:

//function
void DebugPrint(char *debugstr){
Send(SEND1_PORT,debugstr); // Send debug text
}

//DebugPrint call
char debugstr[255];

sprintf(debugstr,"\nLength of file array=%#x (dec %d)", strlen(cFile), strlen(cFile));
DebugPrint(debugstr);

Note: I am not showing all the stuff around the filestream object - this is just to illustrate formatting the string. If your string is declared in a char array you can obviously simply print that string or concatenate it with something like "Alarm message is:"

Reply
#7
kill the unsolicited messages window in the IDE to make sure your HMI gets all of the messages...
Reply
#8
I thought about that, but I like having the alarm message show up in the unsolicited message window. Its not uncommon for us to monitor equipment remotely, so I won't always have the HMI to look at.

(03-28-2011, 02:05 PM)DavisG Wrote: kill the unsolicited messages window in the IDE to make sure your HMI gets all of the messages...

Reply
#9
Do a SENDALL after each SEND.

Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)