Skip to content

kmu2030/ModeManagerLib

Repository files navigation

ModeManagerLib

ModeManagerLib provides a simple initialization system for Omron's NX/NJ controllers. A set of programs is called a mode, and the program to be launched is determined by selecting a mode. For details, please check "Sysmac Studioで簡単な初期化システムを作る".

By defining a mode as shown below and executing the mode activation POU, the program specified in the mode will be started.

IF P_First_Run THEN
    SPEC_USE_MQTT := TRUE;
    SPEC_USE_KINTONE := TRUE;

    ModeManager_init(Context:=iModeManager,
                     // The name of the program under which the mode manager runs.
                     Name:='ProgramLoader',
                     // Whether the mode manager should terminate the running program on successful mode activation.
                     // The default is TRUE (stop).
                     OnSuccessStop:=TRUE,
                     // Whether the mode manager should terminate the running program on failed mode activation.
                     // The default is TRUE (stop).
                     OnFailStop:=FALSE,
                     // Whether to leave an alarm log in the controller on failed mode activation.
                     // The default is FALSE (No logs).
                     OnFailAlarm:=TRUE,
                     // User log alarm code.
                     // The default is 1.
                     AlarmCode:=1);

    ModeSet(Context:=iModeManager);
        Mode(Context:=iModeManager,
             // Mode identifier.
             Name:='modeselect',
             // Whether this is the default mode.
             // The default is FALSE (not default).
             Default:=TRUE);
            ModeUnit(Context:=iModeManager,
                     // The name of the program that is the mode unit.
                     Name:='DeviceIn',
                     // Whether to enable P_First_Run.
                     // The default is TRUE (enabled).
                     FirstRun:=TRUE,
                     // Whether to stop the program on failed mode activation.
                     // The default is TRUE (stop).
                     OnFailStop:=TRUE);
            ModeUnit(Context:=iModeManager, Name:='DeviceOut');
            ModeUnit(Context:=iModeManager, Name:='TelnetService');

        Mode(Context:=iModeManager, Name:='setup');
            ModeUnit(Context:=iModeManager, Name:='DeviceIn');
            ModeUnit(Context:=iModeManager, Name:='DeviceOut');
            ModeUnit(Context:=iModeManager, Name:='Machine1Setup');
            ModeUnit(Context:=iModeManager, Name:='Machine2Setup');
            ModeUnit(Context:=iModeManager, Name:='TelnetService');

        Mode(Context:=iModeManager, Name:='run');
            ModeUnit(Context:=iModeManager, Name:='DeviceIn');
            ModeUnit(Context:=iModeManager, Name:='DeviceOut');
            ModeUnit(Context:=iModeManager, Name:='Machine1Ctrl');
            ModeUnit(Context:=iModeManager, Name:='Machine2Ctrl');
            IF SPEC_USE_MQTT THEN
                ModeUnit(Context:=iModeManager, Name:='MqttMachineStatSender');
            END_IF;
            IF SPEC_USE_KINTONE THEN
                ModeUnit(Context:=iModeManager, Name:='KintoneClientService');
                ModeUnit(Context:=iModeManager, Name:='KintoneAlarmCollector');
            END_IF;

        Mode(Context:=iModeManager, Name:='diagnosis');
            ModeUnit(Context:=iModeManager, Name:='DeviceIn');
            ModeUnit(Context:=iModeManager, Name:='DeviceOut');
            ModeUnit(Context:=iModeManager, Name:='DiagnosisCtrl');
            ModeUnit(Context:=iModeManager, Name:='Machine1Diagnosis');
            ModeUnit(Context:=iModeManager, Name:='Machine2Diagnosis');
            ModeUnit(Context:=iModeManager, Name:='DiagnosisReporter');
            ModeUnit(Context:=iModeManager, Name:='TelnetService');
            IF SPEC_USE_MQTT THEN
                ModeUnit(Context:=iModeManager, Name:='MqttMachineStatSender');
            END_IF;
            IF SPEC_USE_KINTONE THEN
                ModeUnit(Context:=iModeManager, Name:='KintoneClientService');
                ModeUnit(Context:=iModeManager, Name:='KintoneAlarmCollector');
            END_IF;
    ModeSetClose(Context:=iModeManager);
    
    // Select the mode.
    ModeManager_selectMode(Context:=iModeManager, Name:=RUN_MODE);
END_IF;

// Activates the selected mode.
ModeManager_activate(Context:=iModeManager);

// When you output logs to the controller yourself.
(*
IF ModeManager_activate(Context:=iModeManager) THEN
    IF ModeManager_hasError(Context:=iModeManager) THEN
        ModeManager_getAlarmInfo(Context:=iModeManager,
                                 ErrorID=>iErrorID,
                                 RunMode=>iRunMode);
        SetAlarm(Code:=1, Info1:=iErrorID, Info2:=iRunMode);
    END_IF;
END_IF;
*)

In the controller task settings, set the program that contains the code to activate the mode to Enable, and the program that you want to start to Stop, as shown below.

Sample program task settings

ProgramLoader is the program POU that executes the mode activate POU.

If you set the RUN_MODE global variable to "diagnosis" and run it in the simulator, only the program in the mode specified as follows will be launched.

Task execution monitor when the sample program is started in diagnosis mode

If mode activation fails, the following error occurs.

ErrorID Description
0x0000..0x0FFF The program specified in the mode unit Name does not exist.
0x2000 The program specified by Name in the mode manager does not exist.
0x8000 The mode manager was initialized with a Name of an empty string.
0x81** Defined a mode whose Name is an empty string.
0x82** Defined a mode unit whose Name is an empty string.

If you have specified that an alarm log should be left when mode activation fails, a log of the specified alarm code will be left and the Error ID will be recorded in additional information 1.

Mode Deactivate Function

ModeManagerLib has a limited function to deactivate currently active modes. When using, please keep the following in mind.

  • Dependencies are not taken into account.
  • Deactivate in the same order as activated.
  • When a mode unit (program) in a mode fails to stop, subsequent mode units will not stop.

As long as you can determine that each is an independent program and can be stopped, there is no problem in deactivating the mode. To deactivate the mode, use the following POU, which is similar to ModeManager_activate.

FUNCTION ModeManager_deactivate(ModeManagerContext) : BOOL;

Below is an example of using ModeManager to dynamically switch programs in manual testing on an actual device. It monitors changes in the mode value and switches the running program.

CASE iState OF
    // STATE_INIT
    0:
        Clear(iRunMode);
        Clear(iPrevRunMode);
        
        ModeManager_init(Context:=iContext,
            Name:='Test_ManualTest',
            OnSuccessStop:=FALSE,
            OnFailStop:=FALSE,
            OnFailAlarm:=FALSE);
        
        ModeSet(iContext);
            // NOP is to not start any programs.
            Mode(Context:=iContext, Name:='NOP', Default:=TRUE);
            
            Mode(Context:=iContext, Name:='EdgeFunction');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_EdgeFunction');
            Mode(Context:=iContext, Name:='Rpc');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_Rpc');
            Mode(Context:=iContext, Name:='Select');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_Select');
            Mode(Context:=iContext, Name:='Insert');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_Insert');
            Mode(Context:=iContext, Name:='BulkInsert_json');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_BulkInsert_json');
            Mode(Context:=iContext, Name:='BulkInsert_csv');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_BulkInsert_csv');
            Mode(Context:=iContext, Name:='Update');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_Update');
            Mode(Context:=iContext, Name:='Upsert_json');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_Upsert_json');
            Mode(Context:=iContext, Name:='Upsert_csv');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_Upsert_csv');
            Mode(Context:=iContext, Name:='SingleUpsert_json');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_SingleUpsert_json');
            Mode(Context:=iContext, Name:='SingleUpsert_csv');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_SingleUpsert_csv');
            Mode(Context:=iContext, Name:='Delete');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Worker_Delete');            
            Mode(Context:=iContext, Name:='ServiceKeyAccess');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Check_ServiceKeyAccess');
            Mode(Context:=iContext, Name:='ServiceKeyAccessWithKey');
                ModeUnit(Context:=iContext, Name:='Test_ManualTest_Check_ServiceKeyAccessWithKey');
        ModeSetClose(iContext);
        
        iState := STATE_ACTIVE;
    
    // STATE_ACTIVE
    10:
        IF iRunMode <> iPrevRunMode
            AND iRunMode <> ''
        THEN
            iPrevRunMode := iRunMode;
            IF ModeManager_selectMode(
                   Context:=iContext,
                   Name:=iRunMode)
            THEN        
                Inc(iState);
            END_IF;
        END_IF;
    11:
        IF ModeManager_activate(Context:=iContext) THEN
            IF ModeManager_hasError(Context:=iContext) THEN
                iState := STATE_ERROR;
            ELSE
                Inc(iState);
            END_IF;
        END_IF;
    12:
        IF iRunMode <> iPrevRunMode THEN
            Inc(iState);
        END_IF;
    13:
        IF ModeManager_deactivate(
               Context:=iContext,
               IfActive:=TRUE)
        THEN
            iState := STATE_ACTIVE;
        END_IF;
END_CASE;

Usage environment

The following environment is required to use this project.

Sysmac Studio The latest version is recommended.

Built environment

This project was built in the following environment.

Sysmac Studio Ver.1.62

Sample program usage steps

The sample program (POU/Program/ProgramLoader) is used in the following steps.

1. Run the simulator

Run the simulator and change to Program mode.

2. Set the mode in the RUN_MODE global variable

In the Watch window, set the startup mode to the RUN_MODE global variable.

3. Change the simulator to operation mode

Switch the simulator to operation mode and confirm that the program for the specified mode is running.

About

Simple initialization system for NX/NJ in Sysmac Studio

Topics

Resources

License

Stars

Watchers

Forks

Languages