Development Example

This section describes how to add a customized alarm. The following uses the customized alarm whose ID is 001A0000 as an example to describe how to perform secondary development.

File Description

The file path involved in the development example is {project_dir}/src/app/add_customized_alarm. The directory structure is as follows:

├── alarm_info_en.json                        // Configuration file for backend alarm information configuration, which is used to report alarms to FusionDirector.
├── alarm_info_solution_en.json               // Configuration file for frontend alarm information configuration, which is used for page display.
├── alarm_info_solution_zh.json               // Configuration file for frontend alarm information configuration, which is used for page display.
├── all_alarm_for_manager.json                // Configuration file for backend alarm masking rule configuration, which is used to check the validity of the created login rule.
├── all_alarm_for_manager_web.json            // Configuration file for frontend alarm masking rule configuration, which is used for page display.
├── build_customized_alarm.sh                 // Compilation script
├── validate_alarm_config.py                  // Configuration file verification script
├── CMakeLists.txt                             // CMake configuration file
├── customized_alarm_check.c                  // Source file for the customized alarm implementation
└── customized_alarm_check.h                  // Header file for the customized alarm implementation

Configuration File Description

File Description lists the configuration files related to customized alarms. The fields in the configuration files are described as follows.

  • The formats of configuration files such as alarm_info_en.json, alarm_info_solution_en.json, and alarm_info_solution_zh.json are the same. The following uses alarm_info_en.json as an example.
    {
        "MAJOR_VERSION": "2",      # Major version
        "MINOR_VERSION": "8",      # Minor version
        "AUX_VERSION": "0",        # Auxiliary version
        "EventSuggestion": [     # Alarm information list
            {
            "id": "00000000",      # Alarm ID
            "name": "Drive Overtemperature",   # Alarm Name
            "dealSuggestion": "1. Check whether a TEC alarm is generated. @#AB2. Check whether the ambient temperature of the device exceeds 60°C.@#AB3. Restart the system. Then check whether the alarm is cleared.@#AB4. Contact Vendor technical support.",     # Handling suggestion
            "detailedInformation": "The component temperature exceeds the threshold.",      # Details
            "reason": " The ambient temperature is excessively high.",        # Cause
            "impact": " The system reliability may be affected."              # Impact
            }
        ]
    }
  • The fields and formats of all_alarm_for_manager.json and all_alarm_for_manager_web.json are the same. The difference is that the unique identifier field of all_alarm_for_manager_web.json is defined as innerid.
    {
        "LANG": {
            "MAJOR_VERSION": "2",               # Major version
            "MINOR_VERSION": "8",               # Minor version
            "AUX_VERSION": "0",                 # Auxiliary version
            "EventSuggestion": {                # Alarm masking rule information
                "item": [                         # Alarm masking rule list
                    {
                    "@innerid": "a000000000",     # Unique identifier. The unique identifier field of all_alarm_for_manager_web.json is innerid.
                    "id": "00000000",             # Alarm ID
                    "level": "2",                 # Alarm severity
                    "AlarmInstance": "M.2"        # Alarm object
                    }
                ]
            }
        }
    }

Procedure

  1. Enable the function of adding customized alarms.

    Change the value of the _NeedCustomizedAlarmCheck field in the project.conf file to yes (the default value is no).

  2. Define the alarm initialization API, callback function registration API, and related structures in customized_alarm_check.h.
    • An alarm message consists of two parts: message header (FAULT_MSG_HEAD_STRU, which defines the message length, message source, and number of alarms) and message body (array of the FAULT_ITEM_STRU type. Each FAULT_ITEM_STRU indicates an alarm). FAULT_MSG_HEAD_STRU and FAULT_ITEM_STRU must be defined according to the structure in the following example. Otherwise, the OM SDK fails to parse the alarm information.
    • The cmd field in the FAULT_MSG_HEAD_STRU message header must be set to 2, indicating that the alarm is a customized alarm. If the cmd field is set to another value, the customized alarm function may fail or the alarms supported by the OM SDK may be affected.
    • The values of the fault_id and sub_fault_id fields in the FAULT_ITEM_STRU message header range from 0 to 49. If the value exceeds 49, the alarm fails to be reported. The number of alarm types with the same fault_id cannot exceed 50.
    • In the following example, CUSTOMIZED_ALARM_CHECK_CALLBACK_PFN indicates the callback function provided by the OM SDK. Define the callback function according to the function definition in the example. Otherwise, the callback function of the OM SDK fails to be registered and the alarm message fails to be reported.
    • When the OM SDK is started, it calls the initialization API drv_fault_check_init and callback function registration API drv_fault_check_register_callback provided by the customized alarm detection component. Define the two APIs strictly according to the API definition in the example. Otherwise, the customized alarm detection component fails to be started.
    #ifndef CUSTOMIZED_ALARM_CHECK_H
    #define CUSTOMIZED_ALARM_CHECK_H
    
    #define ALARM_INFO_MAX_SIZE 64 * 1024
    
    
    typedef int (*CUSTOMIZED_ALARM_CHECK_CALLBACK_PFN)(unsigned char *data, unsigned int data_len);
    
    typedef struct {
        unsigned int data_len;       // Packet length
        unsigned int cmd;            // This parameter must be set to 2, which indicates a customized alarm. Other values may lead to failure of the customized alarm function or impact the alarms supported by the OM SDK.
        unsigned int item_num;       // Number of alarms
    } FAULT_MSG_HEAD_STRU;
    
    typedef struct {
        unsigned short fault_id;     // Alarm ID
        unsigned short sub_fault_id; // Sub-alarm ID
        unsigned short fault_level;  // Alarm severity
        unsigned short reserved;     // 4-byte alignment
        time_t raise_time_stamp;     // Alarm timestamp. The value is expressed in seconds (start counting since 00:00 on January 1, 1970).
        char fault_name[64];         // Alarm name
        char resource[32];           // Alarm entity
    } FAULT_ITEM_STRU;
    
    
    int drv_fault_check_init();
    void *customized_alarm_check(void *para);
    unsigned char *generate_customized_alarm();
    int drv_fault_check_register_callback(CUSTOMIZED_ALARM_CHECK_CALLBACK_PFN pfnRx);
    
    #endif
  3. Implement the customized alarm initialization API and callback function registration API in customized_alarm_check.c.

    You are advised to create a thread to implement the customized alarm detection initialization API. The following uses the simulated construction of an alarm as an example.

    /*
     * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
     */
    
    #include "unistd.h"
    #include "stdlib.h"
    #include "string.h"
    #include <time.h>
    #include "pthread.h"
    #include "customized_alarm_check.h"
    
    
    CUSTOMIZED_ALARM_CHECK_CALLBACK_PFN g_customized_alarm_check_rx_pfn = NULL;
    
    // Alarm detection function. In this example, simulated construction of an alarm is used.
    void* customized_alarm_check(void *para)
    {
        int ret;
        unsigned char *alarmBuff = NULL;
        unsigned int alarmSize = 0;
        sleep(5);
        // Perform simulated construction of the alarm.
        do {
            alarmSize = sizeof(FAULT_MSG_HEAD_STRU) + sizeof(FAULT_ITEM_STRU);
            alarmBuff = generate_customized_alarm();
            if (alarmBuff == NULL) {
                continue;
            }
            FAULT_MSG_HEAD_STRU *msg_head = (FAULT_MSG_HEAD_STRU *)alarmBuff;
            msg_head->data_len = alarmSize;
            msg_head->item_num = 1;
            msg_head->cmd = 2;
            if(g_customized_alarm_check_rx_pfn(alarmBuff, alarmSize) != 0) {
                free(alarmBuff);
                continue;
            }
            sleep(30);
            free(alarmBuff);
        } while (1);
    
        return ((void *)0);
    }
    
    // Generate alarm information.
    unsigned char *generate_customized_alarm()
    {
        unsigned int head_size = sizeof(FAULT_MSG_HEAD_STRU);
        unsigned int body_size = sizeof(FAULT_ITEM_STRU);
    
        if (head_size + body_size > ALARM_INFO_MAX_SIZE) {
            return NULL;
        }
        unsigned char *alarmBuff = (unsigned char *)malloc(head_size + body_size);
        if (alarmBuff == NULL) {
            return NULL;
        }
        (void)memset_s(alarmBuff, sizeof(head_size + body_size), 0, sizeof(head_size + body_size));
    
        FAULT_ITEM_STRU *item = (FAULT_ITEM_STRU *)(alarmBuff + head_size);
        item->fault_id = 26;                 // Alarm ID
        item->fault_level = 1;               // Alarm severity FAULT_LEVEL_ENUM: critical alarms, major alarms, and minor alarms
        item->raise_time_stamp = time(NULL); // Alarm timestamp. The value is expressed in seconds (start counting since 00:00 on January 1, 1970).
        (void)strncpy_s(item->fault_name, 64, "TEST_ERROR", strlen("TEST_ERROR")); // Alarm Name
        (void)strncpy_s(item->resource, 32, "TEST", strlen("TEST"));               // Alarm entity
    
        return alarmBuff;
    }
    
    // Initialize the customized alarm. To prevent the initialization from taking too long, create a new thread to start it.
    int drv_fault_check_init()
    {
        int ret = 0;
        unsigned long customized_alarm_check_thread = 0;
        ret = pthread_create(&customized_alarm_check_thread, NULL, customized_alarm_check, NULL);
        return ret;
    }
    
    // Register the callback function and save it in the global variable.
    int drv_fault_check_register_callback(CUSTOMIZED_ALARM_CHECK_CALLBACK_PFN pfnRx)
    {
        g_customized_alarm_check_rx_pfn = pfnRx;
        return 0;
    }
  4. Copy the alarm configuration file in the OM SDK to {project_dir}/src/app/add_customized_alarm and add customized alarm information. The paths of the configuration files are as follows:
    • alarm_info_en.json: config/alarm_info_en.json
    • alarm_info_solution_zh.json: software/nginx/html/manager/config/alarm_info_solution_zh.json
    • alarm_info_solution_en.json: software/nginx/html/manager/config/alarm_info_solution_en.json
    • all_alarm_for_manager.json: software/ibma/config/all_alarm_for_manager.json
    • all_alarm_for_manager_web.json: software/nginx/html/manager/config/all_alarm_for_manager.json

      All the alarm masking rule configuration files in the OM SDK software package is named all_alarm_for_manager.json. To distinguish the alarm masking rule configuration files, the alarm masking rule configuration file used by the frontend is named all_alarm_for_manager_web.json.

  5. Modify the configuration file. The following describes how to add the information of an alarm whose ID is 001A0000 to the corresponding configuration file. The following is only an example for reference only, which cannot be directly copied for use.

    Shift fault_id leftwards by 16 digits, add sub_fault_id to it, and convert it to a hexadecimal number. In this way the alarm ID is obtained. If the converted number is fewer than eight digits, add it to eight digits. Take alarm ID 001A0000 as an example. The value of fault_id is 26, and the value of sub_fault_id is 0. Shift 26 leftwards by 16 digits, 110100000000000000000 is obtained. Add sub_fault_id, 110100000000000000000 is obtained. Convert the number to a hexadecimal value, and 1A0000 is obtained. As the number contains fewer than eight digits, add it to eight digits. Alarm ID 001A0000 is obtained.

    1. Add customized alarm information to alarm_info_en.json.
      {
          "MAJOR_VERSION": "2",
          "MINOR_VERSION": "8",
          "AUX_VERSION": "0",
          "EventSuggestion": [
              {
              "id": "00000000",
              "name": "Drive Overtemperature",
              "dealSuggestion": "1. Check whether a TEC alarm is generated. @#AB2. Check whether the ambient temperature of the device exceeds 60°C.@#AB3. Restart the system. Then check whether the alarm is cleared.@#AB4. Contact Vendor technical support.",
              "detailedInformation": "The component temperature exceeds the threshold.",
              "reason": " The ambient temperature is excessively high.",
              "impact": " The system reliability may be affected."
              },
              {
              "id": "00000001",
              "name": "Drive Service Life Prewarning",
              "dealSuggestion": "1. Restart the system. Then check whether the alarm is cleared. @#AB2. Back up data and replace the drive. Then check whether the alarm is cleared. @#AB3. Contact Vendor technical support.",
              "detailedInformation": "The drive is severely worn.",
              "reason": " The hard drive has bad blocks.",
              "impact": "Data may be lost."
              },
      ...
      # The preceding is the original alarm information in the configuration file. The new alarm information is as follows:
              {
              "id": "001A0000",
              "name": "Test customized alarm",
              "dealSuggestion": "do nothing",
              "detailedInformation": "Test customized alarm.",
              "reason": "Test customized alarm.",
              "impact": "no impact."
              }
          ]
      }
    2. Add customized alarm information to alarm_info_solution_zh.json (Chinese version) and alarm_info_solution_en.json (English version).
      {
          "MAJOR_VERSION": "2",
          "MINOR_VERSION": "8",
          "AUX_VERSION": "0",
          "EventSuggestion": [
              {
              "id": "00000000",
              "name": "The drive temperature is too high.",
              "dealSuggestion": "1. Check whether a TEC alarm is generated. @#AB2. Use a temperature measurement tool to check whether the ambient temperature of the device exceeds 60°C (140°F). @#AB3. Restart the AI edge station and check whether the alarm is cleared. @#AB4. Contact the supplier for technical support.",
              "detailedInformation": "The drive temperature exceeds the threshold.",
              "reason": "The ambient temperature is too high.",
              "impact": "The system reliability may be affected."
              },
              {
              "id": "00000001",
              "name": "Drive service life expires.",
              "dealSuggestion": "1. Restart the AI edge station and check whether the alarm is cleared. @#AB2. Back up data, replace the drive, and check whether the alarm is cleared. @#AB3. Contact the supplier for technical support.",
              "detailedInformation": "The drive is severely worn.",
              "reason": "The drive has bad blocks.",
              "impact": "Data may be lost."
              },
      ...
      # The preceding is the original alarm information in the configuration file. The new alarm information is as follows:
              {
              "id": "001A0000",
              "name": "Test the customized alarm.",
              "dealSuggestion": "Do nothing.",
              "detailedInformation": "Do nothing.",
              "reason": "Test the customized alarm.",
              "impact": "No impact."
          }
        ]
      }
    3. Add the alarm masking rule to all_alarm_for_manager.json.
      {
          "LANG": {
              "MAJOR_VERSION": "2",
              "MINOR_VERSION": "8",
              "AUX_VERSION": "0",
              "EventSuggestion": {
                  "item": [
                  {
                  "@innerid": "a000000000",
                  "id": "00000000",
                  "level": "2",
                  "AlarmInstance": "M.2"
                  },
                  {
                  "@innerid": "a000000001",
                  "id": "00000001",
                  "level": "2",
                  "AlarmInstance": "M.2"
                  },
      ...
      # The preceding is the original alarm information in the configuration file. The new alarm information is as follows:
                  {
                  "@innerid": "x000000000",
                  "id": "001A0000",
                  "level": "1",
                  "AlarmInstance": "TEST"
                  }
                  ]
              }
          }
      }
    4. Add the alarm masking rule to all_alarm_for_manager_web.json.
      {
          "MAJOR_VERSION": "2",
          "MINOR_VERSION": "8",
          "AUX_VERSION": "0",
          "EventSuggestion": [
              {
                  "innerid": "a000000000",
                  "id": "00000000",
                  "level": "2",
                  "AlarmInstance": "M.2"
              },
              {
                  "innerid": "a000000001",
                  "id": "00000001",
                  "level": "2",
                  "AlarmInstance": "M.2"
              },
      ...
      # The preceding is the original alarm information in the configuration file. The new alarm information is as follows:
              {
                  "innerid": "x000000000",
                  "id": "001A0000",
                  "level": "1",
                  "AlarmInstance": "TEST"
              }
          ]
      }

    If the added customized alarm already exists in the preset alarm configuration items of the OM SDK, skip adding the alarm information to the corresponding alarm configuration file. For details about the preset alarms, see Table 1.

  6. Check whether the configuration file is correctly configured.

    The validate_alarm_config.py script verifies the alarm masking configuration files (all_alarm_for_manager.json and all_alarm_for_manager_web.json) and alarm information configuration files (alarm_info_en.json, alarm_info_solution_en.json, and alarm_info_solution_zh.json). For the alarm masking configuration files, the system checks: whether duplicate @innerid, innerid, and ID+AlarmInstance combinations exist; whether the configuration file format is correct; whether fields are missing or not within the required range. For the alarm information configuration files, the system checks: whether duplicate IDs exist; whether the configuration file format is correct; whether some fields are missing or not in the required range.

    1. Run the following command to switch to the directory that contains the configuration file:
      cd {project_dir}/src/app/add_customized_alarm
    2. Run the following commands to verify the configuration file:
      python3 validate_alarm_config.py ./

      The following is an example of the validate_alarm_config.py script:

      import json
      import os
      import sys
      
      ALARM_INFO_CONFIG = ("alarm_info_en.json", "alarm_info_solution_en.json", "alarm_info_solution_zh.json")
      ALARM_INFO_FIELDS = {"id", "name", "dealSuggestion", "detailedInformation", "reason", "impact"}
      ALARM_SHIELD_FIELDS = {"@innerid", "id", "level", "AlarmInstance"}
      ALARM_SHIELD_WEB_FIELDS = {"innerid", "id", "level", "AlarmInstance"}
      
      
      class Result:
          def __init__(self, result: bool, err_msg: str = ""):
              self._result = result
              self._err_msg = err_msg
      
          def __bool__(self):
              return self._result
      
          @property
          def error(self) -> str:
              return self._err_msg
      
      
      def check_alarm_id(filename: str, alarm_id: str):
          if len(alarm_id) != 8:
              raise Exception(f"{filename}: alarm id length wrong, should be 8")
      
          try:
              int(alarm_id, base=16)
          except Exception as err:
              raise Exception(f"{filename}: alarm id is invalid, reason: {err}")
      
      
      def check_alarm_field_range(alarms: list, filename: str, filed_range: set):
          for alarm in alarms:
              if not isinstance(alarm, dict):
                  raise Exception(f"{filename}: alarm info type is wrong, should be map")
      
              if len(alarm.keys()) != len(filed_range):
                  raise Exception(f"{filename}: alarm info miss some fields")
      
              if not set(alarm.keys()).issubset(filed_range):
                  raise Exception(f"{filename}: alarm info fields is not in range of {filed_range}")
      
              check_alarm_id(filename, alarm.get("id"))
      
      
      def check_alarm_info_config(content: dict, filename: str) -> Result:
          """
          Check whether the alarm information configuration file is correctly configured. The check items include whether the alarm ID is duplicate, whether the alarm information format is correct, and whether the fields are missing or not in the required field range.
          :param filename: alarm configuration file name
          :param content: configuration file content
          :return: detection result
          """
          alarms = content.get("EventSuggestion")
          if not alarms:
              return Result(False, f"{filename}: EventSuggestion is null")
      
          if not isinstance(alarms, list):
              return Result(False, f"{filename}: EventSuggestion type is wrong, should be list")
      
          try:
              check_alarm_field_range(alarms, filename, ALARM_INFO_FIELDS)
          except Exception as err:
              return Result(False, f'{err}')
      
          ids = [alarm.get("id") for alarm in alarms]
          if len(set(ids)) != len(alarms):
              return Result(False, f"{filename}: have same id, please check")
      
          return Result(True)
      
      
      def check_alarm_shield(inner_id: str, alarm_shields: list, filename: str, filed_range: set) -> Result:
          try:
              check_alarm_field_range(alarm_shields, filename, filed_range)
          except Exception as err:
              return Result(False, f'{err}')
      
          ids = [alarm_shield.get(inner_id) for alarm_shield in alarm_shields]
          if len(set(ids)) != len(alarm_shields):
              return Result(False, f"{filename}: have same {inner_id}, please check")
      
          unique_keys = [f"{alarm_shield.get('id')}-{alarm_shield.get('AlarmInstance')}" for alarm_shield in alarm_shields]
          if len(set(unique_keys)) != len(alarm_shields):
              return Result(False, f"{filename}: have same unique_key(id-AlarmInstance), please check")
      
          return Result(True)
      
      
      def check_alarm_shield_config(content: dict, filename: str) -> Result:
          """
          Check whether the alarm masking configuration file is correct, including whether duplicate inerid and alarm ID+object combinations exist; whether the alarm masking configuration format is correct; whether fields are missing; whether fields are not within the required field range.
          :param content: configuration file content
          :param filename: configuration file name
          :return: detection result
          """
          lang = content.get("LANG")
          if not isinstance(lang, dict):
              return Result(False, f"{filename}: LANG type is wrong, should be map")
      
          event_suggestion = lang.get("EventSuggestion")
          if not event_suggestion:
              return Result(False, f"{filename}: EventSuggestion is null")
      
          if not isinstance(event_suggestion, dict):
              return Result(False, f"{filename}: EventSuggestion type is wrong, should be map")
      
          alarm_shields = event_suggestion.get("item")
          if not alarm_shields:
              return Result(False, f"{filename}: item is null")
          if not isinstance(alarm_shields, list):
              return Result(False, f"{filename}: item type is wrong, should be list")
      
          return check_alarm_shield("@innerid", alarm_shields, filename, ALARM_SHIELD_FIELDS)
      
      
      def check_alarm_shield_web_config(content: dict, filename: str) -> Result:
          """
          Check whether the alarm masking configuration file on the frontend is correct, including whether duplicate inerid and alarm ID+object combinations exist; whether the alarm masking configuration format is correct; whether fields are missing; whether fields are not within the required field range.
          :param content: configuration file content
          :param filename: configuration file name
          :return: detection result
          """
          alarm_shields = content.get("EventSuggestion")
          if not alarm_shields:
              return Result(False, f"{filename}: EventSuggestion is null")
      
          if not isinstance(alarm_shields, list):
              return Result(False, f"{filename}: EventSuggestion type is wrong, should be list")
      
          return check_alarm_shield("innerid", alarm_shields, filename, ALARM_SHIELD_WEB_FIELDS)
      
      
      def check(config_file_dir: str):
          """
          Check whether the alarm configuration file is correctly configured.
          :param config_file_dir: path of the alarm-related configuration files
          :return: None
          """
          for filename in os.listdir(config_file_dir):
              if not filename.endswith("json"):
                  continue
              try:
                  with open(os.path.join(config_file_dir, filename)) as stream:
                      document = json.load(stream)
              except Exception as err:
                  print(f"read file content of {filename} failed, reason: {err}")
                  return
      
              if filename in ALARM_INFO_CONFIG:
                  ret = check_alarm_info_config(document, filename)
                  if not ret:
                      print(f"check file {filename} failed, reason:{ret.error}")
                      return
              elif filename == "all_alarm_for_manager.json":
                  ret = check_alarm_shield_config(document, filename)
                  if not ret:
                      print(f"check file {filename} failed, reason:{ret.error}")
                      return
              elif filename == "all_alarm_for_manager_web.json":
                  ret = check_alarm_shield_web_config(document, filename)
                  if not ret:
                      print(f"check file {filename} failed, reason:{ret.error}")
                      return
              else:
                  raise AssertionError(f"Unknown file: {filename}")
      
          print(f"The collection of configurations in {config_file_dir} is correct. ")
      
      
      if __name__ == "__main__":
          if len(sys.argv) == 2:
              check(sys.argv[1])
          else:
              print("The input argument should be the directory of the configuration files")
      
  7. Compile the construction mode in CMakeLists.txt.

    The name of the generated binary file must be libcustomized_alarm.so. Otherwise, the OM SDK may fail to start the customized alarm component.

    # Set the minimum CMake version.
    cmake_minimum_required(VERSION 3.16)
    
    # Cross compilation options
    if (CROSSCOMPILE_ENABLED)
        set(CMAKE_SYSTEM_NAME Linux)
        set(CMAKE_SYSTEM_PROCESSOR aarch64)
        set(target_arch aarch64-linux-gnu)
        set(CMAKE_C_COMPILER /usr/bin/aarch64-linux-gnu-gcc)
        set(CMAKE_CXX_COMPILER /usr/bin/aarch64-linux-gnu-g++)
        set(CMAKE_LIBRARY_ARCHITECTURE ${target_arch} CACHE STRING "" FORCE)
        set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
        set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
        set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
        set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
    endif()
    
    # Add the name of the project to be constructed.
    project(customized_alarm)
    # Generate a link file named libcustomized_alarm.so from the source file. STATIC: static link. SHARED: dynamic link.
    add_library(customized_alarm SHARED customized_alarm_check.c customized_alarm_check.h)
  8. Implement the build logic in the build_customized_alarm.sh script.
    #!/bin/bash
    
    CUR_DIR=$(dirname "$(readlink -f "$0")")
    
    function build_customized_alarm()
    {
        echo "build customized alarm ..."
        if [ ! -d "${CUR_DIR}/build" ];then
            mkdir -p "${CUR_DIR}/build"
        else
            rm -rf "${CUR_DIR}/build"/*
        fi
    
        cd "${CUR_DIR}/build"
        cmake -DCROSSCOMPILE_ENABLED=ON ..
        make
        echo "build customized alarm success"
        return 0
    }
    
    build_customized_alarm
    RESULT=$?
    exit "${RESULT}"
  9. Add the invoking of the customized build script to the {project_dir}/build/build.sh file.
    # Add customized alarm detection.
    if [[ "${_NeedCustomizedAlarmCheck}" == "yes" ]]; then
        if ! bash "${TOP_DIR}/src/app/add_customized_alarm/build_customized_alarm.sh";then
            return 1
        fi
    
        cp -rf ${TOP_DIR}/src/app/add_customized_alarm/build/libcustomized_alarm.so ${OMSDK_TAR_PATH}/lib/
        # Overwrite the alarm-related configuration files in the OM SDK software package.
        cp -rf ${TOP_DIR}/src/app/add_customized_alarm/alarm_info_en.json ${OMSDK_TAR_PATH}/config/alarm_info_en.json
        cp -rf ${TOP_DIR}/src/app/add_customized_alarm/all_alarm_for_manager.json ${OMSDK_TAR_PATH}/software/ibma/config/all_alarm_for_manager.json
        cp -rf ${TOP_DIR}/src/app/add_customized_alarm/all_alarm_for_manager_web.json ${OMSDK_TAR_PATH}/software/nginx/html/manager/config/all_alarm_for_manager.json
        cp -rf ${TOP_DIR}/src/app/add_customized_alarm/alarm_info_solution_en.json ${OMSDK_TAR_PATH}/software/nginx/html/manager/config/alarm_info_solution_en.json
        cp -rf ${TOP_DIR}/src/app/add_customized_alarm/alarm_info_solution_zh.json ${OMSDK_TAR_PATH}/software/nginx/html/manager/config/alarm_info_solution_zh.json
    fi