Developer Portal Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 
    SOLVED

    Operating mode does not stop when an error occurs in my object

    Operating mode does not stop when an error occurs in my object

    StefanKayser
    Member

    Hello,
    I wrote an object for a temperature control unit.
    There is a command set parameters , start and stop.
    This means it is possible that the temperature control unit is running but the unit is in ExecState ready.
    In OnUnitOperational, I evaluate the status of the device and, if necessary, trigger an error message.
    The error message can be seen in the HMI and the ExecState of the Object unit goes to Error, but automatic mode continues.

    How can I stop the operating mode from inside the object?

    I thought there is a Cancel through the Backbone...

    3 REPLIES 3

    MarvinW
    Long-established Member

    In general, Cancel is propagated from the top to the bottom. So if you want to use the cancel mechanism, then the command handler first has to issue it (or be triggered by its parent handler) and then this will reach the object. But this is not what you want anyway. You want the object to throw the error and then this error to propagate from bottom to the top.

    The error _event_ is propagated upwards automatically, but this is really only for showing the event. This has no control effect. For this you need to look at the ExecState of your hierarchy, like you correctly do, and investigate what happens to the states and how they switch to error (the unit state OpconUnitState.ERROR and events of type OpconEventClass.ERROR are two separate and only loosely connected concepts).

    If a unit switches to error, then this is _not_ automatically propagated upwards. In your normal station application this seems to happen but this is a feature that comes from your handlers' command chains using ExecuteUnit(RepeatOnError := FALSE, ..) or CheckUnitDone(RepeatOnError := FALSE, ...). The application guideline has some very detailed description about this mechanism. Everyone should be familiar with this.

    But the application guideline will not have a straight answer to your problem. Here are some things that you can do:

    • Have the handler check the unit state of the TCU and somehow stop itself when it sees its TCU unit switch to error. This moves the logic out of your object, so you get no reusability with this solution. I also generally don't recommend to do it this way, because you'll have to put some control flow influencing logic in your command handler's OnUnitOperational or somewhere similar. Simple, but ugly.
    • Change your object's commands so that it requires constant execution of the run command. This is how most automatic chains are realized in the command handlers and it works for objects, too. The user has to leave the Execute input on your TCU on TRUE for as long as it is working. In that case you won't really need a stop command and your start command should probably be called ControlTemperature instead or something. In order to stop you need a ParImm or something. Also, if you can change parameters during running, then those also need to use ParImm instead of a command. With some description of your TcuCmdEnum.CONTROL_TEMPERATURE item in the object you can convey this way of operation quite easily to your users. They will then use CheckUnitDone/ExecuteUnit with RepeatOnError := FALSE and get the effect that you want. But this is ugly for manual functions, possibly ATD and may not make the object seem very object-y.
    • Give the unit a ParCfg member that links back to its parent unit (I think this is also available in _stdUnitData or some such variable?) and use that to trigger a cancel or whatever reaction you really need on the father handler. This way, the unit gets some control of the parent handler, which is generally a BAD idea, but depending on circumstances might be the least of all evil. If you go this route, please add a parameter to the object like "Trigger parent cancel on error yes/no", so the user knows that your device has this capability and can switch it off to regain full control of their command handler. Then they need to handle it themselves (like option 1).

     

    Maybe somebody else has some other suggestions? I would probably pick option 1 and delegate the problem to the parent command handler. When programming an object, it is not that object's task to manipulate the control flow of the entire station's application it is embedded in. That is the business of the handlers, which are programmed by the application engineers. You may want to put some hints and possibly examples in your object documentation to inform your object users that this is a common pattern they might need in their application.

    Thank you very much for the detailed explanation

    SteffenR-
    Community Moderator
    Community Moderator

    Very Good answer by MarvinW!

    Option 3 is for example implemented in the Set Event add-on (NexeedSetEventAddon):

    SteffenR_0-1658485170653.png

    The add-on sets ModeHandler.Unit.Cancel / StopRequest / RunEmptyRequest.

    You should keep in mind that it can be very difficult in an application to find the reason of a cancel. At least you should make this very clear to the programmer (and operator by showing an error message).

    Currently the safety add-ons (ControlOn, MainValve, SafetyValve, SafetyDoor) and the Set Event add-on can cause a global cancel on the ModeForwarder/ModeHandler (depending on which one the add-ons are located).

    Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist