/ src / hal / components / boss_plc.c
boss_plc.c
   1  /******************************************************************************
   2   *
   3   * Copyright (C) 2007 Peter G. Vavaroutsos <pete AT vavaroutsos DOT com>
   4   *
   5   *
   6   * This module is a hard coded PLC for use on a Bridgeport Boss.
   7   *
   8   * Installation of the component (realtime only):
   9   *
  10   * insmod boss_plc count=<1>
  11   *
  12   *
  13   * The following items are exported to the HAL. <id> is
  14   * the component id number and is formatted as "%d".
  15   *
  16   *  Pins (former parameters):
  17   *        u32       boss_plc.<id>.amp-ready-delay
  18   *        u32       boss_plc.<id>.brake-on-delay
  19   *        u32       boss_plc.<id>.brake-off-delay
  20   *        u32       boss_plc.<id>.spindle-lo-to-hi
  21   *        float     boss_plc.<id>.jog-scale-0
  22   *        float     boss_plc.<id>.jog-scale-1
  23   *        float     boss_plc.<id>.jog-scale-2
  24   *
  25   *  Pins:
  26   *        bit       boss_plc.<id>.cycle-start-in
  27   *        bit       boss_plc.<id>.cycle-hold-in
  28   *        bit       boss_plc.<id>.feed-hold-out
  29   *        float     boss_plc.<id>.adaptive-feed-in
  30   *        float     boss_plc.<id>.adaptive-feed-out
  31   *        bit       boss_plc.<id>.tool-change-in
  32   *        bit       boss_plc.<id>.tool-changed-out
  33   *        bit       boss_plc.<id>.wait-user-out
  34   *        bit       boss_plc.<id>.mist-on-in
  35   *        bit       boss_plc.<id>.mist-on-out
  36   *        bit       boss_plc.<id>.flood-on-in
  37   *        bit       boss_plc.<id>.flood-on-out
  38   *
  39   *        bit       boss_plc.<id>.limit-override-in
  40   *        bit       boss_plc.<id>.limit-active-out
  41   *        float     boss_plc.<id>.x-position-in
  42   *        bit       boss_plc.<id>.x-jog-en-in
  43   *        bit       boss_plc.<id>.x-limit-in
  44   *        bit       boss_plc.<id>.x-limit-pos-out
  45   *        bit       boss_plc.<id>.x-limit-neg-out
  46   *        float     boss_plc.<id>.y-position-in
  47   *        bit       boss_plc.<id>.y-jog-en-in
  48   *        bit       boss_plc.<id>.y-limit-in
  49   *        bit       boss_plc.<id>.y-limit-pos-out
  50   *        bit       boss_plc.<id>.y-limit-neg-out
  51   *        bit       boss_plc.<id>.z-jog-en-in
  52   *        bit       boss_plc.<id>.z-limit-pos-in
  53   *        bit       boss_plc.<id>.z-limit-neg-in
  54   *        bit       boss_plc.<id>.z-limit-pos-out
  55   *        bit       boss_plc.<id>.z-limit-neg-out
  56   *
  57   *        bit       boss_plc.<id>.x-amp-enable-in
  58   *        bit       boss_plc.<id>.x-amp-ready-in
  59   *        bit       boss_plc.<id>.x-amp-fault-out
  60   *        bit       boss_plc.<id>.y-amp-enable-in
  61   *        bit       boss_plc.<id>.y-amp-ready-in
  62   *        bit       boss_plc.<id>.y-amp-fault-out
  63   *        bit       boss_plc.<id>.z-amp-enable-in
  64   *        bit       boss_plc.<id>.z-amp-ready-in
  65   *        bit       boss_plc.<id>.z-amp-fault-out
  66   *        bit       boss_plc.<id>.a-amp-enable-in
  67   *        bit       boss_plc.<id>.a-amp-ready-in
  68   *        bit       boss_plc.<id>.a-amp-fault-out
  69   *
  70   *        float     boss_plc.<id>.spindle-speed-in
  71   *        bit       boss_plc.<id>.spindle-is-on-in
  72   *        bit       boss_plc.<id>.spindle-fwd-out
  73   *        bit       boss_plc.<id>.spindle-rev-out
  74   *        bit       boss_plc.<id>.spindle-inc-in
  75   *        bit       boss_plc.<id>.spindle-dec-in
  76   *        bit       boss_plc.<id>.spindle-inc-out
  77   *        bit       boss_plc.<id>.spindle-dec-out
  78   *        bit       boss_plc.<id>.brake-en-in
  79   *        bit       boss_plc.<id>.brake-en-out
  80   *
  81   *        bit       boss_plc.<id>.jog-sel-in-0
  82   *        bit       boss_plc.<id>.jog-sel-in-1
  83   *        bit       boss_plc.<id>.jog-sel-in-2
  84   *        bit       boss_plc.<id>.jog-scale-out
  85   *
  86   *   Functions:
  87   *        void      boss_plc.<id>.refresh
  88   *
  89   ******************************************************************************
  90   *
  91   * This program is free software; you can redistribute it and/or
  92   * modify it under the terms of version 2 of the GNU General
  93   * Public License as published by the Free Software Foundation.
  94   * This library is distributed in the hope that it will be useful,
  95   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  96   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  97   * GNU General Public License for more details.
  98   *
  99   * You should have received a copy of the GNU General Public
 100   * License along with this library; if not, write to the Free Software
 101   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 102   *
 103   * THE AUTHORS OF THIS LIBRARY ACCEPT ABSOLUTELY NO LIABILITY FOR
 104   * ANY HARM OR LOSS RESULTING FROM ITS USE.  IT IS _EXTREMELY_ UNWISE
 105   * TO RELY ON SOFTWARE ALONE FOR SAFETY.  Any machinery capable of
 106   * harming persons must have provisions for completely removing power
 107   * from all motors, etc, before persons enter any danger area.  All
 108   * machinery must be designed to comply with local and national safety
 109   * codes, and the authors of this software can not, and do not, take
 110   * any responsibility for such compliance.
 111   *
 112   * This code was written as part of the EMC HAL project.  For more
 113   * information, go to www.linuxcnc.org.
 114   *
 115   ******************************************************************************/
 116  
 117  
 118  #include "rtapi.h"              // RTAPI realtime OS API.
 119  #include "rtapi_app.h"          // RTAPI realtime module decls.
 120  #include "hal.h"                // HAL public API decls.
 121  
 122  
 123  #define TRUE                    1
 124  #define FALSE                   0
 125  typedef int                     BOOL;
 126  
 127  
 128  // Module information.
 129  MODULE_AUTHOR("Pete Vavaroutsos");
 130  MODULE_DESCRIPTION("Bridgeport BOSS PLC for EMC HAL");
 131  MODULE_LICENSE("GPL");
 132  static unsigned long                    count = 1;
 133  RTAPI_MP_LONG(count, "Number of BOSS PLCs to instance");
 134  static int                              debug = 0;
 135  RTAPI_MP_INT(debug, "Enables optional params");
 136  
 137  
 138  /******************************************************************************
 139   * TIMER OBJECT
 140   *
 141   * This object implements a timer with mSec resolution.
 142   *
 143   ******************************************************************************/
 144  
 145  typedef enum {
 146      TM_ONE_SHOT,
 147      TM_CONTINUOUS,
 148  } TimerMode;
 149  
 150  typedef void                    (*TIMER_ROUTINE)(void *pArgs);
 151  
 152  typedef struct {
 153      // Private data.
 154      BOOL                        enabled;
 155      hal_u32_t                   nSec;
 156      hal_u32_t                   count;
 157      hal_u32_t                   timeout;
 158      TIMER_ROUTINE               pTimeout;
 159      void                        *pArgs;
 160      TimerMode                   mode;
 161  } Timer;
 162  
 163  static void Timer_Init(Timer *this);
 164  static void Timer_Enable(Timer *this, TimerMode mode);
 165  static void Timer_Disable(Timer *this);
 166  static BOOL Timer_IsEnabled(Timer *this);
 167  static void Timer_Update(Timer *this, long period);
 168  static void Timer_SetTimeout(Timer *this, hal_u32_t timeout);
 169  #if 0
 170  static void Timer_SetCallback(Timer *this, TIMER_ROUTINE pCallback, void *pArgs);
 171  #endif
 172  
 173  
 174  /******************************************************************************
 175   * LIMIT OBJECT
 176   *
 177   * This object converts a bi-directional limit switch into to limit signals.
 178   *
 179   ******************************************************************************/
 180  
 181  typedef enum {
 182      LS_INIT,
 183      LS_ON_LIMIT,
 184      LS_NO_MOTION,
 185      LS_POS_MOTION,
 186      LS_NEG_MOTION,
 187  } LimitState;
 188  
 189  typedef struct {
 190      // Exported pins.
 191      hal_float_t                 *pPositionIn;
 192      hal_bit_t                   *pJogEnIn;
 193      hal_bit_t                   *pIn;
 194      hal_bit_t                   *pPosOut;
 195      hal_bit_t                   *pNegOut;
 196  
 197      // Internal data.
 198      LimitState                  state;
 199      hal_float_t                 position;
 200      hal_bit_t                   limitPos;
 201      hal_bit_t                   limitNeg;
 202  } Limit;
 203  
 204  static int Limit_Export(Limit *this, int compId, int id, char *name, char axis);
 205  static void Limit_Init(Limit *this);
 206  static BOOL Limit_IsActive(Limit *this);
 207  static void Limit_Refresh(Limit *this, hal_bit_t override);
 208  
 209  
 210  /******************************************************************************
 211   * AMP OBJECT
 212   *
 213   * This object creates the amp fault signal from the enable and ready signal.
 214   *
 215   ******************************************************************************/
 216  
 217  typedef struct {
 218      // Exported pins.
 219      hal_bit_t                   *pEnableIn;
 220      hal_bit_t                   *pReadyIn;
 221      hal_bit_t                   *pFaultOut;
 222  
 223      // Internal data.
 224      Timer                       timer;
 225      hal_bit_t                   lastEnable;
 226  } Amp;
 227  
 228  static int Amp_Export(Amp *this, int compId, int id, char *name, char axis);
 229  static void Amp_Init(Amp *this);
 230  static void Amp_Refresh(Amp *this, long period, hal_u32_t readyDelay);
 231  
 232  
 233  /******************************************************************************
 234   * PLC OBJECT
 235   *
 236   * This object contains all the data for one PLC. A component object is
 237   * dynamically allocated in shmem for each PLC during initialization.
 238   *
 239   ******************************************************************************/
 240  
 241  #define NUM_JOG_SEL             3
 242  #define NUM_AXIS                4
 243  
 244  static char                     axisNames[NUM_AXIS] = {
 245      'x', 'y', 'z', 'a'
 246  };
 247  
 248  typedef enum {
 249      SS_OFF,
 250      SS_WAIT_BRAKE_OFF,
 251      SS_WAIT_ON,
 252      SS_ON,
 253      SS_WAIT_OFF,
 254      SS_WAIT_BRAKE_ON,
 255  } SpindleState;
 256  
 257  typedef struct {
 258      // Pins. (former parameters)
 259      hal_u32_t                   *ampReadyDelay;
 260      hal_u32_t                   *brakeOnDelay;
 261      hal_u32_t                   *brakeOffDelay;
 262      hal_float_t                 *spindleLoToHi;
 263      hal_float_t                 *jogScale[NUM_JOG_SEL];
 264  
 265      // Pins.
 266      hal_bit_t                   *pCycleStartIn;
 267      hal_bit_t                   *pCycleHoldIn;
 268      hal_bit_t                   *pFeedHoldOut;
 269      hal_float_t                 *pAdaptiveFeedIn;
 270      hal_float_t                 *pAdaptiveFeedOut;
 271      hal_bit_t                   *pToolChangeIn;
 272      hal_bit_t                   *pToolChangedOut;
 273      hal_bit_t                   *pWaitUserOut;
 274      hal_bit_t                   *pMistOnIn;
 275      hal_bit_t                   *pMistOnOut;
 276      hal_bit_t                   *pFloodOnIn;
 277      hal_bit_t                   *pFloodOnOut;
 278  
 279      hal_bit_t                   *pLimitOverrideIn;
 280      hal_bit_t                   *pLimitActiveOut;
 281      Limit                       xLimit;
 282      Limit                       yLimit;
 283      hal_bit_t                   *pZJogEnIn;
 284      hal_bit_t                   *pZLimitPosIn;
 285      hal_bit_t                   *pZLimitNegIn;
 286      hal_bit_t                   *pZLimitPosOut;
 287      hal_bit_t                   *pZLimitNegOut;
 288  
 289      Amp                         amps[NUM_AXIS];
 290  
 291      hal_float_t                 *pSpindleSpeedIn;
 292      hal_bit_t                   *pSpindleIsOnIn;
 293      hal_bit_t                   *pSpindleFwdOut;
 294      hal_bit_t                   *pSpindleRevOut;
 295      hal_bit_t                   *pSpindleIncIn;
 296      hal_bit_t                   *pSpindleDecIn;
 297      hal_bit_t                   *pSpindleIncOut;
 298      hal_bit_t                   *pSpindleDecOut;
 299      hal_bit_t                   *pBrakeEnIn;
 300      hal_bit_t                   *pBrakeEnOut;
 301  
 302      hal_bit_t                   *pJogSelIn[NUM_JOG_SEL];
 303      hal_float_t                 *pJogScaleOut;
 304  
 305      // Private data.
 306      SpindleState                spindleState;
 307      Timer                       spindleTimer;
 308      hal_float_t                 lastSpindleSpeed;
 309      hal_bit_t                   lastCycleStart;
 310  } Plc;
 311  
 312  
 313  // These methods are used for initialization.
 314  static int Plc_Init(Plc *this);
 315  static int Plc_Export(Plc *this, int compId, int id);
 316  static int Plc_ExportFeed(Plc *this, int compId, int id, char *name);
 317  static int Plc_ExportLimits(Plc *this, int compId, int id, char *name);
 318  static int Plc_ExportAmps(Plc *this, int compId, int id, char *name);
 319  static int Plc_ExportSpindle(Plc *this, int compId, int id, char *name);
 320  static int Plc_ExportJog(Plc *this, int compId, int id, char *name);
 321  
 322  // These methods are exported to the HAL.
 323  static void Plc_Refresh(void *this, long period);
 324  
 325  // Private helper methods.
 326  static void Plc_RefreshFeed(Plc *this, long period);
 327  static void Plc_RefreshLimits(Plc *this, long period);
 328  static void Plc_RefreshAmps(Plc *this, long period);
 329  static void Plc_RefreshSpindle(Plc *this, long period);
 330  static void Plc_RefreshJog(Plc *this, long period);
 331  
 332  
 333  /******************************************************************************
 334   * COMPONENT OBJECT
 335   *
 336   * This object contains all the data for this HAL component.
 337   *
 338   ******************************************************************************/
 339  
 340  #define MAX_DEVICES             4
 341  
 342  typedef struct {
 343      int                         id;             // HAL component ID.
 344      Plc                         *plcTable[MAX_DEVICES];
 345  } Component;
 346  
 347  static Component                component;
 348  
 349  
 350  /******************************************************************************
 351   * INIT AND EXIT CODE
 352   ******************************************************************************/
 353  
 354  int
 355  rtapi_app_main(void)
 356  {
 357      int                         i;
 358      Plc                         *pComp;
 359  
 360      // Connect to the HAL.
 361      component.id = hal_init("boss_plc");
 362      if (component.id < 0) {
 363          rtapi_print_msg(RTAPI_MSG_ERR, "BOSS_PLC: ERROR: hal_init() failed\n");
 364          return(-1);
 365      }
 366  
 367      for(i = 0; i < MAX_DEVICES; i++){
 368          component.plcTable[i] = NULL;
 369      }
 370  
 371      if(count > MAX_DEVICES)
 372          count = MAX_DEVICES;
 373  
 374      for(i = 0; i < count; i++){
 375          // Allocate memory for device object.
 376          pComp = hal_malloc(sizeof(Plc));
 377  
 378          if (pComp == NULL) {
 379              rtapi_print_msg(RTAPI_MSG_ERR, "BOSS_PLC: ERROR: hal_malloc() failed\n");
 380              hal_exit(component.id);
 381              return(-1);
 382          }
 383  
 384          // Save pointer to device object.
 385          component.plcTable[i] = pComp;
 386  
 387          // Initialize device.
 388          if(Plc_Init(pComp)){
 389              hal_exit(component.id);
 390              return(-1);
 391          }
 392  
 393          // Export pins, parameters, and functions.
 394          if(Plc_Export(pComp, component.id, i)){
 395              hal_exit(component.id);
 396              return(-1);
 397          }
 398      }
 399  
 400      hal_ready(component.id);
 401      return(0);
 402  }
 403  
 404  
 405  void
 406  rtapi_app_exit(void)
 407  {
 408      int                         i;
 409      Plc                         *pComp;
 410  
 411      hal_exit(component.id);
 412  
 413      for(i = 0; i < MAX_DEVICES; i++){
 414          if((pComp = component.plcTable[i]) != NULL){
 415              // TODO: Free device object when HAL supports free.
 416  //            hal_free(pComp);
 417          }
 418      }
 419  }
 420  
 421  
 422  /******************************************************************************
 423   * PLC OBJECT FUNCTION DEFINITIONS
 424   ******************************************************************************/
 425  
 426  /*
 427   * LOCAL FUNCTIONS
 428   */
 429  
 430  static int
 431  Plc_Init(Plc *this)
 432  {
 433      int                         i;
 434  
 435      // Initialize variables.
 436      this->spindleState = SS_OFF;
 437      this->lastSpindleSpeed = 0.0;
 438      this->lastCycleStart = 1;
 439  
 440      // Initialize parameters.
 441      *(this->brakeOffDelay) = 500;
 442      *(this->brakeOnDelay) = 300;
 443      *(this->ampReadyDelay) = 50;
 444      *(this->spindleLoToHi) = 500;
 445  
 446      *(this->jogScale[0]) = 0.0001;
 447      for(i = 1; i < NUM_JOG_SEL; i++){
 448          *(this->jogScale[i]) = *(this->jogScale[i-1]) * 10;
 449      }
 450  
 451      // Initialize timer.
 452      Timer_Init(&this->spindleTimer);
 453  
 454      // Initialize limits.
 455      Limit_Init(&this->xLimit);
 456      Limit_Init(&this->yLimit);
 457  
 458      // Initialize amps.
 459      for(i = 0; i < NUM_AXIS; i++){
 460          Amp_Init(&this->amps[i]);
 461      }
 462  
 463      return(0);
 464  }
 465  
 466  
 467  static int
 468  Plc_Export(Plc *this, int compId, int id)
 469  {
 470      int                         msgLevel, error;
 471      char                        name[HAL_NAME_LEN + 1];
 472  
 473      // This function exports a lot of stuff, which results in a lot of
 474      // logging if msg_level is at INFO or ALL. So we save the current value
 475      // of msg_level and restore it later.  If you actually need to log this
 476      // function's actions, change the second line below.
 477      msgLevel = rtapi_get_msg_level();
 478      rtapi_set_msg_level(RTAPI_MSG_WARN);
 479  
 480      // Export pins and parameters.
 481      error = Plc_ExportFeed(this, compId, id, name);
 482  
 483      if(!error){
 484          error = Plc_ExportLimits(this, compId, id, name);
 485      }
 486  
 487      if(!error){
 488          error = Plc_ExportAmps(this, compId, id, name);
 489      }
 490  
 491      if(!error){
 492          error = Plc_ExportSpindle(this, compId, id, name);
 493      }
 494      if(!error){
 495          error = Plc_ExportJog(this, compId, id, name);
 496      }
 497  
 498      // Export functions.
 499      if(!error){
 500          rtapi_snprintf(name, sizeof(name), "boss_plc.%d.refresh", id);
 501          error = hal_export_funct(name, Plc_Refresh, this, 1, 0, compId);
 502      }
 503  
 504      // Restore saved message level.
 505      rtapi_set_msg_level(msgLevel);
 506  
 507      return(error);
 508  }
 509  
 510  
 511  static int
 512  Plc_ExportFeed(Plc *this, int compId, int id, char *name)
 513  {
 514      int                         error;
 515  
 516      // Export pins.
 517      error = hal_pin_bit_newf(HAL_IN, &this->pCycleStartIn, compId,
 518  			     "boss_plc.%d.cycle-start-in", id);
 519  
 520      if(!error){
 521          error = hal_pin_bit_newf(HAL_IN, &this->pCycleHoldIn, compId,
 522  				 "boss_plc.%d.cycle-hold-in", id);
 523      }
 524  
 525      if(!error){
 526          error = hal_pin_bit_newf(HAL_OUT, &this->pFeedHoldOut, compId,
 527  				 "boss_plc.%d.feed-hold-out", id);
 528      }
 529  
 530      if(!error){
 531          error = hal_pin_float_newf(HAL_IN, &this->pAdaptiveFeedIn, compId,
 532  				   "boss_plc.%d.adaptive-feed-in", id);
 533      }
 534  
 535      if(!error){
 536          *this->pAdaptiveFeedIn = 1.0;
 537          error = hal_pin_float_newf(HAL_OUT, &this->pAdaptiveFeedOut, compId,
 538  				   "boss_plc.%d.adaptive-feed-out", id);
 539      }
 540  
 541      if(!error){
 542          error = hal_pin_bit_newf(HAL_IN, &this->pToolChangeIn, compId,
 543  				 "boss_plc.%d.tool-change-in", id);
 544      }
 545  
 546      if(!error){
 547          error = hal_pin_bit_newf(HAL_OUT, &this->pToolChangedOut, compId,
 548  				 "boss_plc.%d.tool-changed-out", id);
 549      }
 550  
 551      if(!error){
 552          error = hal_pin_bit_newf(HAL_OUT, &this->pWaitUserOut, compId,
 553  				 "boss_plc.%d.wait-user-out", id);
 554      }
 555  
 556      if(!error){
 557          error = hal_pin_bit_newf(HAL_IN, &this->pMistOnIn, compId,
 558  				 "boss_plc.%d.mist-on-in", id);
 559      }
 560  
 561      if(!error){
 562          error = hal_pin_bit_newf(HAL_OUT, &this->pMistOnOut, compId,
 563  				 "boss_plc.%d.mist-on-out", id);
 564      }
 565  
 566      if(!error){
 567          error = hal_pin_bit_newf(HAL_IN, &this->pFloodOnIn, compId,
 568  				 "boss_plc.%d.flood-on-in", id);
 569      }
 570  
 571      if(!error){
 572          error = hal_pin_bit_newf(HAL_OUT, &this->pFloodOnOut, compId,
 573  				 "boss_plc.%d.flood-on-out", id);
 574      }
 575  
 576      return(error);
 577  }
 578  
 579  
 580  static int
 581  Plc_ExportLimits(Plc *this, int compId, int id, char *name)
 582  {
 583      int                         error;
 584  
 585      // Export pins.
 586      error = hal_pin_bit_newf(HAL_IN, &this->pLimitOverrideIn, compId,
 587  			     "boss_plc.%d.limit-override-in", id);
 588  
 589      if(!error){
 590          error = hal_pin_bit_newf(HAL_OUT, &this->pLimitActiveOut, compId,
 591  				 "boss_plc.%d.limit-active-out", id);
 592      }
 593  
 594      if(!error){
 595          error = Limit_Export(&this->xLimit, compId, id, name, axisNames[0]);
 596      }
 597  
 598      if(!error){
 599          error = Limit_Export(&this->yLimit, compId, id, name, axisNames[1]);
 600      }
 601  
 602      if(!error){
 603          error = hal_pin_bit_newf(HAL_IN, &this->pZLimitPosIn, compId,
 604  				 "boss_plc.%d.%c-limit-pos-in", id, axisNames[2]);
 605      }
 606  
 607      if(!error){
 608          error = hal_pin_bit_newf(HAL_IN, &this->pZJogEnIn, compId,
 609  				 "boss_plc.%d.%c-jog-en-in", id, axisNames[2]);
 610      }
 611  
 612      if(!error){
 613          error = hal_pin_bit_newf(HAL_IN, &this->pZLimitNegIn, compId,
 614  				 "boss_plc.%d.%c-limit-neg-in", id, axisNames[2]);
 615      }
 616  
 617      if(!error){
 618          error = hal_pin_bit_newf(HAL_OUT, &this->pZLimitPosOut, compId,
 619  				 "boss_plc.%d.%c-limit-pos-out", id, axisNames[2]);
 620      }
 621  
 622      if(!error){
 623          error = hal_pin_bit_newf(HAL_OUT, &this->pZLimitNegOut, compId,
 624  				 "boss_plc.%d.%c-limit-neg-out", id, axisNames[2]);
 625      }
 626  
 627      // Export optional parameters.
 628      if(debug > 0){
 629          if(!error){
 630              error = hal_param_u32_newf(HAL_RO, &this->xLimit.state, compId,
 631  				       "boss_plc.%d.%c-limit-state", id, axisNames[0]);
 632          }
 633  
 634          if(!error){
 635              error = hal_param_u32_newf(HAL_RO, &this->yLimit.state, compId,
 636  				       "boss_plc.%d.%c-limit-state", id, axisNames[1]);
 637          }
 638      }
 639  
 640      return(error);
 641  }
 642  
 643  
 644  static int
 645  Plc_ExportAmps(Plc *this, int compId, int id, char *name)
 646  {
 647      int                         error, i;
 648      Amp                         *pAmp;
 649  
 650      error = hal_pin_u32_newf(HAL_IO, &this->ampReadyDelay, compId,
 651  			     "boss_plc.%d.amp-ready-delay", id);
 652  
 653      pAmp = this->amps;
 654      for(i = 0; i < NUM_AXIS && !error; i++, pAmp++){
 655          error = Amp_Export(pAmp, compId, id, name, axisNames[i]);
 656      }
 657  
 658      return(error);
 659  }
 660  
 661  
 662  static int
 663  Plc_ExportSpindle(Plc *this, int compId, int id, char *name)
 664  {
 665      int                         error;
 666  
 667      // Export parameters.
 668      error = hal_pin_u32_newf(HAL_IO, &this->brakeOnDelay, compId,
 669  			     "boss_plc.%d.brake-on-delay", id);
 670  
 671      if(!error){
 672          error = hal_pin_u32_newf(HAL_IO, &this->brakeOffDelay, compId,
 673  				 "boss_plc.%d.brake-off-delay", id);
 674      }
 675  
 676      if(!error){
 677          error = hal_pin_float_newf(HAL_IO, &this->spindleLoToHi, compId,
 678  				   "boss_plc.%d.spindle-lo-to-hi", id);
 679      }
 680  
 681      // Export optional parameters.
 682      if(debug > 0){
 683          if(!error){
 684              error = hal_param_u32_newf(HAL_RO, &this->spindleState, compId,
 685  				       "boss_plc.%d.spindle-state", id);
 686          }
 687      }
 688  
 689      // Export pins.
 690      if(!error){
 691          error = hal_pin_float_newf(HAL_IN, &this->pSpindleSpeedIn, compId,
 692  				   "boss_plc.%d.spindle-speed-in", id);
 693      }
 694  
 695      if(!error){
 696          error = hal_pin_bit_newf(HAL_IN, &this->pSpindleIsOnIn, compId,
 697  				 "boss_plc.%d.spindle-is-on-in", id);
 698      }
 699  
 700      if(!error){
 701          error = hal_pin_bit_newf(HAL_OUT, &this->pSpindleFwdOut, compId,
 702  				 "boss_plc.%d.spindle-fwd-out", id);
 703      }
 704  
 705      if(!error){
 706          error = hal_pin_bit_newf(HAL_OUT, &this->pSpindleRevOut, compId,
 707  				 "boss_plc.%d.spindle-rev-out", id);
 708      }
 709  
 710      if(!error){
 711          error = hal_pin_bit_newf(HAL_IN, &this->pSpindleIncIn, compId,
 712  				 "boss_plc.%d.spindle-inc-in", id);
 713      }
 714  
 715      if(!error){
 716          error = hal_pin_bit_newf(HAL_IN, &this->pSpindleDecIn, compId,
 717  				 "boss_plc.%d.spindle-dec-in", id);
 718      }
 719  
 720      if(!error){
 721          error = hal_pin_bit_newf(HAL_OUT, &this->pSpindleIncOut, compId,
 722  				 "boss_plc.%d.spindle-inc-out", id);
 723      }
 724  
 725      if(!error){
 726          error = hal_pin_bit_newf(HAL_OUT, &this->pSpindleDecOut, compId,
 727  				 "boss_plc.%d.spindle-dec-out", id);
 728      }
 729  
 730      if(!error){
 731          error = hal_pin_bit_newf(HAL_IN, &this->pBrakeEnIn, compId,
 732  				 "boss_plc.%d.brake-en-in", id);
 733      }
 734  
 735      if(!error){
 736          error = hal_pin_bit_newf(HAL_OUT, &this->pBrakeEnOut, compId,
 737  				 "boss_plc.%d.brake-en-out", id);
 738      }
 739  
 740      return(error);
 741  }
 742  
 743  
 744  static int
 745  Plc_ExportJog(Plc *this, int compId, int id, char *name)
 746  {
 747      int                         error, i;
 748  
 749      // Export parameters.
 750      for(i = 0, error = 0; i < NUM_JOG_SEL && !error; i++){
 751          error = hal_pin_float_newf(HAL_IO, &this->jogScale[i], compId,
 752  				   "boss_plc.%d.jog-scale-%d", id, i);
 753      }
 754  
 755      if(!error){
 756          for(i = 0; i < NUM_JOG_SEL && !error; i++){
 757              error = hal_pin_bit_newf(HAL_IN, &this->pJogSelIn[i], compId,
 758  				     "boss_plc.%d.jog-sel-in-%d", id, i);
 759          }
 760      }
 761  
 762      // Export pins.
 763      if(!error){
 764          error = hal_pin_float_newf(HAL_OUT, &this->pJogScaleOut, compId,
 765  				   "boss_plc.%d.jog-scale-out", id);
 766      }
 767  
 768      return(error);
 769  }
 770  
 771  
 772  /*
 773   * HAL EXPORTED FUNCTIONS
 774   */
 775  
 776  static void
 777  Plc_Refresh(void *arg, long period)
 778  {
 779      Plc                         *this = (Plc *)arg;
 780  
 781      Plc_RefreshFeed(this, period);
 782      Plc_RefreshLimits(this, period);
 783      Plc_RefreshAmps(this, period);
 784      Plc_RefreshSpindle(this, period);
 785      Plc_RefreshJog(this, period);
 786  }
 787  
 788  
 789  static void
 790  Plc_RefreshFeed(Plc *this, long period)
 791  {
 792      BOOL                        riseCycleStart;
 793  
 794      riseCycleStart = !this->lastCycleStart && *this->pCycleStartIn;
 795      this->lastCycleStart = *this->pCycleStartIn;
 796  
 797      // Condition feed hold so machine waits for cycle start and spindle to be
 798      // running if it is enabled.
 799      *this->pFeedHoldOut = *this->pCycleHoldIn
 800                              || (*this->pSpindleSpeedIn && !*this->pSpindleIsOnIn)
 801                              || (*this->pSpindleIsOnIn
 802                                  && (this->lastSpindleSpeed != *this->pSpindleSpeedIn))
 803                              || (*this->pFeedHoldOut && !riseCycleStart);
 804      this->lastSpindleSpeed = *this->pSpindleSpeedIn;
 805  
 806      // Limit rapid/feed to 1% when limits are being overriden.
 807      if(*this->pLimitOverrideIn && (*this->pAdaptiveFeedIn > 0.01))
 808          *this->pAdaptiveFeedOut = 0.01;
 809      else
 810          *this->pAdaptiveFeedOut = *this->pAdaptiveFeedIn;
 811  
 812      // Wait for cycle start to acknowledge tool change.
 813      *this->pToolChangedOut = (*this->pToolChangeIn && riseCycleStart)
 814                              || (*this->pToolChangedOut && *this->pToolChangeIn);
 815  
 816      // Indicates waiting for user to press cycle start.
 817      *this->pWaitUserOut = *this->pFeedHoldOut
 818                              || (*this->pToolChangeIn && !*this->pToolChangedOut);
 819  
 820      // Turn coolant off during tool changes.
 821      *this->pMistOnOut = *this->pMistOnIn && !*this->pToolChangeIn;
 822      *this->pFloodOnOut = *this->pFloodOnIn && !*this->pToolChangeIn;
 823  }
 824  
 825  
 826  static void
 827  Plc_RefreshLimits(Plc *this, long period)
 828  {
 829      Limit_Refresh(&this->xLimit, *this->pLimitOverrideIn);
 830      Limit_Refresh(&this->yLimit, *this->pLimitOverrideIn);
 831  
 832      // Condition Z limits with override in manual mode.
 833      *this->pZLimitPosOut = *this->pZLimitPosIn
 834                              && !(*this->pZJogEnIn && *this->pLimitOverrideIn);
 835      *this->pZLimitNegOut = *this->pZLimitNegIn
 836                              && !(*this->pZJogEnIn && *this->pLimitOverrideIn);
 837  
 838      // Generate limit active signal for pilot lamp.
 839      *this->pLimitActiveOut = Limit_IsActive(&this->xLimit)
 840                              || Limit_IsActive(&this->yLimit)
 841                              || *this->pZLimitPosIn || *this->pZLimitNegIn;
 842  }
 843  
 844  
 845  static void
 846  Plc_RefreshAmps(Plc *this, long period)
 847  {
 848      int                         i;
 849      Amp                         *pAmp;
 850  
 851      pAmp = this->amps;
 852      for(i = 0; i < NUM_AXIS; i++, pAmp++){
 853          Amp_Refresh(pAmp, period, *(this->ampReadyDelay));
 854      }
 855  }
 856  
 857  static void
 858  Plc_RefreshSpindle(Plc *this, long period)
 859  {
 860      Timer_Update(&this->spindleTimer, period);
 861  
 862      switch(this->spindleState){
 863      // Spindle is off, brake is on.
 864      case SS_OFF:
 865          if(!*this->pBrakeEnIn){
 866              this->spindleState = SS_WAIT_BRAKE_OFF;
 867              *this->pBrakeEnOut = 0;
 868              Timer_SetTimeout(&this->spindleTimer, *(this->brakeOffDelay));
 869              Timer_Enable(&this->spindleTimer, TM_ONE_SHOT);
 870          }
 871          break;
 872  
 873      // Spindle is off, brake has been turned off. Wait at least a brake off
 874      // delay before turning spindle on.
 875      case SS_WAIT_BRAKE_OFF:
 876          if(*this->pBrakeEnIn){
 877              this->spindleState = SS_OFF;
 878              *this->pBrakeEnOut = 1;
 879              Timer_Disable(&this->spindleTimer);
 880  
 881          }else if((*this->pSpindleSpeedIn != 0.0)
 882                   && !Timer_IsEnabled(&this->spindleTimer)){
 883  
 884              this->spindleState = SS_WAIT_ON;
 885  
 886              if(*this->pSpindleSpeedIn > *(this->spindleLoToHi)
 887                || (*this->pSpindleSpeedIn < 0.0
 888                  && *this->pSpindleSpeedIn >= -*(this->spindleLoToHi))){
 889  
 890                  *this->pSpindleFwdOut = 1;
 891              }else{
 892                  *this->pSpindleRevOut = 1;
 893              }
 894          }
 895          break;
 896  
 897      // Spindle has been turned on. Wait for confirmation that it is running.
 898      case SS_WAIT_ON:
 899          if(*this->pSpindleIsOnIn){
 900              this->spindleState = SS_ON;
 901  
 902          }else if(*this->pSpindleSpeedIn == 0.0){
 903              this->spindleState = SS_WAIT_BRAKE_OFF;
 904  
 905              *this->pSpindleFwdOut = 0;
 906              *this->pSpindleRevOut = 0;
 907          }
 908          break;
 909  
 910      // Spindle is running.
 911      case SS_ON:
 912          if(*this->pSpindleSpeedIn == 0.0){
 913              this->spindleState = SS_WAIT_OFF;
 914  
 915              *this->pSpindleFwdOut = 0;
 916              *this->pSpindleRevOut = 0;
 917          }
 918          break;
 919  
 920      // Spindle has been turned off. Wait for confirmation.
 921      case SS_WAIT_OFF:
 922          if(!*this->pSpindleIsOnIn){
 923              this->spindleState = SS_WAIT_BRAKE_ON;
 924  
 925              Timer_SetTimeout(&this->spindleTimer, *(this->brakeOnDelay));
 926              Timer_Enable(&this->spindleTimer, TM_ONE_SHOT);
 927          }
 928          break;
 929  
 930      case SS_WAIT_BRAKE_ON:
 931          if(!Timer_IsEnabled(&this->spindleTimer)){
 932              this->spindleState = SS_WAIT_BRAKE_OFF;
 933          }
 934          break;
 935  
 936      default:
 937          this->spindleState = SS_WAIT_OFF;
 938  
 939          *this->pSpindleFwdOut = 0;
 940          *this->pSpindleRevOut = 0;
 941      }
 942  
 943      // Condition spindle increase and decrease so they are disabled when
 944      // spindle is not running and both cannot be enabled at the same time.
 945      *this->pSpindleIncOut = *this->pSpindleIncIn && !*this->pSpindleDecIn
 946                              && *this->pSpindleIsOnIn;
 947      *this->pSpindleDecOut = *this->pSpindleDecIn && !*this->pSpindleIncIn
 948                              && *this->pSpindleIsOnIn;
 949  }
 950  
 951  
 952  static void
 953  Plc_RefreshJog(Plc *this, long period)
 954  {
 955      int                         i;
 956  
 957      // Jog scale.
 958      for(i = 0; i < NUM_JOG_SEL; i++){
 959          if(*this->pJogSelIn[i]){
 960              *this->pJogScaleOut = *(this->jogScale[i]);
 961              break;
 962          }
 963      }
 964  }
 965  
 966  
 967  /******************************************************************************
 968   * LIMIT OBJECT FUNCTION DEFINITIONS
 969   ******************************************************************************/
 970  
 971  static int
 972  Limit_Export(Limit *this, int compId, int id, char *name, char axis)
 973  {
 974      int                         error;
 975  
 976      error = hal_pin_float_newf(HAL_IN, &this->pPositionIn, compId,
 977  			       "boss_plc.%d.%c-position-in", id, axis);
 978  
 979      if(!error){
 980          error = hal_pin_bit_newf(HAL_IN, &this->pJogEnIn, compId,
 981  				 "boss_plc.%d.%c-jog-en-in", id, axis);
 982      }
 983  
 984      if(!error){
 985          error = hal_pin_bit_newf(HAL_IN, &this->pIn, compId,
 986  				 "boss_plc.%d.%c-limit-in", id, axis);
 987      }
 988  
 989      if(!error){
 990          error = hal_pin_bit_newf(HAL_OUT, &this->pPosOut, compId,
 991  				 "boss_plc.%d.%c-limit-pos-out", id, axis);
 992      }
 993  
 994      if(!error){
 995          error = hal_pin_bit_newf(HAL_OUT, &this->pNegOut, compId,
 996  				 "boss_plc.%d.%c-limit-neg-out", id, axis);
 997      }
 998  
 999      return(error);
1000  }
1001  
1002  
1003  static void
1004  Limit_Init(Limit *this)
1005  {
1006      this->state = LS_INIT;
1007  }
1008  
1009  
1010  static BOOL
1011  Limit_IsActive(Limit *this)
1012  {
1013      return(*this->pIn);
1014  }
1015  
1016  static void
1017  Limit_Refresh(Limit *this, hal_bit_t override)
1018  {
1019      switch(this->state){
1020      case LS_INIT:
1021      default:
1022          this->state = LS_ON_LIMIT;
1023          this->limitNeg = this->limitPos = 1;
1024          this->position = *this->pPositionIn;
1025          // Fall through.
1026  
1027      case LS_ON_LIMIT:
1028          if(*this->pIn == 0){
1029              this->limitNeg = this->limitPos = 0;
1030  
1031              if(*this->pPositionIn == this->position)
1032                  this->state = LS_NO_MOTION;
1033              else if(*this->pPositionIn > this->position)
1034                  this->state = LS_POS_MOTION;
1035              else if(*this->pPositionIn < this->position)
1036                  this->state = LS_NEG_MOTION;
1037          }
1038          break;
1039  
1040      case LS_NO_MOTION:
1041          if(*this->pIn){
1042              this->state = LS_ON_LIMIT;
1043              this->limitNeg = this->limitPos = 1;
1044          }else if(*this->pPositionIn > this->position){
1045              this->state = LS_POS_MOTION;
1046          }else if(*this->pPositionIn < this->position){
1047              this->state = LS_NEG_MOTION;
1048          }
1049          break;
1050  
1051      case LS_POS_MOTION:
1052          if(*this->pIn){
1053              this->state = LS_ON_LIMIT;
1054              this->limitPos = 1;
1055          }else if(*this->pPositionIn == this->position){
1056              this->state = LS_NO_MOTION;
1057          }else if(*this->pPositionIn < this->position){
1058              this->state = LS_NEG_MOTION;
1059          }
1060          break;
1061  
1062      case LS_NEG_MOTION:
1063          if(*this->pIn){
1064              this->state = LS_ON_LIMIT;
1065              this->limitNeg = 1;
1066          }else if(*this->pPositionIn == this->position){
1067              this->state = LS_NO_MOTION;
1068          }else if(*this->pPositionIn > this->position){
1069              this->state = LS_POS_MOTION;
1070          }
1071          break;
1072      }
1073  
1074      this->position = *this->pPositionIn;
1075  
1076      // Condition limits with override in manual mode.
1077      *this->pPosOut = this->limitPos && !(*this->pJogEnIn && override);
1078      *this->pNegOut = this->limitNeg && !(*this->pJogEnIn && override);
1079  }
1080  
1081  
1082  /******************************************************************************
1083   * AMP OBJECT FUNCTION DEFINITIONS
1084   ******************************************************************************/
1085  
1086  static int
1087  Amp_Export(Amp *this, int compId, int id, char *name, char axis)
1088  {
1089      int                         error;
1090  
1091      error = hal_pin_bit_newf(HAL_IN, &this->pEnableIn, compId,
1092  			     "boss_plc.%d.%c-amp-enable-in", id, axis);
1093  
1094      if(!error){
1095          error = hal_pin_bit_newf(HAL_IN, &this->pReadyIn, compId,
1096  				 "boss_plc.%d.%c-amp-ready-in", id, axis);
1097      }
1098  
1099      if(!error){
1100          error = hal_pin_bit_newf(HAL_OUT, &this->pFaultOut, compId,
1101  				 "boss_plc.%d.%c-amp-fault-out", id, axis);
1102      }
1103  
1104      return(error);
1105  }
1106  
1107  
1108  static void
1109  Amp_Init(Amp *this)
1110  {
1111      // Initialize variables.
1112      this->lastEnable = 0;
1113  
1114      // Initialize timer.
1115      Timer_Init(&this->timer);
1116  }
1117  
1118  
1119  static void
1120  Amp_Refresh(Amp *this, long period, hal_u32_t readyDelay)
1121  {
1122      Timer_Update(&this->timer, period);
1123  
1124      if(*this->pEnableIn){
1125          if(!this->lastEnable){
1126              Timer_SetTimeout(&this->timer, readyDelay);
1127              Timer_Enable(&this->timer, TM_ONE_SHOT);
1128          }
1129      } else {
1130          Timer_Disable(&this->timer);
1131      }
1132  
1133      *this->pFaultOut = *this->pEnableIn && !*this->pReadyIn
1134                          && !Timer_IsEnabled(&this->timer);
1135  
1136      this->lastEnable = *this->pEnableIn;
1137  }
1138  
1139  
1140  /******************************************************************************
1141   * TIMER OBJECT FUNCTION DEFINITIONS
1142   ******************************************************************************/
1143  
1144  static void
1145  Timer_Init(Timer *this)
1146  {
1147      this->enabled = FALSE;
1148      this->pTimeout = NULL;
1149  }
1150  
1151  static void
1152  Timer_Enable(Timer *this, TimerMode mode)
1153  {
1154      this->mode = mode;
1155      this->enabled = TRUE;
1156      this->count = 0;
1157  }
1158  
1159  
1160  static void
1161  Timer_Disable(Timer *this)
1162  {
1163      this->enabled = FALSE;
1164  }
1165  
1166  
1167  static BOOL
1168  Timer_IsEnabled(Timer *this)
1169  {
1170      return(this->enabled);
1171  }
1172  
1173  
1174  static void
1175  Timer_Update(Timer *this, long period)
1176  {
1177      if(!this->enabled)
1178          return;
1179  
1180      this->nSec += period;
1181  
1182      if(this->nSec > 1000000){
1183          this->count += this->nSec / 1000000;
1184          this->nSec %= 1000000;
1185      }
1186  
1187      if(this->count >= this->timeout){
1188          if(this->pTimeout != NULL)
1189              this->pTimeout(this->pArgs);
1190  
1191          if(this->mode != TM_CONTINUOUS){
1192              this->enabled = FALSE;
1193          }else{
1194              this->count -= this->timeout;
1195          }
1196      }
1197  }
1198  
1199  
1200  static void
1201  Timer_SetTimeout(Timer *this, hal_u32_t timeout)
1202  {
1203      this->count = 0;
1204      this->timeout = timeout;
1205  }
1206  
1207  
1208  #if 0
1209  static void
1210  Timer_SetCallback(Timer *this, TIMER_ROUTINE pCallback, void *pArgs)
1211  {
1212      this->pTimeout = pCallback;
1213      this->pArgs = pArgs;
1214  }
1215  #endif