watchdog.cpp

Setup a watchdog timer using User Limits, User Faults and the User Buffer

/*  watchdog.cpp

 Copyright(c) 1998-2009 by Robotic Systems Integration, Inc. All rights reserved.
 This software contains proprietary and confidential information of Robotic 
 Systems Integration, Inc. (RSI) and its suppliers. Except as may be set forth 
 in the license agreement under which this software is supplied, disclosure, 
 reproduction, or use with controls other than those provided by RSI or suppliers
 for RSI is strictly prohibited without the prior express written consent of 
 Robotic Systems Integration.

 This sample code presumes that the user has set the tuning paramters(PID, PIV, etc.) 
 prior to running this program so that the motor can rotate in a stable manner.

 For any questions regarding this sample code please visit our documentation at www.roboticsys.com

 Warning!  This is a sample program to assist in the integration of your motion 
 controller with your application.  It may not contain all of the logic and safety
 features that your application requires.




User Limits = A way to configure custom Events and Actions
User Faults = A configuration of a SynqNet node to watch controller data and perform a programmable action
User Buffer = Some unused memory on the controller


We'll need one axis to monitor the watchdog, usually this is best as a Phantom axis

*/

#include "rsi.h"

using namespace RSI::RapidCode::SynqNet;

#define AXIS_X          (0)     // a real axis
#define AXIS_Y          (2)     // another real axis
#define AXIS_WATCHDOG     (1)     // the phantom/virtual axis to monitor the watchdog

#define WATCHDOG_TIME     (0.02)    // how long before we are timed out?  (seconds)

// what should axes do if watchdog stops?
#define WATCHDOG_ACTION             RSIActionABORT

// which User Limits to use on the watchdog axis
#define WATCHDOG_MONITOR_LIMIT      RSIEventTypeLIMIT_USER1
#define WATCHDOG_RESET_LIMIT        RSIEventTypeLIMIT_USER2



void ConfigureWatchdogUserLimits(Axis *axis, long watchdogAddress, long timeoutAddress)
{

  // Setup User Limit to monitor watchdog value (expects PC to write a 1 if alive)
  axis->UserLimitConditionSet(WATCHDOG_MONITOR_LIMIT,       // which User Limit?
                    0,              // which Condition? (0 or 1)
                    RSIXmpLimitTypeNE,      // make sure we're NOT EQUAL
                    watchdogAddress,    // watch this address
                    0xFFFFFFFF ,        // AND the value with this 
                    0);             // the expected value
  
  axis->UserLimitOutputSet(WATCHDOG_MONITOR_LIMIT,      // which User Limit?
                    0,             // AND mask
                    1,            // OR mask
                    timeoutAddress,  // where to write value
                    true);          // enabled = yes

  axis->UserLimitConfigSet(WATCHDOG_MONITOR_LIMIT,      // which User Limit
                    RSIXmpStatusLIMIT,    // perform any action?
                    RSIXmpLogicSINGLE,    // how many conditions?
                    WATCHDOG_TIME);     // how long ?
  
  
  
  // Setup User Limit to reset the limit
  axis->UserLimitConditionSet(WATCHDOG_RESET_LIMIT,      // which User Limit?
                    0,              // which Condition? (0 or 1)
                    RSIXmpLimitTypeEQ,    // equal
                    axis->rsiControl->AddressFromStringGet("MEIXmpBufferData.UserLimit[7].Limit[1].Count", "c:\\synqnet\\stdmei.map"),  // watch this address
                    0xFFFFFFFF,             // AND the value with this 
                    0);             // the expected value
  
  axis->UserLimitOutputSet(WATCHDOG_RESET_LIMIT,        // which User Limit?
                    0,             // AND mask
                    1,            // OR mask
                    watchdogAddress,  // where to write value
                    true);          // enabled = yes

  axis->UserLimitConfigSet(WATCHDOG_RESET_LIMIT,        // which User Limit
                    RSIXmpStatusLIMIT,    // perform any action?
                    RSIXmpLogicSINGLE,    // how many conditions?
                    0.0);     // how long ?

}


// any axis that needs an action upon watchdog timeout should call this
void ConfigureUserFaults(Axis *axis, long timeoutAddress)
{
  axis->SqNode->UserFaultAddressSet(timeoutAddress);  // expecting a 1 here if timeout occurs
  axis->SqNode->UserFaultMaskSet(1);  
  axis->SqNode->UserFaultPatternSet(1);
  axis->UserFaultActionSet(WATCHDOG_ACTION);
}


void WatchdogPet(MotionController *controller, long watchdogAddress)
{
  // write a 0 to the watchdogAddress
  controller->MemorySet(watchdogAddress, 0);
}

void WatchdogClear(MotionController *controller, long timeoutAddress)
{
  // write a 0 to the timeoutAddress -- clears any pre-existing timeouts
  controller->MemorySet(timeoutAddress, 0);
}

void WatchdogDisable(Axis *axis, long timeoutAddress)
{
  // disable User Limits
  axis->UserLimitConfigSet(WATCHDOG_MONITOR_LIMIT,    // which User Limit
                  RSIXmpStatusLIMIT,    
                  RSIXmpLogicNEVER,   // how many conditions?
                  0.0);     

  axis->UserLimitConfigSet(WATCHDOG_RESET_LIMIT,        // which User Limit
                    RSIXmpStatusLIMIT,    
                    RSIXmpLogicNEVER,   // how many conditions?
                    0.0);   

  // wait a few samples so the limits have been processed with new settings
  axis->rsiControl->OS->Sleep(10);

}


void watchdogMain()
{
  try
  {
    MotionController  *controller ;
    Axis        *axisX ;
    Axis        *axisY ;
    Axis        *axisWatchdog ;
    
    long        watchdogAddress;   // where we expect the PC to write a non-zero value if alive
    long        timeoutAddress;    // a value will be set here if there is a timeout

    // initialize MotionController class (PCI board)
    controller = MotionController::CreateFromBoard(0);
    
    // initialize Axis X and Y classes respectively
    axisX = controller->AxisGet(AXIS_X);
    axisY = controller->AxisGet(AXIS_Y);
    axisWatchdog = controller->AxisGet(AXIS_WATCHDOG);

    watchdogAddress = controller->AddressFromStringGet("MEIXmpBufferData.UserBuffer.Data[0]", "c:\\synqnet\\stdmei.map");
    timeoutAddress = controller->AddressFromStringGet("MEIXmpBufferData.UserBuffer.Data[1]", "c:\\synqnet\\stdmei.map");
    // be sure the watchdog phantom axis is in an idle state
    axisWatchdog->ClearFaults();
    
    // clear any pre-existing watchdog timeouts
    WatchdogClear(controller, timeoutAddress);

    // setup the watchdog
    ConfigureWatchdogUserLimits(axisWatchdog, watchdogAddress, timeoutAddress);

    // be sure existing faults are cleared
    axisX->ClearFaults();
    axisY->ClearFaults();
    axisX->AmpEnableSet(true);
    axisY->AmpEnableSet(true);

    // configure real axes to perform action on watchdog timeout
    ConfigureUserFaults(axisX, timeoutAddress);
    ConfigureUserFaults(axisY, timeoutAddress);

    // pet the watchdog since it's running now
    WatchdogPet(controller, watchdogAddress);

    printf("Press a key to stop petting the watchdog...\n");
    long previousTime = 0;
    while(controller->OS->KeyGet(RSIWaitPOLL) < 0)
    {
      WatchdogPet(controller, watchdogAddress);
      // wait a few ms
      //controller->OS->Sleep(1)  ;
    }

    // wait a bit (make sure timeout occurs)
    controller->OS->Sleep( WATCHDOG_TIME * 1000);   // convert seconds to milliseconds

    // wait an extra second
    controller->OS->Sleep(1000);

    // now disable the feature
    WatchdogDisable(axisWatchdog, timeoutAddress);
    // clear any pre-existing watchdog timeouts
    WatchdogClear(controller, timeoutAddress);

  
  }
  catch (RsiError *err)
  {
    printf("%s\n", err->text);
  }
}