Exemple #1
0
    def __init__(self):
        CodeFile.__init__(self)

        filepath = self.PythonFileName()

        if os.path.isfile(filepath):
            PythonParser = GenerateParserFromXSD(
                paths.AbsNeighbourFile(__file__, "py_ext_xsd.xsd"))

            xmlfile = open(filepath, 'r')
            pythonfile_xml = xmlfile.read()
            xmlfile.close()

            pythonfile_xml = pythonfile_xml.replace(
                'xmlns="http://www.w3.org/2001/XMLSchema"',
                'xmlns:xhtml="http://www.w3.org/1999/xhtml"')
            for cre, repl in [(re.compile(r"(?<!<xhtml:p>)(?:<!\[CDATA\[)"),
                               "<xhtml:p><![CDATA["),
                              (re.compile(r"(?:]]>)(?!</xhtml:p>)"),
                               "]]></xhtml:p>")]:
                pythonfile_xml = cre.sub(repl, pythonfile_xml)

            try:
                python_code, error = PythonParser.LoadXMLString(pythonfile_xml)
                if error is None:
                    self.CodeFile.globals.setanyText(python_code.getanyText())
                    os.remove(filepath)
                    self.CreateCodeFileBuffer(False)
                    self.OnCTNSave()
            except Exception as exc:
                error = str(exc)

            if error is not None:
                self.GetCTRoot().logger.write_error(
                    _("Couldn't import old %s file.") % self.CTNName())
Exemple #2
0
    def Generate_C(self, buildpath, varlist, IECCFLAGS):

        plc_python_filepath = paths.AbsNeighbourFile(__file__, "plc_python.c")
        plc_python_file = open(plc_python_filepath, 'r')
        plc_python_code = plc_python_file.read()
        plc_python_file.close()
        python_eval_fb_list = []
        for v in varlist:
            if v["vartype"] == "FB" and v["type"] in [
                    "PYTHON_EVAL", "PYTHON_POLL"
            ]:
                python_eval_fb_list.append(v)
        python_eval_fb_count = max(1, len(python_eval_fb_list))

        # prepare python code
        plc_python_code = plc_python_code % {
            "python_eval_fb_count": python_eval_fb_count
        }

        Gen_Pythonfile_path = os.path.join(buildpath, "py_ext.c")
        pythonfile = open(Gen_Pythonfile_path, 'w')
        pythonfile.write(plc_python_code)
        pythonfile.close()

        return (["py_ext"], [(Gen_Pythonfile_path, IECCFLAGS)], True), ""
Exemple #3
0
def GetCode(name):
    filename = paths.AbsNeighbourFile(__file__, name)
    return open(filename).read()
Exemple #4
0
def GetHeader():
    filename = paths.AbsNeighbourFile(__file__, "beremiz.h")
    return open(filename).read()
Exemple #5
0
 def GetLibraryPath(self):
     return paths.AbsNeighbourFile(__file__, "pous.xml")
Exemple #6
0
    def CTNGenerate_C(self, buildpath, locations):
        # Determine the current location in Beremiz's project configuration
        # tree
        current_location = self.GetCurrentLocation()
        # The current location of this plugin in Beremiz's configuration tree, separated by underscores
        #  NOTE: Since BACnet plugin currently does not use sub-branches in the tree (in other words, this
        #        _BacnetSlavePlug class was actually renamed as the RootClass), the current_location_dots
        #        will actually be a single number (e.g.: 0 or 3 or 6, corresponding to the location
        #        in which the plugin was inserted in the Beremiz configuration tree on Beremiz's left panel).
        locstr = "_".join(map(str, current_location))

        # First check whether all the current parameters (inserted by user in
        # the GUI) are valid...
        if self.HasDuplicateObjectNames():
            self.GetCTRoot().logger.write_warning(
                _("Error: BACnet server '{a1}.x:{a2}' contains objects with duplicate object names.\n"
                  ).format(a1=locstr, a2=self.CTNName()))
            raise Exception(False)
            # TODO: return an error code instead of raising an exception
            # (currently unsupported by Beremiz)

        if self.HasDuplicateObjectIDs():
            self.GetCTRoot().logger.write_warning(
                _("Error: BACnet server '{a1}.x: {a2}' contains objects with duplicate object identifiers.\n"
                  ).format(a1=locstr, a2=self.CTNName()))
            raise Exception(False)
            # TODO: return an error code instead of raising an exception
            # (currently unsupported by Beremiz)

        # -------------------------------------------------------------------------------
        # Create and populate the loc_dict dictionary with all parameters needed to configure
        #  the generated source code (.c and .h files)
        # ----------------------------------------------------------------------

        # 1) Create the dictionary (loc_dict = {})
        loc_dict = {}
        loc_dict["locstr"] = locstr

        # The BACnetServerNode attribute is added dynamically by ConfigTreeNode._AddParamsMembers()
        # It will be an XML parser object created by
        # GenerateParserFromXSDstring(self.XSD).CreateRoot()
        #
        # Note: Override_Parameters_Saved_on_PLC is converted to an integer by int()
        #       The above flag is not currently in use. It requires further thinking on how the
        #       user will interpret and interact with this user interface...
        # loc_dict["Override_Parameters_Saved_on_PLC"] = int(self.BACnetServerNode.getOverride_Parameters_Saved_on_PLC())
        loc_dict[
            "network_interface"] = self.BACnetServerNode.getNetwork_Interface(
            )
        loc_dict["port_number"] = self.BACnetServerNode.getUDP_Port_Number()
        loc_dict[
            "BACnet_Device_ID"] = self.BACnetServerNode.getBACnet_Device_ID()
        loc_dict[
            "BACnet_Device_Name"] = self.BACnetServerNode.getBACnet_Device_Name(
            )
        loc_dict[
            "BACnet_Comm_Control_Password"] = self.BACnetServerNode.getBACnet_Communication_Control_Password(
            )
        loc_dict[
            "BACnet_Device_Location"] = self.BACnetServerNode.getBACnet_Device_Location(
            )
        loc_dict[
            "BACnet_Device_Description"] = self.BACnetServerNode.getBACnet_Device_Description(
            )
        loc_dict[
            "BACnet_Device_AppSoft_Version"] = self.BACnetServerNode.getBACnet_Device_Application_Software_Version(
            )
        loc_dict["BACnet_Vendor_ID"] = BACNET_VENDOR_ID
        loc_dict["BACnet_Vendor_Name"] = BACNET_VENDOR_NAME
        loc_dict["BACnet_Model_Name"] = BACNET_DEVICE_MODEL_NAME
        loc_dict["BACnet_Param_String_Size"] = BACNET_PARAM_STRING_SIZE

        # 2) Add the data specific to each BACnet object type
        # For each BACnet object type, start off by creating some intermediate helpful lists
        #  a) parameters_list containing the strings that will
        #     be included in the C source code, and which will initialize the struct with the
        #     object (Analog Value, Binary Value, or Multi State Value) parameters
        #  b) locatedvar_list containing the strings that will
        #     declare the memory to store the located variables, as well as the
        #     pointers (required by matiec) that point to that memory.

        # format for delaring IEC 61131-3 variable (and pointer) onto which
        # BACnet object is mapped
        locvar_format = '%(Ctype)s ___%(loc)s_%(Object Identifier)s; ' + \
                        '%(Ctype)s *__%(loc)s_%(Object Identifier)s = &___%(loc)s_%(Object Identifier)s;'

        # format for initializing a ANALOG_VALUE_DESCR struct in C code
        #    also valid for ANALOG_INPUT and ANALOG_OUTPUT
        AX_params_format = '{&___%(loc)s_%(Object Identifier)s, ' + \
                           '%(Object Identifier)s, "%(Object Name)s", "%(Description)s", %(Unit ID)d}'
        # format for initializing a BINARY_VALUE_DESCR struct in C code
        #    also valid for BINARY_INPUT and BINARY_OUTPUT
        BX_params_format = '{&___%(loc)s_%(Object Identifier)s, ' + \
                           '%(Object Identifier)s, "%(Object Name)s", "%(Description)s"}'

        # format for initializing a MULTISTATE_VALUE_DESCR struct in C code
        #    also valid for MULTISTATE_INPUT and MULTISTATE_OUTPUT
        MSX_params_format = '{&___%(loc)s_%(Object Identifier)s, ' + \
                            '%(Object Identifier)s, "%(Object Name)s", "%(Description)s", %(Number of States)s}'

        # see the comment in GetVariableLocationTree()
        AV_locstr = 'MD' + locstr + '_2'
        AO_locstr = 'QD' + locstr + '_1'
        AI_locstr = 'ID' + locstr + '_0'
        BV_locstr = 'MX' + locstr + '_5'
        BO_locstr = 'QX' + locstr + '_4'
        BI_locstr = 'IX' + locstr + '_3'
        MSV_locstr = 'MB' + locstr + '_19'
        MSO_locstr = 'QB' + locstr + '_14'
        MSI_locstr = 'IB' + locstr + '_13'

        for ObjType, ObjLocStr, params_format in [
            ("AV", AV_locstr, AX_params_format),
            ("AO", AO_locstr, AX_params_format),
            ("AI", AI_locstr, AX_params_format),
            ("BV", BV_locstr, BX_params_format),
            ("BO", BO_locstr, BX_params_format),
            ("BI", BI_locstr, BX_params_format),
            ("MSV", MSV_locstr, MSX_params_format),
            ("MSO", MSO_locstr, MSX_params_format),
            ("MSI", MSI_locstr, MSX_params_format)
        ]:
            parameters_list = []
            locatedvar_list = []
            self.ObjTables[ObjType + "_Obj"].UpdateAllVirtualProperties()
            for ObjProp in self.ObjTablesData[ObjType + "_Obj"]:
                ObjProp["loc"] = ObjLocStr
                parameters_list.append(params_format % ObjProp)
                locatedvar_list.append(locvar_format % ObjProp)
            loc_dict[ObjType + "_count"] = len(parameters_list)
            loc_dict[ObjType + "_param"] = ",\n".join(parameters_list)
            loc_dict[ObjType + "_lvars"] = "\n".join(locatedvar_list)

        # ----------------------------------------------------------------------
        # Create the C source files that implement the BACnet server
        # ----------------------------------------------------------------------

        # Names of the .c files that will be generated, based on a template file with same name
        #   (names without '.c'  --> this will be added later)
        #   main server.c file is handled separately
        Generated_BACnet_c_mainfile = "server"
        Generated_BACnet_c_files = [
            "ai", "ao", "av", "bi", "bo", "bv", "msi", "mso", "msv", "device"
        ]

        # Names of the .h files that will be generated, based on a template file with same name
        #   (names without '.h'  --> this will be added later)
        Generated_BACnet_h_files = [
            "server", "device", "config_bacnet_for_beremiz", "ai", "ao", "av",
            "bi", "bo", "bv", "msi", "mso", "msv"
        ]

        # Generate the files with the source code
        postfix = "_".join(map(str, current_location))
        template_file_dir = os.path.join(os.path.split(__file__)[0], "runtime")

        def generate_file(file_name, extension):
            generate_file_name = os.path.join(
                buildpath, "%s_%s.%s" % (file_name, postfix, extension))
            template_file_name = os.path.join(template_file_dir,
                                              "%s.%s" % (file_name, extension))
            generate_file_content = open(template_file_name).read() % loc_dict
            generate_file_handle = open(generate_file_name,
                                        'w',
                                        encoding='utf-8')
            generate_file_handle.write(generate_file_content)
            generate_file_handle.close()

        for file_name in Generated_BACnet_c_files:
            generate_file(file_name, "c")
        for file_name in Generated_BACnet_h_files:
            generate_file(file_name, "h")
        generate_file(Generated_BACnet_c_mainfile, "c")
        Generated_BACnet_c_mainfile_name = \
            os.path.join(buildpath, "%s_%s.%s" %
                         (Generated_BACnet_c_mainfile, postfix, "c"))

        # ----------------------------------------------------------------------
        # Finally, define the compilation and linking commands and flags
        # ----------------------------------------------------------------------

        LDFLAGS = []
        # when using dynamically linked library...
        # LDFLAGS.append(' -lbacnet')
        # LDFLAGS.append(' -L"'+BacnetLibraryPath+'"')
        # LDFLAGS.append(' "-Wl,-rpath,' + BacnetLibraryPath + '"')
        # when using static library:
        LDFLAGS.append(' "' + os.path.join(BacnetLibraryPath, "libbacnet.a") +
                       '"')

        CFLAGS = ' -I"' + BacnetIncludePath + '"'
        CFLAGS += ' -I"' + BacnetIncludePortPath + '"'

        # ----------------------------------------------------------------------
        # Create a file containing the default configuration paramters.
        # Beremiz will then transfer this file to the PLC, where the web server
        # will read it to obtain the default configuration parameters.
        # ----------------------------------------------------------------------
        # NOTE: This is no loner needed! The web interface will read these
        # parameters directly from the compiled C code (.so file)
        #
        ### extra_file_name   = os.path.join(buildpath, "%s_%s.%s" % ('bacnet_extrafile', postfix, 'txt'))
        ### extra_file_handle = open(extra_file_name, 'w')
        ###
        ### proplist = ["network_interface", "port_number", "BACnet_Device_ID", "BACnet_Device_Name",
        ###             "BACnet_Comm_Control_Password", "BACnet_Device_Location",
        ###             "BACnet_Device_Description", "BACnet_Device_AppSoft_Version"]
        ### for propname in proplist:
        ###     extra_file_handle.write("%s:%s\n" % (propname, loc_dict[propname]))
        ###
        ### extra_file_handle.close()
        ### extra_file_handle = open(extra_file_name, 'r')

        # Format of data to return:
        #   [(Cfiles, CFLAGS), ...], LDFLAGS, DoCalls, extra_files
        # LDFLAGS     = ['flag1', 'flag2', ...]
        # DoCalls     = true  or  false
        # extra_files = (fname,fobject), ...
        # fobject     = file object, already open'ed for read() !!
        #
        # extra_files -> files that will be downloaded to the PLC!

        websettingfile = open(
            paths.AbsNeighbourFile(__file__, "web_settings.py"), 'r')
        websettingcode = websettingfile.read()
        websettingfile.close()

        location_str = "_".join(map(str, self.GetCurrentLocation()))
        websettingcode = websettingcode % locals()

        runtimefile_path = os.path.join(buildpath,
                                        "runtime_bacnet_websettings.py")
        runtimefile = open(runtimefile_path, 'w')
        runtimefile.write(websettingcode)
        runtimefile.close()

        return (
            [(Generated_BACnet_c_mainfile_name, CFLAGS)],
            LDFLAGS,
            True,
            ['bacnet'],
            ("runtime_bacnet_websettings_%s.py" % location_str,
             open(runtimefile_path, "r", encoding='utf-8')),
        )
Exemple #7
0
    def CTNGenerate_C(self, buildpath, locations):
        # print "#############"
        # print self.__class__
        # print type(self)
        # print "self.CTNType >>>"
        # print self.CTNType
        # print "type(self.CTNType) >>>"
        # print type(self.CTNType)
        # print "#############"

        loc_dict = {"locstr": "_".join(map(str, self.GetCurrentLocation()))}

        # Determine the number of (modbus library) nodes ALL instances of the modbus plugin will need
        #   total_node_count: (tcp nodes, rtu nodes, ascii nodes)
        #
        # Also get a list with tuples of (location, IP address, port number) used by all the Modbus/IP server nodes
        #   This list is later used to search for duplicates in port numbers!
        #   IPServer_port_numbers = [(location, IP address, port number), ...]
        #       location            : tuple similar to (0, 3, 1) representing the location in the configuration tree "0.3.1.x"
        #       IPserver_port_number: a number (i.e. port number used by the Modbus/IP server)
        #       IP address          : IP address of the network interface on which the server will be listening
        #                             ("", "*", or "#ANY#" => listening on all interfaces!)
        #
        # Also get a list with tuples of (location, Configuration_Name) used by all the Modbus nodes
        #   This list is later used to search for duplicates in Configuration Names!
        #   Node_Configuration_Names = [(location, Configuration_Name), ...]
        #       location          : tuple similar to (0, 3, 1) representing the location in the configuration tree "0.3.1.x"
        #       Configuration_Name: the "Configuration_Name" string
        total_node_count = (0, 0, 0)
        IPServer_port_numbers = []
        Node_Configuration_Names = []
        for CTNInstance in self.GetCTRoot().IterChildren():
            if CTNInstance.CTNType == "modbus":
                # ask each modbus plugin instance how many nodes it needs, and add them all up.
                total_node_count = tuple(x1 + x2 for x1, x2 in zip(
                    total_node_count, CTNInstance.GetNodeCount()))
                IPServer_port_numbers.extend(
                    CTNInstance.GetIPServerPortNumbers())
                Node_Configuration_Names.extend(CTNInstance.GetConfigNames())

        # Search for use of duplicate Configuration_Names by Modbus nodes
        # Configuration Names are used by the web server running on the PLC
        # (more precisely, run by Beremiz_service.py) to identify and allow
        # changing the Modbus parameters after the program has been downloaded
        # to the PLC (but before it is started)
        # With clashes in the configuration names, the Modbus nodes will not be
        # distinguasheble on the web interface!
        for i in range(0, len(Node_Configuration_Names) - 1):
            for j in range(i + 1, len(Node_Configuration_Names)):
                if Node_Configuration_Names[i][1] == Node_Configuration_Names[
                        j][1]:
                    error_message = _(
                        "Error: Modbus plugin nodes %{a1}.x and %{a2}.x use the same Configuration_Name \"{a3}\".\n"
                    ).format(a1=_lt_to_str(Node_Configuration_Names[i][0]),
                             a2=_lt_to_str(Node_Configuration_Names[j][0]),
                             a3=Node_Configuration_Names[j][1])
                    self.FatalError(error_message)

        # Search for use of duplicate port numbers by Modbus/IP servers
        # Note: We only consider duplicate port numbers if using the same network interface!
        i = 0
        for loc1, addr1, port1 in IPServer_port_numbers[:-1]:
            i = i + 1
            for loc2, addr2, port2 in IPServer_port_numbers[i:]:
                if (port1 == port2) and (
                    (addr1 == addr2)  # on the same network interface
                        or (addr1 == "") or (addr1 == "*") or
                    (addr1 == "#ANY#")  # or one (or both) of the servers
                        or (addr2 == "") or (addr2 == "*") or
                    (addr2 == "#ANY#")  # use all available network interfaces
                ):
                    error_message = _(
                        "Error: Modbus plugin nodes %{a1}.x and %{a2}.x use same port number \"{a3}\" "
                        +
                        "on the same (or overlapping) network interfaces \"{a4}\" and \"{a5}\".\n"
                    ).format(a1=_lt_to_str(loc1),
                             a2=_lt_to_str(loc2),
                             a3=port1,
                             a4=addr1,
                             a5=addr2)
                    self.FatalError(error_message)

        # Determine the current location in Beremiz's project configuration
        # tree
        current_location = self.GetCurrentLocation()

        # define a unique name for the generated C and h files
        prefix = "_".join(map(str, current_location))
        Gen_MB_c_path = os.path.join(buildpath, "MB_%s.c" % prefix)
        Gen_MB_h_path = os.path.join(buildpath, "MB_%s.h" % prefix)
        c_filename = os.path.join(os.path.split(__file__)[0], "mb_runtime.c")
        h_filename = os.path.join(os.path.split(__file__)[0], "mb_runtime.h")

        tcpclient_reqs_count = 0
        rtuclient_reqs_count = 0
        ascclient_reqs_count = 0
        tcpclient_node_count = 0
        rtuclient_node_count = 0
        ascclient_node_count = 0
        tcpserver_node_count = 0
        rtuserver_node_count = 0
        ascserver_node_count = 0
        nodeid = 0
        client_nodeid = 0
        client_requestid = 0
        server_id = 0

        server_node_list = []
        client_node_list = []
        client_request_list = []
        server_memarea_list = []
        loc_vars = []
        loc_vars_list = []  # list of variables already declared in C code!
        for child in self.IECSortedChildren():
            # print "<<<<<<<<<<<<<"
            # print "child (self.IECSortedChildren())----->"
            # print child.__class__
            # print ">>>>>>>>>>>>>"
            #
            if child.PlugType == "ModbusTCPserver":
                tcpserver_node_count += 1
                new_node = GetTCPServerNodePrinted(self, child)
                if new_node is None:
                    return [], "", False
                server_node_list.append(new_node)
                #
                for subchild in child.IECSortedChildren():
                    new_memarea = GetTCPServerMemAreaPrinted(
                        self, subchild, nodeid)
                    if new_memarea is None:
                        return [], "", False
                    server_memarea_list.append(new_memarea)
                    function = subchild.GetParamsAttributes(
                    )[0]["children"][0]["value"]
                    # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
                    memarea = modbus_memtype_dict[function][1]
                    for iecvar in subchild.GetLocations():
                        # print repr(iecvar)
                        absloute_address = iecvar["LOC"][3]
                        start_address = int(GetCTVal(subchild, 2))
                        relative_addr = absloute_address - start_address
                        # test if relative address in request specified range
                        if relative_addr in xrange(int(GetCTVal(subchild, 1))):
                            if str(iecvar["NAME"]) not in loc_vars_list:
                                loc_vars.append(
                                    "u16 *" + str(iecvar["NAME"]) +
                                    " = &server_nodes[%d].mem_area.%s[%d];" %
                                    (server_id, memarea, absloute_address))
                                loc_vars_list.append(str(iecvar["NAME"]))
                server_id += 1
            #
            if child.PlugType == "ModbusRTUslave":
                rtuserver_node_count += 1
                new_node = GetRTUSlaveNodePrinted(self, child)
                if new_node is None:
                    return [], "", False
                server_node_list.append(new_node)
                #
                for subchild in child.IECSortedChildren():
                    new_memarea = GetTCPServerMemAreaPrinted(
                        self, subchild, nodeid)
                    if new_memarea is None:
                        return [], "", False
                    server_memarea_list.append(new_memarea)
                    function = subchild.GetParamsAttributes(
                    )[0]["children"][0]["value"]
                    # 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
                    memarea = modbus_memtype_dict[function][1]
                    for iecvar in subchild.GetLocations():
                        # print repr(iecvar)
                        absloute_address = iecvar["LOC"][3]
                        start_address = int(GetCTVal(subchild, 2))
                        relative_addr = absloute_address - start_address
                        # test if relative address in request specified range
                        if relative_addr in xrange(int(GetCTVal(subchild, 1))):
                            if str(iecvar["NAME"]) not in loc_vars_list:
                                loc_vars.append(
                                    "u16 *" + str(iecvar["NAME"]) +
                                    " = &server_nodes[%d].mem_area.%s[%d];" %
                                    (server_id, memarea, absloute_address))
                                loc_vars_list.append(str(iecvar["NAME"]))
                server_id += 1
            #
            if child.PlugType == "ModbusTCPclient":
                tcpclient_reqs_count += len(child.IECSortedChildren())
                new_node = GetTCPClientNodePrinted(self, child)
                if new_node is None:
                    return [], "", False
                client_node_list.append(new_node)
                for subchild in child.IECSortedChildren():
                    new_req = GetClientRequestPrinted(self, subchild,
                                                      client_nodeid)
                    if new_req is None:
                        return [], "", False
                    client_request_list.append(new_req)
                    for iecvar in subchild.GetLocations():
                        # absloute address - start address
                        relative_addr = iecvar["LOC"][3] - int(
                            GetCTVal(subchild, 3))
                        # test if the located variable
                        #    (a) has relative address in request specified range
                        #  AND is NOT
                        #    (b) is a control flag added by this modbus plugin
                        #        to control its execution at runtime.
                        #        Currently, we only add the "Execution Control Flag"
                        #        to each client request (one flag per request)
                        #        to control when to execute the request (if not executed periodically)
                        #        While all Modbus registers/coils are mapped onto a location
                        #        with 4 numbers (e.g. %QX0.1.2.55), this control flag is mapped
                        #        onto a location with 4 numbers (e.g. %QX0.1.2.0.0), where the last
                        #        two numbers are always '0.0', and the first two identify the request.
                        #        In the following if, we check for this condition by checking
                        #        if their are at least 4 or more number in the location's address.
                        if (relative_addr in xrange(int(GetCTVal(
                                subchild, 2)))  # condition (a) explained above
                                and len(iecvar["LOC"]) <
                                5):  # condition (b) explained above
                            if str(iecvar["NAME"]) not in loc_vars_list:
                                loc_vars.append(
                                    "u16 *" + str(iecvar["NAME"]) +
                                    " = &client_requests[%d].plcv_buffer[%d];"
                                    % (client_requestid, relative_addr))
                                loc_vars_list.append(str(iecvar["NAME"]))
                        # Now add the located variable in case it is a flag (condition (b) above
                        if len(iecvar["LOC"]
                               ) >= 5:  # condition (b) explained above
                            if str(iecvar["NAME"]) not in loc_vars_list:
                                loc_vars.append(
                                    "u16 *" + str(iecvar["NAME"]) +
                                    " = &client_requests[%d].flag_exec_req;" %
                                    (client_requestid))
                                loc_vars_list.append(str(iecvar["NAME"]))
                    client_requestid += 1
                tcpclient_node_count += 1
                client_nodeid += 1
            #
            if child.PlugType == "ModbusRTUclient":
                rtuclient_reqs_count += len(child.IECSortedChildren())
                new_node = GetRTUClientNodePrinted(self, child)
                if new_node is None:
                    return [], "", False
                client_node_list.append(new_node)
                for subchild in child.IECSortedChildren():
                    new_req = GetClientRequestPrinted(self, subchild,
                                                      client_nodeid)
                    if new_req is None:
                        return [], "", False
                    client_request_list.append(new_req)
                    for iecvar in subchild.GetLocations():
                        # absloute address - start address
                        relative_addr = iecvar["LOC"][3] - int(
                            GetCTVal(subchild, 3))
                        # test if the located variable
                        #    (a) has relative address in request specified range
                        #  AND is NOT
                        #    (b) is a control flag added by this modbus plugin
                        #        to control its execution at runtime.
                        #        Currently, we only add the "Execution Control Flag"
                        #        to each client request (one flag per request)
                        #        to control when to execute the request (if not executed periodically)
                        #        While all Modbus registers/coils are mapped onto a location
                        #        with 4 numbers (e.g. %QX0.1.2.55), this control flag is mapped
                        #        onto a location with 4 numbers (e.g. %QX0.1.2.0.0), where the last
                        #        two numbers are always '0.0', and the first two identify the request.
                        #        In the following if, we check for this condition by checking
                        #        if their are at least 4 or more number in the location's address.
                        if (relative_addr in xrange(int(GetCTVal(
                                subchild, 2)))  # condition (a) explained above
                                and len(iecvar["LOC"]) <
                                5):  # condition (b) explained above
                            if str(iecvar["NAME"]) not in loc_vars_list:
                                loc_vars.append(
                                    "u16 *" + str(iecvar["NAME"]) +
                                    " = &client_requests[%d].plcv_buffer[%d];"
                                    % (client_requestid, relative_addr))
                                loc_vars_list.append(str(iecvar["NAME"]))
                        # Now add the located variable in case it is a flag (condition (b) above
                        if len(iecvar["LOC"]
                               ) >= 5:  # condition (b) explained above
                            if str(iecvar["NAME"]) not in loc_vars_list:
                                loc_vars.append(
                                    "u16 *" + str(iecvar["NAME"]) +
                                    " = &client_requests[%d].flag_exec_req;" %
                                    (client_requestid))
                                loc_vars_list.append(str(iecvar["NAME"]))
                    client_requestid += 1
                rtuclient_node_count += 1
                client_nodeid += 1
            nodeid += 1

        loc_dict["loc_vars"] = "\n".join(loc_vars)
        loc_dict["server_nodes_params"] = ",\n\n".join(server_node_list)
        loc_dict["client_nodes_params"] = ",\n\n".join(client_node_list)
        loc_dict["client_req_params"] = ",\n\n".join(client_request_list)
        loc_dict["tcpclient_reqs_count"] = str(tcpclient_reqs_count)
        loc_dict["tcpclient_node_count"] = str(tcpclient_node_count)
        loc_dict["tcpserver_node_count"] = str(tcpserver_node_count)
        loc_dict["rtuclient_reqs_count"] = str(rtuclient_reqs_count)
        loc_dict["rtuclient_node_count"] = str(rtuclient_node_count)
        loc_dict["rtuserver_node_count"] = str(rtuserver_node_count)
        loc_dict["ascclient_reqs_count"] = str(ascclient_reqs_count)
        loc_dict["ascclient_node_count"] = str(ascclient_node_count)
        loc_dict["ascserver_node_count"] = str(ascserver_node_count)
        loc_dict["total_tcpnode_count"] = str(total_node_count[0])
        loc_dict["total_rtunode_count"] = str(total_node_count[1])
        loc_dict["total_ascnode_count"] = str(total_node_count[2])
        loc_dict["max_remote_tcpclient"] = int(
            self.GetParamsAttributes()[0]["children"][0]["value"])

        # get template file content into a string, format it with dict
        # and write it to proper .h file
        mb_main = open(h_filename).read() % loc_dict
        f = open(Gen_MB_h_path, 'w')
        f.write(mb_main)
        f.close()
        # same thing as above, but now to .c file
        mb_main = open(c_filename).read() % loc_dict
        f = open(Gen_MB_c_path, 'w')
        f.write(mb_main)
        f.close()

        LDFLAGS = []
        LDFLAGS.append(" \"-L" + ModbusPath + "\"")
        LDFLAGS.append(" \"" + os.path.join(ModbusPath, "libmb.a") + "\"")
        LDFLAGS.append(" \"-Wl,-rpath," + ModbusPath + "\"")
        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_slave_and_master.o") + "\"")
        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_slave.o") + "\"")
        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_master.o") + "\"")
        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_tcp.o")    + "\"")
        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_rtu.o")    + "\"")
        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "mb_ascii.o")    + "\"")
        # LDFLAGS.append("\"" + os.path.join(ModbusPath, "sin_util.o")  + "\"")
        # Target is ARM with linux and not win on x86 so winsock2 (ws2_32) library is useless !!!
        # if os.name == 'nt':   # other possible values: 'posix' 'os2' 'ce' 'java' 'riscos'
        # LDFLAGS.append(" -lws2_32 ")  # on windows we need to load winsock
        # library!

        websettingfile = open(
            paths.AbsNeighbourFile(__file__, "web_settings.py"), 'r')
        websettingcode = websettingfile.read()
        websettingfile.close()

        location_str = "_".join(map(str, self.GetCurrentLocation()))
        websettingcode = websettingcode % locals()

        runtimefile_path = os.path.join(buildpath,
                                        "runtime_modbus_websettings.py")
        runtimefile = open(runtimefile_path, 'w')
        runtimefile.write(websettingcode)
        runtimefile.close()

        return (
            [(Gen_MB_c_path, ' -I"' + ModbusPath + '"')],
            LDFLAGS,
            True,
            ("runtime_modbus_websettings_%s.py" % location_str,
             open(runtimefile_path, "rb")),
        )
Exemple #8
0
    def CTNGenerate_C(self, buildpath, locations):
        can_driver = self.GetCanDriver()
        if can_driver is not None:
            can_drivers = local_canfestival_config.DLL_LIST
            if can_driver not in can_drivers:
                can_driver = can_drivers[0]
            can_drv_ext = self.GetCTRoot().GetBuilder().extension
            can_drv_prefix = self.GetCTRoot().GetBuilder().dlopen_prefix
            can_driver_name = can_drv_prefix + "libcanfestival_" + can_driver + can_drv_ext
        else:
            can_driver_name = ""

        format_dict = {
            "locstr": "_".join(map(str, self.GetCurrentLocation())),
            "candriver": can_driver_name,
            "nodes_includes": "",
            "board_decls": "",
            "nodes_init": "",
            "nodes_open": "",
            "nodes_stop": "",
            "nodes_close": "",
            "nodes_send_sync": "",
            "nodes_proceed_sync": "",
            "slavebootups": "",
            "slavebootup_register": "",
            "post_sync": "",
            "post_sync_register": "",
            "pre_op": "",
            "pre_op_register": "",
        }
        for child in self.IECSortedChildren():
            childlocstr = "_".join(map(str, child.GetCurrentLocation()))
            nodename = "OD_%s" % childlocstr

            # Try to get Slave Node
            child_data = getattr(child, "CanFestivalSlaveNode", None)
            if child_data is None:
                # Not a slave -> master
                child_data = getattr(child, "CanFestivalNode")
                # Apply sync setting
                format_dict[
                    "nodes_init"] += 'NODE_MASTER_INIT(%s, %s)\n    ' % (
                        nodename, child_data.getNodeId())
                if child_data.getSync_TPDOs():
                    format_dict[
                        "nodes_send_sync"] += 'NODE_SEND_SYNC(%s)\n    ' % (
                            nodename)
                    format_dict[
                        "nodes_proceed_sync"] += 'NODE_PROCEED_SYNC(%s)\n    ' % (
                            nodename)

                # initialize and declare node boot status variables for post_SlaveBootup lookup
                SlaveIDs = child.GetSlaveIDs()
                if len(SlaveIDs) == 0:
                    # define post_SlaveBootup lookup functions
                    format_dict["slavebootups"] += (
                        "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){}\n"
                        % (nodename))
                else:
                    format_dict["slavebootups"] += (
                        "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n"
                        % (nodename) +
                        "    check_and_start_node(d, nodeId);\n" + "}\n")
                # register previously declared func as post_SlaveBootup callback for that node
                format_dict["slavebootup_register"] += (
                    "%s_Data.post_SlaveBootup = %s_post_SlaveBootup;\n" %
                    (nodename, nodename))
                format_dict["pre_op"] += (
                    "static void %s_preOperational(CO_Data* d){\n    " %
                    (nodename) + "".join([
                        "    masterSendNMTstateChange(d, %d, NMT_Reset_Comunication);\n"
                        % NdId for NdId in SlaveIDs
                    ]) + "}\n")
                format_dict["pre_op_register"] += (
                    "%s_Data.preOperational = %s_preOperational;\n" %
                    (nodename, nodename))
            else:
                # Slave node
                align = child_data.getSync_Align()
                align_ratio = child_data.getSync_Align_Ratio()
                if align > 0:
                    format_dict["post_sync"] += (
                        "static int %s_CalCount = 0;\n" % (nodename) +
                        "static void %s_post_sync(CO_Data* d){\n" %
                        (nodename) + "    if(%s_CalCount < %d){\n" %
                        (nodename, align) + "        %s_CalCount++;\n" %
                        (nodename) + "        align_tick(-1);\n" +
                        "    }else{\n" + "        align_tick(%d);\n" %
                        (align_ratio) + "    }\n" + "}\n")
                    format_dict["post_sync_register"] += (
                        "%s_Data.post_sync = %s_post_sync;\n" %
                        (nodename, nodename))
                format_dict[
                    "nodes_init"] += 'NODE_SLAVE_INIT(%s, %s)\n    ' % (
                        nodename, child_data.getNodeId())

            # Include generated OD headers
            format_dict["nodes_includes"] += '#include "%s.h"\n' % (nodename)
            # Declare CAN channels according user filled config
            format_dict["board_decls"] += 'BOARD_DECL(%s, "%s", "%s")\n' % (
                nodename, child.GetCanDevice(), child_data.getCAN_Baudrate())
            format_dict["nodes_open"] += 'NODE_OPEN(%s)\n    ' % (nodename)
            format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n    ' % (nodename)
            format_dict["nodes_stop"] += 'NODE_STOP(%s)\n    ' % (nodename)

        filename = paths.AbsNeighbourFile(__file__, "cf_runtime.c")
        cf_main = open(filename).read() % format_dict
        cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c" % format_dict)
        f = open(cf_main_path, 'w')
        f.write(cf_main)
        f.close()

        res = [
            (cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))
        ], local_canfestival_config.getLDFLAGS(CanFestivalPath), True

        if can_driver is not None:
            can_driver_path = os.path.join(CanFestivalPath, "drivers",
                                           can_driver, can_driver_name)
            if os.path.exists(can_driver_path):
                res += ((can_driver_name, file(can_driver_path, "rb")), )

        return res
Exemple #9
0
 def _getSVGUIserverpath(self):
     return paths.AbsNeighbourFile(__file__, "svgui_server.py")
Exemple #10
0
 def __init__(self, plcState=False, *a, **kw):
     super(WebInterface, self).__init__(*a, **kw)
     self.jsModules.mapping[u'WebInterface'] = paths.AbsNeighbourFile(__file__), 'webinterface.js')
     self.plcState = plcState
     self.MainPage.setPLCState(plcState)
Exemple #11
0
 def GetLibraryPath(self):
     return paths.AbsNeighbourFile(__file__, "NativeLib.xml")
Exemple #12
0
class SettingsPage(rend.Page):
    # We deserve a slash
    addSlash = True

    # This makes webform_css url answer some default CSS
    child_webform_css = webform.defaultCSS
    child_webinterface_css = File(
        paths.AbsNeighbourFile(__file__, 'webinterface.css'), 'text/css')

    implements(ISettings)

    def __getattr__(self, name):
        global extensions_settings_od
        if name.startswith('configurable_'):
            token = name[13:]

            def configurable_something(ctx):
                settings, _display = extensions_settings_od[token]
                return settings

            return configurable_something
        raise AttributeError

    def extensions_settings(self, context, data):
        """ Project extensions settings
        Extensions added to Configuration Tree in IDE have their setting rendered here
        """
        global extensions_settings_od
        res = []
        for token in extensions_settings_od:
            _settings, display = extensions_settings_od[token]
            res += [tags.h2[display], webform.renderForms(token)]
        return res

    docFactory = loaders.stan([
        tags.html[
            tags.head[tags.title[_("Beremiz Runtime Settings")],
                      tags.link(rel='stylesheet',
                                type='text/css',
                                href=url.here.child("webform_css")),
                      tags.link(rel='stylesheet',
                                type='text/css',
                                href=url.here.child("webinterface_css"))],
            tags.body[tags.a(href='/')['Back'], tags.h1["Runtime settings:"],
                      webform.renderForms('staticSettings'),
                      tags.h1["Extensions settings:"],
                      webform.renderForms('dynamicSettings'),
                      extensions_settings]]
    ])

    def configurable_staticSettings(self, ctx):
        return configurable.TypedInterfaceConfigurable(self)

    def configurable_dynamicSettings(self, ctx):
        """ Runtime Extensions settings
        Extensions loaded through Beremiz_service -e or optional runtime features render setting forms here
        """
        return ConfigurableSettings

    def sendLogMessage(self, level, message, **kwargs):
        level = LogLevelsDict[level]
        if _PySrv.plcobj is not None:
            _PySrv.plcobj.LogMessage(level, "Web form log message: " + message)

    def locateChild(self, ctx, segments):
        if segments[0] in customSettingsURLs:
            return customSettingsURLs[segments[0]](ctx, segments)
        return super(SettingsPage, self).locateChild(ctx, segments)
Exemple #13
0
# -*- coding: utf-8 -*-

# This file is part of Beremiz, a Integrated Development Environment for
# programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
#
# Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
# Copyright (C) 2017: Andrey Skvortsov
#
# See COPYING file for copyrights details.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

from __future__ import absolute_import
import util.paths as paths
from POULibrary import SimplePOULibraryFactory

NativeLibrary = SimplePOULibraryFactory(
    paths.AbsNeighbourFile(__file__, "NativeLib.xml"))