WITH text_io ; USE text_io ; -- make text input/output available -- robot_handler => Package definition for simple robot simulation. PACKAGE robot_handler IS -- Package Type Definitions : TYPE axis_name IS ( x_axis, y_axis, z_axis ) ; SUBTYPE move_range IS INTEGER RANGE -1000..1000 ; TYPE param_array IS ARRAY ( axis_name ) OF move_range ; -- Package Task Types : -- robot_controller => Task to simulate control of a robot. TASK TYPE robot_controller IS -- Entry points : ENTRY open ; ENTRY single_axis_move ( axis : axis_name ; distance : move_range ) ; ENTRY compound_move ( axis_deltas : param_array ) ; ENTRY close ; END robot_controller ; -- Package Tasks : -- robot_system => To initialise & close down the robot system. TASK robot_system IS -- entries to initialise system & to shut down ENTRY open ; ENTRY close ; END robot_system ; ---------------------------------------------- END robot_handler ; ------------------------------------------------ -- robot_handler => Implementation details for Robot handler package. PACKAGE BODY robot_handler IS -- Local Package Types SUBTYPE uint IS INTEGER RANGE 0..INTEGER'LAST ; -- Inline Procedure Definitions : PROCEDURE putln ( text : STRING ) ; PRAGMA INLINE ( putln ) ; -- putln => output a string followed by a newline PROCEDURE putln ( text : STRING ) IS BEGIN -- putln PUT ( text ) ; NEW_LINE ; END putln ; ----------------------------------------------------- -- id_server => Provide a unique id. number for a robot task. TASK id_server IS -- entries to return an id & terminate task ENTRY generate ( new_id : OUT uint ) ; ENTRY close ; END id_server ; TASK BODY id_server IS -- Local Variables : next_id : uint := 0 ; -- next id no. to be allocated closed : BOOLEAN := FALSE ; -- task terminated ? BEGIN -- id_server -- inform user of task activation putln ( "Task id_server activated." ) ; LOOP -- loop until task terminated SELECT -- wait for an entry call -- return a robot identication number ACCEPT generate ( new_id : OUT uint ) DO new_id := next_id ; PUT ( "Task id_server allocating id no " ) ; PUT ( uint'IMAGE ( next_id ) ) ; NEW_LINE ; next_id := next_id + 1 ; END generate ; OR -- terminate loop & hence task ACCEPT close DO closed := TRUE ; END close ; END SELECT ; -- exit as soon as closed is set TRUE EXIT WHEN closed ; END LOOP ; putln ( "Task id_server terminating." ) ; END id_server ; ------------------------------------------------- -- robot_system => Task body for opening/closing robot system. TASK BODY robot_system IS -- Local Variables : closed : BOOLEAN := FALSE ; -- has a close been encountered ? BEGIN -- robot_system -- inform user of task activation putln ( "Task robot_system activated." ) ; LOOP -- loop until a close is encountered SELECT -- wait for an entry call ACCEPT open DO putln ( "Opening robot system." ) ; END open ; OR ACCEPT close DO putln ( "Closing robot system." ) ; id_server.close ; closed := TRUE ; END close ; END SELECT ; -- exit as soon as closed is set TRUE EXIT WHEN closed ; END LOOP ; putln ( "Task robot_system terminating." ) ; END robot_system ; ---------------------------------------------- -- robot_controller => Task body for robot controller simulation. TASK BODY robot_controller IS -- Local Types : TYPE robot_status IS ( dormant, active, closed ) ; TYPE axis_params IS ARRAY ( axis_name ) OF DURATION ; TYPE flag IS ( stopped, moving, error ) ; TYPE axis_status IS ARRAY ( axis_name ) OF flag ; -- Local Task Types : -- axis_controller => Task to simulate control of one axis of a robot. TASK TYPE axis_controller IS -- entries to open, close & move an axis. ENTRY open ( axis : axis_name ) ; ENTRY close ; ENTRY move ( distance : move_range ) ; END axis_controller ; ------------------------------------------- TYPE axes_control IS ARRAY ( axis_name ) OF axis_controller ; -- I/O Package Definitions : PACKAGE mr_io IS NEW INTEGER_IO ( move_range ) ; PACKAGE an_io IS NEW ENUMERATION_IO ( axis_name ) ; USE mr_io , an_io ; -- Local Constants : time_per_unit : CONSTANT axis_params := ( 0.05, 0.07, 0.09 ) ; -- Local Variables : robot_ident : uint ; -- robot identification number status : axis_status ; -- flags used by axis controller tasks controller : axes_control ; -- array of axis controller tasks robot_state : robot_status := dormant ; axis_deltas : param_array := ( OTHERS => 0 ) ; -- Local Functions : -- axis_stopped => Check if specified axis is not moving. FUNCTION axis_stopped ( axis : axis_name ) RETURN BOOLEAN IS BEGIN -- axis_stopped -- check if axis is stopped or in error condition RETURN ( ( status ( axis ) = stopped ) OR ( status ( axis ) = error ) ) ; END axis_stopped ; ---------------------------------------------- -- all_axes_stopped => Check if all axes have stopped moving FUNCTION all_axes_stopped RETURN BOOLEAN IS -- Local Variables : -- combined flags for all axes res : BOOLEAN := TRUE ; -- initialise to TRUE BEGIN -- all_axes_stopped -- loop through all axes and check whether stopped or error FOR axis IN axis_name LOOP res := ( res AND axis_stopped ( axis ) ) ; END LOOP ; -- return result RETURN res ; END all_axes_stopped ; ------------------------------------------ -- Task Bodies : -- axis_controller => Task to control a single robot axis. TASK BODY axis_controller IS -- Local Variables : -- axis closed flag closed : BOOLEAN := FALSE ; -- initialise to FALSE -- local storage for distance axis to move by move_by : move_range := 0 ; -- initialise to zero for safety -- local storage for axis being controlled controlled_axis : axis_name ; -- axis moving flag axis_moving : BOOLEAN := FALSE ; -- axis not moving initially BEGIN -- axis_controller -- announce task start up, at the moment not assigned to any axis putln ( "Axis controller task activated." ) ; LOOP -- loop until EXIT statement executed SELECT -- wait for an entry call -- handle open case ACCEPT open ( axis : axis_name ) DO PUT ( axis ) ; putln ( " axis controller : axis opened O.K." ) ; status ( axis ) := stopped ; controlled_axis := axis ; END open ; OR -- handle close case ACCEPT close DO PUT ( controlled_axis ) ; putln ( " axis controller : axis closed O.K." ) ; status ( controlled_axis ) := stopped ; closed := TRUE ; END close ; OR -- handle move case ACCEPT move ( distance : move_range ) DO status ( controlled_axis ) := moving ; move_by := distance ; axis_moving := TRUE ; END move ; END SELECT ; -- exit loop & hence task as soon as axis is closed EXIT WHEN closed ; -- simulate a movement of the axis if required IF axis_moving THEN PUT ( controlled_axis ) ; putln ( " axis controller : axis movement starting." ) ; DELAY ABS ( move_by ) * time_per_unit ( controlled_axis ) ; PUT ( controlled_axis ) ; putln ( " axis controller : axis movement finished." ) ; status ( controlled_axis ) := stopped ; move_by := 0 ; axis_moving := FALSE ; END IF ; END LOOP ; -- inform user that task is terminating PUT ( controlled_axis ) ; putln ( " axis controller task terminating." ) ; END axis_controller ; ------------------------------------------- BEGIN -- robot_controller -- get an identification number for this robot id_server.generate ( robot_ident ) ; -- inform user of task startup PUT ( "Robot no. " ) ; PUT ( robot_ident ) ; putln ( " controller task starting." ) ; LOOP -- loop until Robot is closed down SELECT -- wait for an entry call -- opening robot ACCEPT open DO -- initialise all axes FOR axis IN axis_name LOOP controller ( axis ).open ( axis ) ; END LOOP ; -- inform user that open has occured putln ( "Robot controller : Robot opened O.K." ) ; robot_state := active ; END open ; OR -- closing robot ACCEPT close DO -- shut down all axes FOR axis IN axis_name LOOP controller ( axis ).close ; END LOOP ; -- inform user that close has occured putln ( "Robot controller : Robot closed O.K." ) ; robot_state := closed ; END close ; OR -- single axis move ACCEPT single_axis_move ( axis : axis_name ; distance : move_range ) DO -- inform user of single axis move putln ( "Robot controller : single axis move." ) ; -- make entry call to appropriate task for move controller ( axis ).move ( distance ) ; -- loop until axis stops moving LOOP EXIT WHEN axis_stopped ( axis ) ; END LOOP ; END single_axis_move ; OR -- compound move ACCEPT compound_move ( axis_deltas : param_array ) DO -- inform user of compound move putln ( "Robot controller : compound move." ) ; -- use all axis tasks FOR axis IN axis_name LOOP controller ( axis ).move ( axis_deltas ( axis ) ) ; END LOOP ; -- loop until all axes have stopped moving LOOP EXIT WHEN all_axes_stopped ; END LOOP ; END compound_move ; END SELECT ; -- exit loop when robot has been closed down EXIT WHEN robot_state = closed ; END LOOP ; -- inform user that robot controller task is terminating putln ( "Robot controller : task terminating." ) ; END robot_controller ; ------------------------------------------ END robot_handler ; ------------------------------------------------