Commands
Executing Commands without a Response
This model applies when a module needs to send a command to another module, and does not need to receive a response or confirmation. It’s a one-way channel. Here we have a motor subsystem that subscribes to a global PowerAllOn command.
Subsystem
The subsystem is responsible for running the command. It subscribes to the command that it implements. The motor.cmd.PowerOn
boolean will be set when a command is executed. Response from the subscribing system is not required.
// MotorManager
PROGRAM _INIT
//Register a subsystems command to a global command
// Here:
// - The global command is "PowerAllOn"
// - The subsystem is Axis
// - The command bit is motor.cmd.powerOn
//Subscribe a single command to two different global events
subscribeCommand( gCommands.PowerAllOn, 'Axis', motor.cmd.powerOn );
subscribeCommand( gCommands.PowerAxesOn, 'Axis', motor.cmd.powerOn );
//Subscribe a second command to a different event
subscribeCommand( gCommands.HomeAllOn, 'Axis', motor.cmd.home );
END_PROGRAM
PROGRAM _CYCLIC
//Implement Commands
IF motor.cmd.powerOn THEN
powerOnFub.Enable := TRUE;
IF motor.cmd.powerOff THEN
powerOnFub.Enable := FALSE;
ELSIF motor.cmd.home THEN
home.execute := TRUE;
END_IF
powerOnFub();
home();
home.execute := 0;
//Reset command
motor.cmd.powerOn := 0;
motor.cmd.powerOff := 0;
END_PROGRAM
Executer
A process controller can execute a command that many listeners can listen for.
PROGRAM _CYCLIC
IF powerAll THEN
powerAll := 0;
executeCommand( gCommands.PowerAllOn );
END_IF
END_PROGRAM
Executing Commands with a Response
This model is useful when the executer needs a status response for the command that it issues. This type of command/response communication is modeled after the PLCOpen FUBs: the executer sets an execute
bit, and the subsystem responds with one of several status bits: busy
, done
, or error
. Here the same motor subsystem is used as above.
Subsystem
The subsystem is responsible for running the command. It subscribes to the command that it implements. The motor.cmd.powerOn
boolean will be set when a command is executed. Response from the subscribing system is required.
The motor.PLCOpen
parameter is of type AtnPlcOpenStatus, and is used in code to report back on the status of the command.
// MotorManager
PROGRAM _INIT
//Register a subsystems command to a global command
// Here:
// - The global command is "PowerAllOn"
// - The subsystem is Axis
// - The command bit is gMotor.cmd.powerOn
// - The plcopen status is returned using motor.PLCOpen.status
//Subscibe to an axis Command
subscribePLCOpen( gCommands.PowerAllOn, 'Axis', motor.cmd.powerOn, motor.PLCOpen );
END_PROGRAM
PROGRAM _CYCLIC
//Implement Command
IF motor.cmd.powerOn THEN
state := POWERON;
END_IF
CASE state OF
IDLE:
//Do nothing
POWERON:
powerOnFub.enable := TRUE;
IF powerOnFub.isPowered THEN
state := IDLE;
motor.PLCOpen.status := ERR_OK;
ELSIF powerOnFub.Error THEN
state := IDLE;
powerOnFub.enable := FALSE;
motor.PLCOpen.status := MOTOR_ERROR;
END_IF
END_CASE
powerOnFub();
END_PROGRAM
Executer
A process controller can execute a command that many listeners can listen for. With the PLCOpen format, the executer can listen for a response from the subsystem.
The PLCOpenCommand
is of type AtnPLCOpen. PLCOpenCommand.command
specifies the string that represents the command to execute, and then the FUB can be called cyclically as any other PLCOpen FUB would be called. When its .execute
is set, ATN sends the command to the subsystem, and the executer can monitor the status via PLCOpenCommand.busy
, PLCOpenCommand.done
, and PLCOpenCommand.error
.
PROGRAM _CYCLIC
CASE state OF
IDLE:
//Do nothing
SEQ_POWERALL:
IF PLCOpenCommand.done THEN
state := SEQ_NEXT_STEP;
ELSIF PLCOpenCommand.error OR PLCOpenCommand.aborted THEN
state := IDLE;
RaiseError( 'Error Powering on' );
ELSIF NOT PLCOpenCommand.busy THEN
PLCOpenCommand.Execute := TRUE;
END_IF
SEQ_NEXT_STEP:
..
END_CASE
PLCOpenCommand.command := gCommands.PowerAllOn;
PLCOpenCommand();
PLCOpenCommand.Execute := FALSE;
END_PROGRAM