B Cancelling in multi-task subsystems

 B.1 Controlling task
 B.2 Controlled task

This example was provided by Ian Smith (ROE). When the controlling task receives a CANCEL, it sends a CANCEL to the subsidiary task. The controlling task then requests ACT__MESSAGE to wait for the final acknowledgement from the OBEY in the subsidiary task. The final completion status from the subsidiary task is obtained by the controlling task by the call to TASK_GET_REASON, irrespective of whether the final completion was due to a CANCEL.

B.1 Controlling task

  interface cmotask
  #  Motor task controller
     parameter motor
        type ’_char’
        in ’FILTER_WHEEL’, ’FOCUS_WHEEL’
        prompt ’which wheel - FILTER_WHEEL or FOCUS_WHEEL?’
     endparameter
     action motor_control
        obey
           needs motor
        endobey
        cancel
           needs motor
        endcancel
     endaction
  endinterface
  
        SUBROUTINE CMOTASK( STATUS )
  
  *     Control the task Motask which moves 2 imaginary motors
  
        IMPLICIT NONE              ! No implicit typing
  
        INCLUDE ’SAE_PAR’          ! Standard SAE constants
        INCLUDE ’ADAMDEFNS’
        INCLUDE ’MESSYS_ERR’
        INCLUDE ’ACT_ERR’
        INCLUDE ’DTASK_ERR’
  
        INTEGER STATUS             ! modified status
        INTEGER CONTEXT            ! context OBEY or CANCEL
        INTEGER SEQ                ! action sequence number
        INTEGER GOOD_STATUS        ! local status
        INTEGER MOTASK_PATH        ! path to subsidiary task
        INTEGER MOTASK_MESSID      ! message id
        CHARACTER*80 MOTOR         ! name of motor to be moved
        CHARACTER*80 INVAL         ! parameter string sent
        CHARACTER*80 OUTVAL        ! parameter string returned
        INTEGER REASON             ! subsidiary completion status
  
        IF ( STATUS .NE. SAI__OK ) RETURN
  
        GOOD_STATUS = SAI__OK
        CALL TASK_GET_CONTEXT ( CONTEXT, STATUS )
        IF ( CONTEXT .EQ. OBEY ) THEN
           CALL TASK_GET_SEQ ( SEQ, STATUS )
           IF ( SEQ .EQ. 0 ) THEN
              CALL PAR_GET0C ( ’MOTOR’, MOTOR, STATUS )
              INVAL = ’ ’
              CALL TASK_OBEY ( ’MOTASK’, MOTOR, INVAL, OUTVAL,
       :        MOTASK_PATH, MOTASK_MESSID, STATUS )
              IF ( STATUS .EQ. DTASK__ACTSTART ) THEN
                 STATUS = SAI__OK
                 CALL TASK_ADD_MESSINFO ( MOTASK_PATH, MOTASK_MESSID,
       :           STATUS )
                 CALL TASK_PUT_REQUEST ( ACT__MESSAGE, STATUS )
              ELSE
                 CALL MSG_SETC ( ’MOTOR’, MOTOR )
                 CALL ERR_REP ( ’ ’, ’^MOTOR FAILED’, STATUS )
              END IF
           ELSE
              CALL TASK_GET_REASON ( REASON, STATUS )
              IF ( REASON .EQ. DTASK__ACTCANCEL ) THEN
                 CALL MSG_OUT ( ’ ’,
       :           ’CMOTASK: subsidiary task has been cancelled’,
       :           STATUS )
              ELSE IF ( REASON .NE. DTASK__ACTCOMPLETE ) THEN
                 STATUS = REASON
                 CALL ERR_REP ( ’ ’,
       :           ’CMOTASK: subsidiary task has returned bad status’,
       :           STATUS )
              END IF
           END IF
        ELSE IF ( CONTEXT .EQ. CANCEL ) THEN
           CALL TASK_CANCEL ( ’MOTASK’, MOTOR, INVAL, OUTVAL, STATUS )
           IF ( STATUS .EQ. DTASK__ACTCANCEL ) THEN
              STATUS = SAI__OK
              CALL TASK_PUT_REQUEST ( ACT__MESSAGE, STATUS )
           ELSE
              CALL ERR_REP ( ’ ’, ’CMOTASK: failure cancelling MOTASK’,
       :        STATUS )
           ENDIF
        END IF
  
        CALL PAR_CANCL ( ’MOTOR’, GOOD_STATUS )
  
        END

B.2 Controlled task

  interface motask
     parameter filter
        type ’_integer’
        range 1,100
     endparameter
     parameter focus
        type ’_integer’
        range 1,100
     endparameter
     action filter_wheel
        obey
           needs filter
        endobey
        cancel
        endcancel
     endaction
     action focus_wheel
        obey
           needs focus
        endobey
        cancel
        endcancel
     endaction
  endinterface
  
        SUBROUTINE MOTASK( STATUS )
  
  *     Task to drive 2 dummy motors. One called FILTER_WHEEL
  *     and the other FOCUS. Each invocation requires 1 parameter
  *     relating to requested position but will be used in the call to the
  *     delay routine for a delay of n seconds
  
        IMPLICIT NONE              ! No implicit typing
  
        INCLUDE ’SAE_PAR’
        INCLUDE ’ACT_ERR’
        INCLUDE ’ADAMDEFNS’
  
        INTEGER STATUS
        INTEGER CONTEXT
        INTEGER SEQ
        INTEGER FILTER
        INTEGER FOCUS
        INTEGER PERIOD
        CHARACTER*(PAR__SZNAM) NAME
  
        SAVE FILTER
        SAVE FOCUS
  
        IF ( STATUS .NE. SAI__OK ) RETURN
  
        CALL TASK_GET_NAME ( NAME, STATUS )
  
        IF ( NAME .EQ. ’FILTER_WHEEL’ ) THEN
           CALL TASK_GET_CONTEXT ( CONTEXT, STATUS )
           IF ( CONTEXT .EQ. OBEY ) THEN
              CALL TASK_GET_SEQ ( SEQ, STATUS )
              IF ( SEQ .EQ. 0 ) THEN
                 CALL PAR_GET0I ( ’FILTER’, FILTER, STATUS )
                 PERIOD = FILTER * 1000
                 CALL MSG_SETI ( ’FILTER’, FILTER )
                 CALL MSG_OUT ( ’ ’, ’moving to filter ^FILTER...’,
       :           STATUS )
                 CALL TASK_PUT_DELAY ( PERIOD, STATUS )
                 CALL PAR_CANCL ( ’FILTER’, STATUS )
                 CALL TASK_PUT_REQUEST ( ACT__WAIT, STATUS )
              ELSE
                 CALL MSG_SETI ( ’FILTER’, FILTER )
                 CALL MSG_OUT( ’ ’, ’filter position ^FILTER reached’,
       :           STATUS )
              END IF
           ELSE IF ( CONTEXT .EQ. CANCEL ) THEN
              CALL TASK_PUT_REQUEST ( ACT__CANCEL, STATUS )
           END IF
        ELSE IF ( NAME .EQ. ’FOCUS_WHEEL’ ) THEN
           CALL TASK_GET_CONTEXT ( CONTEXT, STATUS )
           IF ( CONTEXT .EQ. OBEY ) THEN
              CALL TASK_GET_SEQ ( SEQ, STATUS )
              IF ( SEQ .EQ. 0 ) THEN
                 CALL PAR_GET0I ( ’FOCUS’, FOCUS, STATUS )
                 PERIOD = FOCUS * 1000
                 CALL MSG_SETI ( ’FOCUS’, FOCUS )
                 CALL MSG_OUT ( ’ ’, ’moving to focus ^FOCUS...’, STATUS )
                 CALL TASK_PUT_DELAY ( PERIOD, STATUS )
                 CALL PAR_CANCL ( ’FOCUS’, STATUS )
                 CALL TASK_PUT_REQUEST ( ACT__WAIT, STATUS )
              ELSE
                 CALL MSG_SETI ( ’FOCUS’, FOCUS )
                 CALL MSG_OUT ( ’ ’, ’focus position ^FOCUS reached’,
       :           STATUS)
              END IF
           ELSE IF ( CONTEXT .EQ. CANCEL ) THEN
              CALL TASK_PUT_REQUEST ( ACT__CANCEL, STATUS )
           END IF
        END IF
        END