Skip to content
Snippets Groups Projects
silecs.sh 11.6 KiB
Newer Older
#!/bin/sh

# File/Project has to be the last argument
FILE=${@:$#}
PROJECT_NAME=$(echo "${FILE##*/}" | sed 's/\.[^.]*$//')


SCRIPT=$(readlink -f "$0")

SILECS_VERSION=2.2.0
SILECS_BASE=/common/usr/cscofe/silecs

FESA_VERSION=7.3.0
FESA_BASE=/opt/fesa/fesa-fwk/$FESA_VERSION

N_ARGUMENTS=$#



function help {
    echo -e ""
    echo -e "Usage: silecs [OPTION] [FILE]"
    echo -e ""
    echo -e "Script in order to model PLC devices in FESA by using the Silecs framework."
    echo -e ""
    echo -e "\t -c \t create new .silecsdesign/.silecsdeploy file for the specified FESA .design/.deploy file"
    echo -e "\t -v \t validate silecs xml file"
    echo -e "\t -g \t generate source code for silecs xml file"
    echo -e "\t -d \t start diagnostic tool for silecs xml file"
    echo -e "\t -r \t release parameter file to FEC (TODO)"
    echo -e "\t -m \t migrate silecs design/deploy file to new silecs version (TODO)"
    echo -e "\t -h \t show this help"
    echo -e ""
    echo -e "Examples:"
    echo -e ""
    echo -e "\t To create a new file 'MyClass.silecsdesign' for the FESA class."
    echo -e "\t\t silces -c ~/workspace/MyClass/src/MyClass.design"
    echo -e ""
    echo -e "\t To validate 'MyClass.silecsdesign'."
    echo -e "\t\t silces -v ~/workspace/MyClass/src/MyClass.silecsdesign"
    echo -e ""
    echo -e "\t To add missing properties and value-items specified in 'MyClass.silecsdesign' into the FESA document 'MyClass.design'."
    echo -e "\t This will as well ate C++ code." 
    echo -e "\t\t silces -g ~/workspace/MyClass/src/MyClass.silecsdesign"
    echo -e ""
    echo -e "Check the Silecs Wiki for more info: https://www-acc.gsi.de/wiki/Frontend/SILECS"
    echo -e ""
    exit 1;
}



if [ $N_ARGUMENTS -lt 1 ]
  then
    echo "Error: Wrong number of arguments supplied."
    help
fi



function assert_n_arguments {
if [ $N_ARGUMENTS -lt $1 ]
  then
    echo "Error: Wrong number of arguments supplied."
    help
fi
}



function silecs_validate {
    assert_n_arguments 2

    EXTENSION=$(echo "$FILE" | sed 's/^.*\.//')

    # Resolve possible relative path
    FILE=$(realpath "$FILE" )

    case $EXTENSION in
      silecsdesign)
          SCHEMA=$SILECS_BASE/silecs-model/$SILECS_VERSION/xml/DesignSchema.xsd
          ;;
      silecsdeploy)
          SCHEMA=$SILECS_BASE/silecs-model/$SILECS_VERSION/xml/DeploySchema.xsd
          ;;
      *)
          echo "Error: Passed file for validation needs to have the extension '.silecsdesign' or '.silecsdeploy'"
          exit 1
          ;;
    esac
 
    echo "validating $FILE"
    echo ""
    xmllint --schema  $SCHEMA $FILE --noout
    RESULT=$?
    echo ""
    if [ $RESULT -eq 0 ]
    then
        echo "File is valid"
    else
        echo "File is not valid. Check errors above."
    fi

    return $RESULT

# TODO: Implement jave-rules -  See here for details: https://gitlab.com/al.schwinn/silecs-cli/-/issues/3

}



function execute_python {
    PYTHON_FILE=$1
    PYTHON_METHOD=$2
    
    SILECS_CODEGEN_BASE=$SILECS_BASE/silecs-codegen/$SILECS_VERSION/xml/
    SILECS_CODEGEN_MIGRATION=$SILECS_BASE/silecs-codegen/$SILECS_VERSION/xml/migration

    # TODO: Check for concrete fesa version -  See here for details: https://gitlab.com/al.schwinn/silecs-cli/-/issues/4
    SILECS_CODEGEN_FESA=$SILECS_BASE/silecs-codegen/$SILECS_VERSION/xml/fesa/fesa_7_3_0/

    ARGUMENTS=""
    for ((i=3; i<=$#; i++))
        do
            ARGUMENTS+="'"
            ARGUMENTS+=${!i}
            ARGUMENTS+="'"
            if [ $i -ne $# ]
              then
                ARGUMENTS+=","
            fi
        done

    #echo $ARGUMENTS

    python3 -c "import sys;\
                sys.path.append('$SILECS_CODEGEN_BASE');\
                sys.path.append('$SILECS_CODEGEN_MIGRATION');\
                sys.path.append('$SILECS_CODEGEN_FESA');\
                import $PYTHON_FILE;\
                $PYTHON_FILE.$PYTHON_METHOD($ARGUMENTS);"
    return $?
}



function silecs_generate {
    assert_n_arguments 2
    
    silecs_validate
    if [ $? -ne 0 ]; then
        echo ""
        echo "Error: $FILE is not valid. Please fix all xml errors before generating code !"
        exit 1
    fi

    # Resolve possible relative path
    FILE=$(realpath "$FILE" )

    EXTENSION=$(echo "$FILE" | sed 's/^.*\.//')

  case $EXTENSION in
    silecsdesign)
        silecs_generate_silecsdesign
        ;;
    silecsdeploy)
        silecs_generate_silecsdeploy
        ;;
    *)
        echo "Error: Passed file for code generation needs to have the exctension '.silecsdesign' or '.silecsdeploy'"
        exit 1
        ;;
  esac
}



function silecs_generate_silecsdesign {

    SILECS_DESIGN_FILE=$FILE
    PROJECT_PATH=$(dirname "$(dirname "$FILE")")
    WORKSPACE_PATH=$(dirname "$PROJECT_PATH")
    SILECS_LIBRARY_BASE=$SILECS_BASE/silecs-communication-cpp/$SILECS_VERSION
    FESA_DESIGN_FILE=$PROJECT_PATH/src/$PROJECT_NAME.design
    FESA_XSD=$FESA_BASE/fesa-model-gsi/xml/design/design-gsi.xsd

    echo "generating code for $PROJECT_NAME ..."
    echo ""

    if [ -f $FESA_DESIGN_FILE ];
        then
            echo "Please note that old, obsolete xml-elements are not deleted automatically! Sometimes this can lead to an invalid FESA Design document!"
            echo "If this is the case, please remove the obsolete elements by hand."
            echo "Creating a backup of the existing FESA file at: $FESA_DESIGN_FILE.backup"
            echo ""
            cp $FESA_DESIGN_FILE $FESA_DESIGN_FILE.backup
    fi

    execute_python generateFesaDesign fillDesignFile $FESA_VERSION $PROJECT_NAME $WORKSPACE_PATH $FESA_XSD
    execute_python generateSourceCode genCppFiles $PROJECT_NAME $WORKSPACE_PATH $SILECS_DESIGN_FILE

    echo ""
    echo "Please not that you need to add the dependency to the silecs library to your Makefile."
    echo "Here an example: https://www-acc.gsi.de/wiki/Frontend/Silecs_1_0_0_CodeSnippets#Dependency_in_Makefile.specific !"
    echo ""
    echo "Code generation finished"
}

function silecs_generate_silecsdeploy {

    SILECS_DEPLOY_FILE=$FILE
    PROJECT_PATH=$(dirname "$(dirname "$FILE")")
    WORKSPACE_PATH=$(dirname "$PROJECT_PATH")
    SILECS_LIBRARY_BASE=$SILECS_BASE/silecs-communication-cpp/$SILECS_VERSION
    FESA_DEPLOY_FILE=$PROJECT_PATH/src/$PROJECT_NAME.deploy
    FESA_XSD=$FESA_BASE/fesa-model-gsi/xml/deployment/deployment-gsi.xsd
    FESA_GSI_TEMPLATE=$FESA_BASE/fesa-model-gsi/xml/design/templates/GSIClassTemplate.xml
    SILECS_DEPLOY_VERSION="unused_parameter"

    echo "generating code for $PROJECT_NAME ..."
    echo ""

    if [ -f $FESA_DESIGN_FILE ];
        then
            echo "Please note that old, obsolete xml-elements are not deleted automatically! Sometimes this can lead to an invalid FESA document!"
            echo "If this is the case, please remove the obsolete elements by hand."
            echo "Creating a backup of the existing FESA file at: $FESA_DEPLOY_FILE.backup"
            echo ""
            cp $FESA_DEPLOY_FILE $FESA_DEPLOY_FILE.backup
    fi

    execute_python genparam genParam $WORKSPACE_PATH $PROJECT_NAME $SILECS_DEPLOY_VERSION $SILECS_VERSION
    execute_python genplcsrc genPlcSrc $WORKSPACE_PATH $PROJECT_NAME $SILECS_VERSION
    execute_python genduwrapper genDuWrapper $WORKSPACE_PATH $PROJECT_NAME $SILECS_DEPLOY_VERSION
    execute_python fillFESADeployUnit fillDeployUnit $WORKSPACE_PATH $PROJECT_NAME $FESA_XSD $FESA_VERSION

    echo ""
    echo "Please not that you need to add the dependency to the silecs library to your Makefile."
    echo "Here an example: https://www-acc.gsi.de/wiki/Frontend/Silecs_1_0_0_CodeSnippets#Dependency_in_Makefile.specific !"
    echo ""
    echo "Code generation finished"
}




function silecs_create_design {
    NEWFILEPATH=$1
    DATE=$(date +%x)
    SCHEMA_PATH=$SILECS_BASE/silecs-model/$SILECS_VERSION/xml/DesignSchema.xsd
    
    DESIGN_TEMPLATE='<?xml version="1.0" encoding="UTF-8"?>
<SILECS-Design silecs-version="'$SILECS_VERSION'" created="'$DATE'" updated="'$DATE'"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="'$SCHEMA_PATH'">
    <Information>
        <Owner user-login="'$USER'"/>
        <Editor user-login="'$USER'"/>
    </Information>
    <SILECS-Class name="'$PROJECT_NAME'" version="0.1.0" domain="OPERATIONAL" >
        <Acquisition-Block name="MyBlock" generateFesaProperty="true">
            <Acquisition-Register name="myRegister" generateFesaValueItem="true">
                <scalar format="int32"/>
            </Acquisition-Register>
        </Acquisition-Block>
    </SILECS-Class>
</SILECS-Design>'

if [ -f $NEWFILEPATH ]; then
    echo "Error: There is already a .silecsdesign file available: $NEWFILEPATH"
    exit 1
fi

echo $DESIGN_TEMPLATE | xmllint --format - > $NEWFILEPATH

echo ""
echo "created new silecsdesign: $NEW_FILE"
}



function silecs_create_deploy {
    NEWFILEPATH=$1
    DATE=$(date +%x)
    SCHEMA_PATH=$SILECS_BASE/silecs-model/$SILECS_VERSION/xml/DeploySchema.xsd
    
    DEPLOY_TEMPLATE='<?xml version="1.0" encoding="UTF-8"?>
<SILECS-Deploy silecs-version="'$SILECS_VERSION'" created="'$DATE'" updated="'$DATE'" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="'$SCHEMA_PATH'">
    <Information>
        <Owner user-login="'$USER'"/>
        <Editor user-login="'$USER'"/>
    </Information>
    <Deploy-Unit name="'$PROJECT_NAME'" version="0.1.0"/>
    <SilecsDesign silecs-design-name="" silecs-design-version=""/>
        
    <Controller host-name="">
        <Siemens-PLC system="TIA-PORTAL" model="SIMATIC_S7-300" protocol="DEVICE_MODE" base-DB-number="1">
            <Device silecs-device-label="dev0" silecs-design-ref="" fesa-device-name="" fesa-fec-name=""/>
        </Siemens-PLC>
    </Controller>
</SILECS-Deploy>'

if [ -f $NEWFILEPATH ]; then
    echo "Error: There is already a .silecsdeploy file available: $NEWFILEPATH"
    exit 1
fi
    
echo $DEPLOY_TEMPLATE | xmllint --format - > $NEWFILEPATH

echo ""
echo "created new silecsdeploy: $NEW_FILE"
}



function silecs_create {
    assert_n_arguments 2

    # Resolve possible relative path
    FILE=$(realpath "$FILE" )

    EXTENSION=$(echo "$FILE" | sed 's/^.*\.//')
    FILE_PATH=$(dirname "$FILE")

    case $EXTENSION in
      design)
          NEW_FILE=$FILE_PATH/$PROJECT_NAME.silecsdesign
          silecs_create_design $NEW_FILE
          ;;
      deploy)
          NEW_FILE=$FILE_PATH/$PROJECT_NAME.silecsdeploy
          silecs_create_deploy $NEW_FILE
          ;;
      *)
          echo "Error: Passed FESA file needs to have the extension '.design' or '.deploy'"
          exit 1
          ;;
    esac
}



function silecs_open_diag {
    assert_n_arguments 2

    # Resolve possible relative path
    FILE=$(realpath "$FILE" )

    EXTENSION=$(echo "$FILE" | sed 's/^.*\.//')
    if [ $EXTENSION -ne "silecsdeploy"]; then
        echo "Error: diag tool only can be opened for a -silecsdeploy file"
    fi

    SILECS_DIAG_TOOL=$SILECS_BASE/silecs-diagnostic-cpp/$SILECS_VERSION/bin/x86_64/silecs-diagnostic
    SNAP7_LIB_FOLDER=$SILECS_BASE/snap7/$SILECS_VERSION/bin/x86_64-linux

    LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SNAP7_LIB_FOLDER
    $SILECS_DIAG_TOOL -d $FILE
}



function silecs_release_param {
    # TODO -  See here for details: https://gitlab.com/al.schwinn/silecs-cli/-/issues/5
    echo "Not implemented yet .. please copy the param file by hand for now"
}



function silecs_migrate {
    # TODO -  See here for details: https://gitlab.com/al.schwinn/silecs-cli/-/issues/7
    echo "Not implemented yet .. please update/migrate by hand for now"
}



while getopts c:v:g:d:r:m:h flag
do
    case "${flag}" in
        c ) silecs_create;;
        v ) silecs_validate;;
        g ) silecs_generate;;
        d ) silecs_open_diag;;
        r ) silecs_release_param;;
        m ) silecs_migrate;;
        h ) help;;
    esac
done