svghmi/parse_labels.ysl2
author Edouard Tisserant
Wed, 01 Mar 2023 10:54:54 +0100
changeset 3740 ac0e6de439b5
parent 3595 375626e60b63
permissions -rw-r--r--
Linux runtime: overrun detection for real-time timers and for plc execution.

If real-time timer wakes-up PLC thread too late (10% over period), then
warning is logged.

If PLC code (IO retreive, execution, IO publish) takes longer than requested
PLC execution cycle, then warning is logged, and CPU hoogging is mitigated
by delaying next PLC execution a few cylces more until having at least
1ms minimal idle time.
// parse_labels.ysl2


//  Parses:
//  "HMI:WidgetType|freq:param1:param2@a=path1,path1min,path1max@b=path2#a+b>3"
//
//  Into:
//  widget type="WidgetType" id="blah456" {
//      arg value="param1";
//      arg value="param2";
//      path value=".path1" index=".path1" min="path1min" max="path1max" type="PAGE_LOCAL";
//      path value="/path1" index="348" type="HMI_INT";
//      path value="path4" index="path4" type="HMI_LOCAL";
//  }
//
const "pathregex",!"'^(\w+=)?([^,=]+)([-.\d,]*)$'"!;

const "newline" |
const "twonewlines", "concat($newline,$newline)";

template "*", mode="parselabel"
{
    const "label","@inkscape:label";
    const "desc", "svg:desc";

    // add svg:desc field if continuation "\" marker is found at the end of label
    const "len","string-length($label)";
    const "has_continuation", "substring($label,$len,1)='\\'";
    const "full_decl" choose{
        when "$has_continuation" {
           const "_continuation", "substring-before($desc, $twonewlines)";
           const "continuation" choose {
               when "$_continuation" value "$_continuation";
               otherwise value "$desc";
           }
           value "concat(substring($label,1,$len - 1),translate($continuation,$newline,''))";
        }
        otherwise value "$label";
    }

    const "id","@id";

    const "declaration", "substring-after($full_decl,'HMI:')";

    const "_args", "substring-before($declaration,'@')";
    const "args" choose {
        when "$_args" value "$_args";
        otherwise value "$declaration";
    }

    const "_typefreq", "substring-before($args,':')";
    const "typefreq" choose {
        when "$_typefreq" value "$_typefreq";
        otherwise value "$args";
    }

    const "freq", "substring-after($typefreq,'|')";

    const "_type", "substring-before($typefreq,'|')";
    const "type" choose {
        when "$_type" value "$_type";
        otherwise value "$typefreq";
    }
    if "$type" widget {
        attrib "id" > «$id»
        attrib "type" > «$type»
        if "$freq" {
            if "not(regexp:test($freq,'^[0-9]*(\.[0-9]+)?[smh]?'))" {
                error > Widget id:«$id» label:«$full_decl» has wrong syntax of frequency forcing «$freq»
            }
            attrib "freq" > «$freq»
        }

        // find "#" + JS expr at the end
        const "tail", "substring-after($declaration,'@')";
        const "taillen","string-length($tail)";
        const "has_enable", "contains($tail, '#')";
        const "paths" choose{
            when "$has_enable" {
               value "substring-before($tail,'#')";
            }
            otherwise value "$tail";
        }
        if "$has_enable" {
            const "enable_expr", "substring-after($tail,'#')";
            attrib "enable_expr" value "$enable_expr";
        }

        foreach "str:split(substring-after($args, ':'), ':')" {
            arg {
                attrib "value" > «.»
            }
        }

        // for stricter syntax checking, this should make error
        // if $paths contains "@@" or ends with "@" (empty paths)

        foreach "str:split($paths, '@')" {
            if "string-length(.) > 0" path {
                // 1 : global match
                // 2 : assign=
                // 2 : /path
                // 3 : min,max
                const "path_match", "regexp:match(.,$pathregex)";
                const "pathassign", "substring-before($path_match[2],'=')";
                const "pathminmax", "str:split($path_match[4],',')";
                const "path", "$path_match[3]";
                const "pathminmaxcount", "count($pathminmax)";
                if "not($path)"
                    error > Widget id:«$id» label:«$full_decl» has wrong syntax

                attrib "value" value "$path";
                if "$pathassign"
                    attrib "assign" value "$pathassign";
                choose {
                    when "$pathminmaxcount = 2" {
                        attrib "min" > «$pathminmax[1]»
                        attrib "max" > «$pathminmax[2]»
                    }
                    when "$pathminmaxcount = 1 or $pathminmaxcount > 2" {
                        error > Widget id:«$id» label:«$full_decl» has wrong syntax of path section «$pathminmax»
                    }
                }
                if "$indexed_hmitree" choose {
                    when "regexp:test($path,'^\.[a-zA-Z0-9_]+$')" {
                        attrib "type" > PAGE_LOCAL
                    }
                    when "regexp:test($path,'^[a-zA-Z0-9_]+$')" {
                        attrib "type" > HMI_LOCAL
                    }
                    otherwise {
                        const "item", "$indexed_hmitree/*[@hmipath = $path]";
                        const "pathtype", "local-name($item)";
                        if "$pathminmaxcount = 3 and not($pathtype = 'HMI_INT' or $pathtype = 'HMI_REAL')" {
                            error > Widget id:«$id» label:«$full_decl» path section «$pathminmax» use min and max on non mumeric value
                        }
                        if "count($item) = 1" {
                            attrib "index" > «$item/@index»
                            attrib "type" > «$pathtype»
                        }
                    }
                }
            }
        }
        choose{
            when "$has_continuation" {
               const "_continuation", "substring-after($desc, $twonewlines)";
               if "$_continuation"
                       desc value "$_continuation";
            }
            otherwise
                if "$desc" desc value "$desc/text()";
        }
    }
}


// Templates to generate label back from parsed tree
template "arg", mode="genlabel" > :«@value»

template "path", mode="genlabel" {
    > @«@value»
    if "string-length(@min)>0 or string-length(@max)>0"  > ,«@min»,«@max»
}

template "widget", mode="genlabel" {
    > HMI:«@type»
    apply "arg", mode="genlabel";
    apply "path", mode="genlabel";
}