Jump to content
OMRON Forums

Disabling CPLCs


daves
 Share

Recommended Posts

In Turbo we used to have PLCCs which had lines in like

 

DISABLE PLCC 29
DISABLE PLCC 1..30

 

This could make a PLCC self-disabling or have control over other PLCCs.

 

In PowerPMAC I have guessed the first line is now:

 

Command((char *)"UserAlgo.BgCplc[29]=0");

 

which seems to work. Is this correct or is there a pshm-> entry for doing this properly? How do I do the second line?

 

BTW: I tried:

pshm->UserAlgo.BgCplcActive[2] = 0;

pshm->UserAlgo.BgCplc[2] = enum_threadshutdown;

 

The first line did not work. The second crashed the IDE on download "Object reference not set to an instance of an object"

 

Dave

Link to comment
Share on other sites

  • Replies 8
  • Created
  • Last Reply

Top Posters In This Topic

Thanks, this works great.

 

Now I'm having issues with the following code:

 

SetGlobalVar(PLC2RunFlag, 0);
pshm->UserAlgo.BgCplc[2] = enum_threadenable;

Send(2, (char *)"Waiting for PLCC 2...");
// Hold here until PLC 2 has finished
while (!GetGlobalVar(PLC2RunFlag))
{
	usleep(1);
}
Send(2, (char *)"PLCC 2 done");

 

We used to launch one PLCC from another and wait for it to finish. This mechanism no longer seems to work and locks up in the while loop.

 

Would you expect this? Is there a way to launch another CPLC asynchronously and wait on it?

 

Link to comment
Share on other sites

Three points:

  • Using pshm->P[PLC2RunFlag] (or pshm->P[AnyGlobalVariableNameYouAlreadyDefined]) will be a more efficient way of accessing global variables.
  • Do not use usleep() in Power PMAC, ever. This is in old examples on our forum, but now no one should ever use it in Power PMAC because it can disrupt the thread scheduling of the real-time operating system.
  • I just received instruction from the Software Engineers we should not write to UserAlgo.BgCplc[n] structures directly in C with pshm, but rather modify them using the SetPmacVar() function, e.g.:
     
    SetPmacVar("UserAlgo.BgCplc[2]=0") to disable CPLC threads
    SetPmacVar("UserAlgo.BgCplc[2]=1") to enable CPLC threads
     
    This is because some special processing occurs only when these structures (UserAlgo.BgCplc[n]) are modified in the text parser, but not when C modifies them directly.

 

Instead of usleep(), you should use nanosleep(). Here's a little example of how to use nanosleep() in a BGCPLC to accomplish what you're trying to do:

 

#include 
#include 
#include 

#include "../../Include/pp_proj.h"

void user_plcc()
{	
struct timespec SleepTime={0};	// Initialize time structure
SleepTime.tv_nsec=1000000;		// 1000000 nanoseconds, which equals 1 msec
pshm->P[PLC2RunFlag]=0;			// Bring PLC2 run flag low.
SetPmacVar("UserAlgo.BgCplc[2]",1); // Enable BGCPLC2 thread
nanosleep(&SleepTime,NULL); // Release thread and wait 1 msec to give the BGCPLC time to start
Send(2, (char *)"Waiting for PLCC 2...");
// Hold here until PLC 2 has finished
while(pshm->P[PLC2RunFlag]>0.0)
{
	// Release control for 1 ms so PMAC does not go into Watchdog mode
	// while waiting
	nanosleep(&SleepTime,NULL); // Release thread and wait 1 msec
}
Send(2, (char *)"PLCC 2 done");

SetPmacVar("UserAlgo.BgCplc[0]", 0); // Disable BGCPLC0 thread (this CPLC)
return;
}







 

 

 

 

 

 

Link to comment
Share on other sites

Thanks for these very useful and interesting tips (sorry for the long reply post)

 

  • I did a timing test and found the pshm->P[MyGlobal] was over twice as fast as GetGlobalVar. I now have to decide if I want to make time to alter my C programs.
     
    I know our company has requested access to be provided to the build chain to insert a custom preprocessor executable (we would write) which would allow MyGlobal to be used directly in C code at the writing stage and substituted for pshm->P[] before compilation. This came from 'real-world' engineers who use Turbo and don't like the software engineer syntax of C. If this is likely to come in the July release I'll hold off, otherwise I'll recode the GetGlobalVar calls.
     
    I then found http://forums.deltatau.com/showthread.php?tid=378 which agrees with my test. I see from there that GetPtrVar is pretty slow (comparatively) I guess there is no quicker access to these as they could point all over the place?
     
    If not, I think I'll have to consider doing manually initiated copies of speed-sensitive Ptr variables (when they change) to Globals similar to a mechanism we used to get dual port ram info into P-variables in Turbo for speed.

 

 

  • I have replaced all usleeps with nanosleeps.

 

 

  • I have replaced structure access to UserAlgo.BgCplc[] with the recommended SetPmacVar call. This seems to work well.
     
    I do however have to change the call to
    SetPmacVar((char *)"UserAlgo.BgCplc[0]", 0);
    


    to avoid warnings being generated which then cause further syntax errors not being reported in the IDE but only in the err.log file as reported in Bugzilla bug 489.

 

 

Thanks again for the help, progress on my conversion is now going great.

 

Dave

Link to comment
Share on other sites

You will be able to use Myvar declared in the globaldefinition.pmh file under script language and then use directly in the C code by use of preprocessor directive. The example code will come with newer release.(DemoBox_4x). Here is the code snippet for using the variable..

//---------------------------------------------------------
// New method of accessing Power PMAC Global P Variables
//---------------------------------------------------------
#ifdef _PPScriptMode_ 
gstep = 0.0;
while(!gstep)
	sleep(1);		// wait for step
#else	
SetGlobalVar(gstep,0.0);
while(!GetGlobalVar(gstep))
	sleep(1);		// wait for step
#endif	

In this the gstep is declared under...(On My machine)

C:\Program Files\Delta Tau Data Systems Inc\2.0\Power PMAC Suite\PowerPMACProjectExamples\DemoBox_4X\DemoBox_4X\PMAC Script Language\Global Includes\demo box defines.pmh

global gstep;

Thanks,

Atul

 

Link to comment
Share on other sites

  • 2 weeks later...

After a brief vacation and then a lot of investigation I have found that this mechanism does not have quite the same result as the equivalent Turbo code.

 

I think this might be informative to explain and I would like to confirm my approach is safe...

 

In Turbo you could have the following:

 

OPEN PLCC 15 CLEAR
WHILE(p5=0)
 p6=p6+1
ENDW
DIS PLCC 15
CLOSE

OPEN PLCC 16 CLEAR
DIS PLCC 15
DIS PLCC 16
CLOSE

 

Calling 'ena plcc 15' would show p6 incrementing. Calling 'ena plcc 16' would show it no longer incrementing and checking plcc status would show nothing running.

 

In PPMAC

 

// bgcplc15
void user_plcc()
{
struct timespec mSecSleeper = {0};
mSecSleeper.tv_nsec = 1e6;

while (!pshm->P[5])
{
	pshm->P[6]++;
	nanosleep(&mSecSleeper, NULL);
}
SetPmacVar((char *)"UserAlgo.BgCplc[15]", 0);
}

// bgcplc16
void user_plcc()
{
SetPmacVar("UserAlgo.BgCplc[15]", 0);
SetPmacVar("UserAlgo.BgCplc[16]", 0);
}

 

Calling 'UserAlgo.BgCplc[15]=1' shows P6 incrementing, calling 'UserAlgo.BgCplc[16]=1' does not stop incrementing P6. Now I understand why, because the while loop is still running, just the flag that PPMAC should call this procedure again after it returns is not set. (And Turbo used to take the execution pointer out of a program when doing whiles somehow).

 

I realise while loops are dangerous but the structure of the code I am converting relies on the behaviour (more complexly then this example). I have come up with the following but am worried about the effect on the scheduler:

 

// bgcplc15
void user_plcc()
{
struct timespec mSecSleeper = {0};
double dRunning;

mSecSleeper.tv_nsec = 1e6;
dRunning = 1;
while ((dRunning) && (!pshm->P[5]))
{
	pshm->P[6]++;
	nanosleep(&mSecSleeper, NULL);
	GetPmacVar((char *)"UserAlgo.BgCplc[15]", &dRunning);
}
SetPmacVar((char *)"UserAlgo.BgCplc[15]", 0);
}

 

I think this replicates Turbo behaviour enough for me. Does it look acceptable?

 

Link to comment
Share on other sites

Yes, that is acceptable.

 

It is actually alright to read UserAlgo.BgCplc[n] using pshm->UserAlgo.BgCplc[n] (but you should not write to it this way, as we have discussed). So to make your while loop a little faster you could write:

 

// bgcplc15
void user_plcc()
{
   struct timespec mSecSleeper = {0};
   double dRunning;

   mSecSleeper.tv_nsec = 1e6;
   dRunning = 1;
   while ((dRunning) && (!pshm->P[5]))
   {
       pshm->P[6]++;
       nanosleep(&mSecSleeper, NULL);
       dRunning=pshm->UserAlgo.BgCplc[15]; 
   }
   SetPmacVar((char *)"UserAlgo.BgCplc[15]", 0);
}

 

Your code is actually a good example of a "safe" while loop in that it has delays and a break condition (it is not an infinite while loop).

 

 

 

 

Link to comment
Share on other sites

  • 4 weeks later...

If I were you I would wrap the sleep stuff into nicer looking functions as the POSIX sleep calls are ugly when you use them all over the place.

 

I would also write functions called something like "EnablePlc(unsigned PlcNumber)" and "DisablePlc(unsigned PlcNumber)" so that you don't have to remember what those PLC commands mean. Comments are nice, but it is better not to have them and have a clean API.

 

This is just an idea, but I would consider looking at programming the Power PMAC alot differently than the turbo pmac. There is so much more flexibility with it that you might find you don't have to do alot with the PLCs. I use the Background C programs with multiple threads instead (disclaimer: You do have to know a bit about the realtime for this...). It is much like using the C language PLCs but organized the way I want them to be. Even having the ability to call C functions can get you around doing alot of PLC enable/disable like you had to do in the old days. I don't know what you are doing exactly but thought I'd mention this. Your mileage may vary as they say... :o)

 

KEJR

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share


×
×
  • Create New...