Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions src/Conveyor/ControlLogic/StopPosition.st
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ NAMESPACE Simatic.Ax.Conveyor
_itemInStopPosition : BOOL;
/// Internal error flag
_hasError : BOOL;
/// Previous error state for edge detection
_hasErrorOld : BOOL;
/// Sensor blocking supervision with timeout detection
_SensorBlocked : Supervision := (behavior := SupervisionBehavior#Reaction);
/// Current startup status
Expand All @@ -48,6 +50,7 @@ NAMESPACE Simatic.Ax.Conveyor
_startedUpRis : BOOL;
_startedUp : BOOL;
_deliveringRis : BOOL;
_errorRis : BOOL;
END_VAR
// Read signals to avoid mutiple method calls
_SensorBlocked.timeout := SensorMonitoringTime;
Expand All @@ -57,6 +60,7 @@ NAMESPACE Simatic.Ax.Conveyor
_stopSensorCovered := StopSensor.Q();
// Detect rising edge of delivering (transfer starts)
_deliveringRis := _delivering AND NOT (_deliveringOld);
_deliveringOld := _delivering;
// Start supervision whenever a transfer is active and monitoring is not yet running
IF (_delivering AND NOT _SensorBlocked.IsActive()) THEN
_SensorBlocked.Start();
Expand All @@ -70,11 +74,10 @@ NAMESPACE Simatic.Ax.Conveyor
_SensorBlocked.Execute(signal := _stopSensorCovered AND _delivering);
// Check for timeout error
_hasError := _SensorBlocked.GetError() = SupervisionError#TIMEOUT;
IF (NOT _hasError AND _delivering AND _stopSensorCovered AND _SensorBlocked.IsActive()) THEN
_hasError := TRUE;
END_IF;
IF (_hasError) THEN
Equipment.SetError(errorState := ErrorState#OtherError, errorText := 'Sensor blocked timeout');
_errorRis := _hasError AND NOT (_hasErrorOld);
_hasErrorOld := _hasError;
IF (_errorRis) THEN
Equipment.SetError(errorState := StopPositionError#SensorBlocked, errorText := 'Sensor blocked timeout');
END_IF;
// Update occupancy logic
IF (_stopSensorCovered AND _startUpStatus = StartUpStatus#AutoStartedUp) THEN
Expand All @@ -89,8 +92,7 @@ NAMESPACE Simatic.Ax.Conveyor
_itemInStopPosition := FALSE;
END_IF;
END_IF;
// Store old delivering value for edge detection
_deliveringOld := _delivering;

EvaluateStopPos := _itemInStopPosition;
END_METHOD
/// Returns whether the stop position is logically occupied
Expand All @@ -117,6 +119,7 @@ NAMESPACE Simatic.Ax.Conveyor
_SensorBlocked.Reset();
// Clear error flag
_hasError := FALSE;
_hasErrorOld := FALSE;
// Reset edge detection flags
_deliveringOld := FALSE;
_startUpStatusOld := FALSE;
Expand Down
11 changes: 11 additions & 0 deletions src/Conveyor/ControlLogic/StopPositionErrors.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
NAMESPACE Simatic.Ax.Conveyor

/// Error codes specific to StopPosition supervision.
TYPE
StopPositionError : WORD (
NoError := WORD#16#0000,
SensorBlocked := WORD#16#8120
) := NoError;
END_TYPE

END_NAMESPACE
4 changes: 2 additions & 2 deletions src/Conveyor/ConveyorBase.st
Original file line number Diff line number Diff line change
Expand Up @@ -242,11 +242,11 @@ NAMESPACE Simatic.Ax.Conveyor
triggerCondition := triggerNextReadyToDeliver OR triggerNextDelivering OR triggerPrevReadyToDeliver OR triggerPrevDelivering OR triggerAutoReleaseEmpty;
result := THIS.RetriggerConveyor(triggerCondition);
IF (NOT triggerCondition AND NOT THIS.IsOccupied()) THEN
_conveyorFollowUpTimeActive := followUpSignal;
_conveyorFollowUpTimeActive := FALSE;
END_IF;
// Stop in case of:
IF THIS.GetStartupStatus() <> StartUpStatus#AutoStartedUp THEN
_conveyorFollowUpTimeActive := FALSE;
_conveyorFollowUpTimeActive := followUpSignal;
END_IF;
// Offdelay for conveyor (Can be probibited by prohibitRunning)
conveyorOffDelay(signal := _conveyorFollowUpTimeActive, duration := OffDelayTime);
Expand Down
20 changes: 4 additions & 16 deletions test/Conveyor/ControlLogic/StopPositionTest.st
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,15 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
sens := sensStateless;
conv := convStateless;
eq := eqStateless;
END_METHOD

/// Helper method to configure test dependencies
METHOD PROTECTED Setup
// Arrange - Wire up dependencies
stop.Equipment := eq;
stop.Deliverer := conv;
stop.StopSensor := sens;
END_METHOD


{Test}
METHOD PUBLIC StopPos_is_not_occupied_when_Q_Sensor_False
// Arrange - Setup with sensor not covered
THIS.Setup();
sens.QValue := FALSE; // Sensor is free

// Act - Evaluate stop position
Expand All @@ -52,7 +47,6 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
{Test}
METHOD PUBLIC StopPos_is_not_occupied_when_Q_Sensor_False_And_Equipment_in_automatic
// Arrange - Setup with sensor free and equipment running
THIS.Setup();
sens.QValue := FALSE; // Sensor is free
eq.MockStatus := StartUpStatus#AutoStartedUp; // Equipment is running

Expand All @@ -66,7 +60,6 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
{Test}
METHOD PUBLIC StopPos_is_not_occupied_when_Q_Sensor_True_and_starting_up
// Arrange - Setup with sensor covered but still starting up
THIS.Setup();
sens.QValue := TRUE; // Sensor is covered
eq.MockStatus := StartUpStatus#AutoStartingUp; // Still starting

Expand All @@ -80,7 +73,6 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
{Test}
METHOD PUBLIC StopPos_is_not_occupied_when_Q_Sensor_True_and_not_released
// Arrange - Setup with sensor covered but not released
THIS.Setup();
sens.QValue := TRUE; // Sensor is covered
eq.MockStatus := StartUpStatus#NotReleased; // Not released

Expand All @@ -94,7 +86,6 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
{Test}
METHOD PUBLIC StopPos_is_occupied_when_Q_Sensor_True_and_is_released
// Arrange - Setup with sensor covered and equipment released
THIS.Setup();
sens.QValue := TRUE; // Sensor is covered
eq.MockStatus := StartUpStatus#AutoStartedUp; // Equipment is running

Expand All @@ -108,7 +99,6 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
{Test}
METHOD PUBLIC Uncover_Sensor_while_equipment_is_still_started_up_keeps_occupied
// Arrange - First establish occupied state
THIS.Setup();
THIS.StopPos_is_occupied_when_Q_Sensor_True_and_is_released();

// Act - Uncover sensor while still running
Expand All @@ -123,7 +113,6 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
{Test}
METHOD PUBLIC Stored_Occuoied_removes_when_state_Changes_from_StartingUp_to_StartedUp
// Arrange - First establish occupied state
THIS.Setup();
THIS.StopPos_is_occupied_when_Q_Sensor_True_and_is_released();

// Act - Uncover sensor and change to starting up
Expand All @@ -141,7 +130,6 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
{Test}
METHOD PUBLIC Sensor_Covered_During_Delivery_Is_Monitored
// Arrange - Setup with sensor covered during delivery
THIS.Setup();
sens.QValue := TRUE; // Sensor is covered
eq.MockStatus := StartUpStatus#AutoStartedUp; // Equipment is running
conv.RTD := DeliverState#Delivering; // Delivery in progress
Expand All @@ -158,7 +146,6 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
{Test}
METHOD PUBLIC Sensor_Remains_Covered_After_Delivery_Completes
// Arrange - First establish occupied state during delivery
THIS.Setup();
sens.QValue := TRUE; // Sensor is covered
eq.MockStatus := StartUpStatus#AutoStartedUp; // Equipment is running
conv.RTD := DeliverState#Delivering; // Delivery in progress
Expand All @@ -181,9 +168,10 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
i : INT;
END_VAR
// Arrange - Setup with sensor jammed (covered) during delivery
THIS.Setup();
sens.QValue := TRUE; // Sensor is covered (jammed)
eq.MockStatus := StartUpStatus#AutoStartedUp; // Equipment is running
eq.MockErrorCode := WORD#16#8120;
eq.MockErrorText := 'Sensor blocked timeout';
conv.RTD := DeliverState#Delivering; // Delivery in progress

// First call to start the supervision monitoring
Expand All @@ -198,7 +186,7 @@ NAMESPACE Simatic.Ax.Conveyor.ControlLogic
stop.EvaluateStopPos();

// Assert - Error code and message should be set due to sensor blocking timeout
Equal(expected := TO_Word(ErrorState#OtherError), actual := eq.MockErrorCode);
Equal(expected := TO_WORD(StopPositionError#SensorBlocked), actual := eq.MockErrorCode);
Equal(expected := 'Sensor blocked timeout', actual := eq.GetErrorText());
END_METHOD
END_CLASS
Expand Down
1 change: 1 addition & 0 deletions test/Conveyor/EndOfLineConveyorTest.st
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ NAMESPACE Simatic.Ax.Conveyor
{Test}
METHOD PUBLIC EndOfLine_conveyor_continues_running_until_item_leaves
// Arrange - Start with item on sensor
AxUnit.Mocking.Mock('System.Timer.OffDelay', 'Simatic.Ax.Mocks.OffDelayMock_true');
THIS.EndOfLine_conveyor_starts_transfer_when_sensor_covered();

// Assert - Motor should be running
Expand Down
3 changes: 2 additions & 1 deletion test/Conveyor/MotorRunsDuringDeliveringTest.st
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ NAMESPACE Simatic.Ax.Conveyor
// Arrange - Setup conveyor with sensor covered and next conveyor ready
nextConv.RTR := ReceiveState#ReadyToReceive;
sensor.QValue := TRUE; // Item on sensor
AxUnit.Mocking.Mock('System.Timer.OffDelay', 'Simatic.Ax.Mocks.OffDelayMock_true');

// Act - Run cyclic execution to start transfer
conv.RunCyclic();
Expand All @@ -123,7 +124,7 @@ NAMESPACE Simatic.Ax.Conveyor
// Act - Item leaves sensor (transfer completes)
sensor.QValue := FALSE;
conv.RunCyclic();

// Assert - Transfer should be complete, motor still running due to off-delay
Equal(expected := TRUE, actual := conv.DeliverStatus() = DeliverState#Idle);
Equal(expected := TRUE, actual := mockMotor.IsRunning());
Expand Down
Loading