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