modbus/mb_utils.py
changeset 1918 e7b6478b4ebc
parent 1909 bb883e063175
child 1919 ccea0fa6ea91
equal deleted inserted replaced
1917:d51d14719392 1918:e7b6478b4ebc
    16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17 # GNU General Public License for more details.
    17 # GNU General Public License for more details.
    18 #
    18 #
    19 # You should have received a copy of the GNU General Public License
    19 # You should have received a copy of the GNU General Public License
    20 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
    20 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
    21 #    
    21 #
    22 # This code is made available on the understanding that it will not be
    22 # This code is made available on the understanding that it will not be
    23 # used in safety-critical situations without a full and competent review.
    23 # used in safety-critical situations without a full and competent review.
    24 
    24 
    25 
    25 
    26 
    26 # dictionary implementing:
    27 
    27 # key   - string with the description we want in the request plugin GUI
    28 #dictionary implementing:
    28 # tuple - (modbus function number, request type, max count value,
    29 #key   - string with the description we want in the request plugin GUI
    29 # data_type, bit_size)
    30 #tuple - (modbus function number, request type, max count value, data_type, bit_size)
    30 modbus_function_dict = {
    31 modbus_function_dict = {"01 - Read Coils" :               ( '1', 'req_input', 2000, "BOOL", 1 , "Q", "X", "Coil"),
    31     "01 - Read Coils":                ('1',  'req_input', 2000, "BOOL",  1, "Q", "X", "Coil"),
    32                         "02 - Read Input Discretes" :     ( '2', 'req_input', 2000, "BOOL", 1 , "I", "X", "Input Discrete"),
    32     "02 - Read Input Discretes":      ('2',  'req_input', 2000, "BOOL",  1, "I", "X", "Input Discrete"),
    33                         "03 - Read Holding Registers" :   ( '3', 'req_input',  125, "WORD", 16, "Q", "W", "Holding Register"),
    33     "03 - Read Holding Registers":    ('3',  'req_input',  125, "WORD", 16, "Q", "W", "Holding Register"),
    34                         "04 - Read Input Registers" :     ( '4', 'req_input',  125, "WORD", 16, "I", "W", "Input Register"),
    34     "04 - Read Input Registers":      ('4',  'req_input',  125, "WORD", 16, "I", "W", "Input Register"),
    35                         "05 - Write Single coil" :        ( '5','req_output',    1, "BOOL", 1 , "Q", "X", "Coil"),
    35     "05 - Write Single coil":         ('5', 'req_output',    1, "BOOL",  1, "Q", "X", "Coil"),
    36                         "06 - Write Single Register" :    ( '6','req_output',    1, "WORD", 16, "Q", "W", "Holding Register"),
    36     "06 - Write Single Register":     ('6', 'req_output',    1, "WORD", 16, "Q", "W", "Holding Register"),
    37                         "15 - Write Multiple Coils" :     ('15','req_output', 1968, "BOOL", 1 , "Q", "X", "Coil"),
    37     "15 - Write Multiple Coils":     ('15', 'req_output', 1968, "BOOL",  1, "Q", "X", "Coil"),
    38                         "16 - Write Multiple Registers" : ('16','req_output',  123, "WORD", 16, "Q", "W", "Holding Register"),
    38     "16 - Write Multiple Registers": ('16', 'req_output',  123, "WORD", 16, "Q", "W", "Holding Register")}
    39                        }
    39 
    40 
    40 
       
    41 # Configuration tree value acces helper
       
    42 def GetCTVal(child, index):
       
    43     return child.GetParamsAttributes()[0]["children"][index]["value"]
       
    44 
       
    45 
       
    46 # Configuration tree value acces helper, for multiple values
       
    47 def GetCTVals(child, indexes):
       
    48     return map(lambda index: GetCTVal(child, index), indexes)
    41 
    49 
    42 
    50 
    43 def GetTCPServerNodePrinted(self, child):
    51 def GetTCPServerNodePrinted(self, child):
    44     """
    52     """
    45     Outputs a string to be used on C files
    53     Outputs a string to be used on C files
    47     """
    55     """
    48     node_init_template = '''/*node %(locnodestr)s*/
    56     node_init_template = '''/*node %(locnodestr)s*/
    49 {"%(locnodestr)s", %(slaveid)s, {naf_tcp, {.tcp = {%(host)s, "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */}'''
    57 {"%(locnodestr)s", %(slaveid)s, {naf_tcp, {.tcp = {%(host)s, "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */}'''
    50 
    58 
    51     location = ".".join(map(str, child.GetCurrentLocation()))
    59     location = ".".join(map(str, child.GetCurrentLocation()))
    52     host     = child.GetParamsAttributes()[0]["children"][0]["value"]
    60     host, port, slaveid = GetCTVals(child, range(3))
    53     port     = child.GetParamsAttributes()[0]["children"][1]["value"]
    61     if host == "#ANY#":
    54     slaveid  = child.GetParamsAttributes()[0]["children"][2]["value"]
    62         host = 'INADDR_ANY'
    55     if host=="#ANY#":
       
    56       host='INADDR_ANY'
       
    57     else:
    63     else:
    58       host='"'+host+'"'
    64         host = '"' + host + '"'
    59     #slaveid = child.GetParamsAttributes()[0]["children"][2]["value"]
    65     # slaveid = GetCTVal(child, 2)
    60     #if int(slaveid) not in xrange(256):
    66     # if int(slaveid) not in xrange(256):
    61         #self.GetCTRoot().logger.write_error("Error: Wrong slave ID in %s server node\nModbus Plugin C code returns empty\n"%location)
    67         # self.GetCTRoot().logger.write_error("Error: Wrong slave ID in %s server node\nModbus Plugin C code returns empty\n"%location)
    62         #return None
    68         # return None
    63 
    69 
    64     node_dict = {"locnodestr" : location,
    70     node_dict = {"locnodestr": location,
    65                  "host"       : host,
    71                  "host": host,
    66                  "port"       : port,
    72                  "port": port,
    67                  "slaveid"    : slaveid,
    73                  "slaveid": slaveid,
    68                 }
    74                  }
    69     return node_init_template % node_dict
    75     return node_init_template % node_dict
    70 
       
    71 
       
    72 
    76 
    73 
    77 
    74 def GetTCPServerMemAreaPrinted(self, child, nodeid):
    78 def GetTCPServerMemAreaPrinted(self, child, nodeid):
    75     """
    79     """
    76     Outputs a string to be used on C files
    80     Outputs a string to be used on C files
    82     """
    86     """
    83     request_dict = {}
    87     request_dict = {}
    84 
    88 
    85     request_dict["locreqstr"] = "_".join(map(str, child.GetCurrentLocation()))
    89     request_dict["locreqstr"] = "_".join(map(str, child.GetCurrentLocation()))
    86     request_dict["nodeid"] = str(nodeid)
    90     request_dict["nodeid"] = str(nodeid)
    87     request_dict["address"] = child.GetParamsAttributes()[0]["children"][2]["value"]
    91     request_dict["address"] = GetCTVal(child, 2)
    88     if int(request_dict["address"]) not in xrange(65536):
    92     if int(request_dict["address"]) not in xrange(65536):
    89         self.GetCTRoot().logger.write_error("Modbus plugin: Invalid Start Address in server memory area node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n"%request_dict)
    93         self.GetCTRoot().logger.write_error(
    90         return None
    94             "Modbus plugin: Invalid Start Address in server memory area node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
    91     request_dict["count"] = child.GetParamsAttributes()[0]["children"][1]["value"]
    95         return None
       
    96     request_dict["count"] = GetCTVal(child, 1)
    92     if int(request_dict["count"]) not in xrange(1, 65536):
    97     if int(request_dict["count"]) not in xrange(1, 65536):
    93         self.GetCTRoot().logger.write_error("Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n"%request_dict)
    98         self.GetCTRoot().logger.write_error(
    94         return None
    99             "Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
    95     if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1,65537):
   100         return None
    96         self.GetCTRoot().logger.write_error("Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n"%request_dict)
   101     if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1, 65537):
    97         return None
   102         self.GetCTRoot().logger.write_error(
    98     
   103             "Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
       
   104         return None
       
   105 
    99     return ""
   106     return ""
   100 
   107 
   101 
   108 
   102 
   109 modbus_serial_baudrate_list = [
   103 
   110     "110", "300", "600", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"]
   104 modbus_serial_baudrate_list = ["110", "300", "600", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"]
       
   105 modbus_serial_stopbits_list = ["1", "2"]
   111 modbus_serial_stopbits_list = ["1", "2"]
   106 modbus_serial_parity_dict   = {"none": 0, "odd": 1, "even": 2}
   112 modbus_serial_parity_dict = {"none": 0, "odd": 1, "even": 2}
   107 
       
   108 
   113 
   109 
   114 
   110 def GetRTUSlaveNodePrinted(self, child):
   115 def GetRTUSlaveNodePrinted(self, child):
   111     """
   116     """
   112     Outputs a string to be used on C files
   117     Outputs a string to be used on C files
   114     """
   119     """
   115     node_init_template = '''/*node %(locnodestr)s*/
   120     node_init_template = '''/*node %(locnodestr)s*/
   116 {"%(locnodestr)s", %(slaveid)s, {naf_rtu, {.rtu = {"%(device)s", %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */}'''
   121 {"%(locnodestr)s", %(slaveid)s, {naf_rtu, {.rtu = {"%(device)s", %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */}'''
   117 
   122 
   118     location = ".".join(map(str, child.GetCurrentLocation()))
   123     location = ".".join(map(str, child.GetCurrentLocation()))
   119     device   = child.GetParamsAttributes()[0]["children"][0]["value"]
   124     device, baud, parity, stopbits, slaveid = GetCTVals(child, range(5))
   120     baud     = child.GetParamsAttributes()[0]["children"][1]["value"]
   125 
   121     parity   = child.GetParamsAttributes()[0]["children"][2]["value"]
   126     node_dict = {"locnodestr": location,
   122     stopbits = child.GetParamsAttributes()[0]["children"][3]["value"]
   127                  "device": device,
   123     slaveid  = child.GetParamsAttributes()[0]["children"][4]["value"]
   128                  "baud": baud,
   124     
   129                  "parity": modbus_serial_parity_dict[parity],
   125     node_dict = {"locnodestr" : location,
   130                  "stopbits": stopbits,
   126                  "device"     : device,
   131                  "slaveid": slaveid
   127                  "baud"       : baud,
   132                  }
   128                  "parity"     : modbus_serial_parity_dict[parity],
   133     return node_init_template % node_dict
   129                  "stopbits"   : stopbits,
   134 
   130                  "slaveid"    : slaveid
       
   131                 }
       
   132     return node_init_template % node_dict
       
   133 
       
   134 
       
   135 
       
   136  
       
   137 
   135 
   138 def GetRTUClientNodePrinted(self, child):
   136 def GetRTUClientNodePrinted(self, child):
   139     """
   137     """
   140     Outputs a string to be used on C files
   138     Outputs a string to be used on C files
   141     params: child - the correspondent subplugin in Beremiz
   139     params: child - the correspondent subplugin in Beremiz
   142     """
   140     """
   143     node_init_template = '''/*node %(locnodestr)s*/
   141     node_init_template = '''/*node %(locnodestr)s*/
   144 {"%(locnodestr)s", {naf_rtu, {.rtu = {"%(device)s", %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */}'''
   142 {"%(locnodestr)s", {naf_rtu, {.rtu = {"%(device)s", %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */}'''
   145 
   143 
   146     location    = ".".join(map(str, child.GetCurrentLocation()))
   144     location = ".".join(map(str, child.GetCurrentLocation()))
   147     device      = child.GetParamsAttributes()[0]["children"][0]["value"]
   145     device, baud, parity, stopbits, coms_period = GetCTVals(child, range(5))
   148     baud        = child.GetParamsAttributes()[0]["children"][1]["value"]
   146 
   149     parity      = child.GetParamsAttributes()[0]["children"][2]["value"]
   147     node_dict = {"locnodestr": location,
   150     stopbits    = child.GetParamsAttributes()[0]["children"][3]["value"]
   148                  "device": device,
   151     coms_period = child.GetParamsAttributes()[0]["children"][4]["value"]
   149                  "baud": baud,
   152     
   150                  "parity": modbus_serial_parity_dict[parity],
   153     node_dict = {"locnodestr"  : location,
   151                  "stopbits": stopbits,
   154                  "device"      : device,
   152                  "coms_period": coms_period
   155                  "baud"        : baud,
   153                  }
   156                  "parity"      : modbus_serial_parity_dict[parity],
   154     return node_init_template % node_dict
   157                  "stopbits"    : stopbits,
       
   158                  "coms_period" : coms_period
       
   159                 }
       
   160     return node_init_template % node_dict
       
   161 
       
   162 
       
   163 
   155 
   164 
   156 
   165 def GetTCPClientNodePrinted(self, child):
   157 def GetTCPClientNodePrinted(self, child):
   166     """
   158     """
   167     Outputs a string to be used on C files
   159     Outputs a string to be used on C files
   169     """
   161     """
   170     node_init_template = '''/*node %(locnodestr)s*/
   162     node_init_template = '''/*node %(locnodestr)s*/
   171 {"%(locnodestr)s", {naf_tcp, {.tcp = {"%(host)s", "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */, 0 /* prev_error */}'''
   163 {"%(locnodestr)s", {naf_tcp, {.tcp = {"%(host)s", "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */, 0 /* prev_error */}'''
   172 
   164 
   173     location = ".".join(map(str, child.GetCurrentLocation()))
   165     location = ".".join(map(str, child.GetCurrentLocation()))
   174     host        = child.GetParamsAttributes()[0]["children"][0]["value"]
   166     host, port, coms_period = GetCTVals(child, range(3))
   175     port        = child.GetParamsAttributes()[0]["children"][1]["value"]
   167 
   176     coms_period = child.GetParamsAttributes()[0]["children"][2]["value"]
   168     node_dict = {"locnodestr": location,
   177 
   169                  "host": host,
   178     node_dict = {"locnodestr"  : location,
   170                  "port": port,
   179                  "host"        : host,
   171                  "coms_period": coms_period
   180                  "port"        : port,
   172                  }
   181                  "coms_period" : coms_period
   173     return node_init_template % node_dict
   182                 }
       
   183     return node_init_template % node_dict
       
   184 
       
   185 
       
   186 
   174 
   187 
   175 
   188 def GetClientRequestPrinted(self, child, nodeid):
   176 def GetClientRequestPrinted(self, child, nodeid):
   189     """
   177     """
   190     Outputs a string to be used on C files
   178     Outputs a string to be used on C files
   197 
   185 
   198     req_init_template = '''/*request %(locreqstr)s*/
   186     req_init_template = '''/*request %(locreqstr)s*/
   199 {"%(locreqstr)s", %(nodeid)s, %(slaveid)s, %(iotype)s, %(func_nr)s, %(address)s , %(count)s,
   187 {"%(locreqstr)s", %(nodeid)s, %(slaveid)s, %(iotype)s, %(func_nr)s, %(address)s , %(count)s,
   200 DEF_REQ_SEND_RETRIES, 0 /* error_code */, 0 /* prev_code */, {%(timeout_s)d, %(timeout_ns)d} /* timeout */,
   188 DEF_REQ_SEND_RETRIES, 0 /* error_code */, 0 /* prev_code */, {%(timeout_s)d, %(timeout_ns)d} /* timeout */,
   201 {%(buffer)s}, {%(buffer)s}}'''
   189 {%(buffer)s}, {%(buffer)s}}'''
   202     
   190 
   203     timeout      = int(child.GetParamsAttributes()[0]["children"][4]["value"])
   191     timeout = int(GetCTVal(child, 4))
   204     timeout_s    = int(timeout / 1000)
   192     timeout_s = int(timeout / 1000)
   205     timeout_ms   = timeout - (timeout_s * 1000)
   193     timeout_ms = timeout - (timeout_s * 1000)
   206     timeout_ns   = timeout_ms * 1000000
   194     timeout_ns = timeout_ms * 1000000
   207     
   195 
   208     request_dict = {}
   196     request_dict = {
   209 
   197         "locreqstr": "_".join(map(str, child.GetCurrentLocation())),
   210     request_dict["locreqstr" ] = "_".join(map(str, child.GetCurrentLocation()))
   198         "nodeid": str(nodeid),
   211     request_dict["nodeid"    ] = str(nodeid)
   199         "slaveid": GetCTVal(child, 1),
   212     request_dict["slaveid"   ] =                      child.GetParamsAttributes()[0]["children"][1]["value"]
   200         "address": GetCTVal(child, 3),
   213     request_dict["address"   ] =                      child.GetParamsAttributes()[0]["children"][3]["value"]
   201         "count": GetCTVal(child, 2),
   214     request_dict["count"     ] =                      child.GetParamsAttributes()[0]["children"][2]["value"]
   202         "timeout": timeout,
   215     request_dict["timeout"   ] = timeout
   203         "timeout_s": timeout_s,
   216     request_dict["timeout_s" ] = timeout_s
   204         "timeout_ns": timeout_ns,
   217     request_dict["timeout_ns"] = timeout_ns
   205         "buffer": ",".join(['0'] * int(GetCTVal(child, 2))),
   218     request_dict["buffer"    ] = ",".join(['0'] * int(child.GetParamsAttributes()[0]["children"][2]["value"]))
   206         "func_nr": modbus_function_dict[GetCTVal(child, 0)][0],
   219     request_dict["func_nr"   ] = modbus_function_dict[child.GetParamsAttributes()[0]["children"][0]["value"]][0]
   207         "iotype": modbus_function_dict[GetCTVal(child, 0)][1],
   220     request_dict["iotype"    ] = modbus_function_dict[child.GetParamsAttributes()[0]["children"][0]["value"]][1]
   208         "maxcount": modbus_function_dict[GetCTVal(child, 0)][2]}
   221     request_dict["maxcount"  ] = modbus_function_dict[child.GetParamsAttributes()[0]["children"][0]["value"]][2]
   209 
   222     
       
   223     if int(request_dict["slaveid"]) not in xrange(256):
   210     if int(request_dict["slaveid"]) not in xrange(256):
   224         self.GetCTRoot().logger.write_error("Modbus plugin: Invalid slaveID in TCP client request node %(locreqstr)s (Must be in the range [0..255])\nModbus plugin: Aborting C code generation for this node\n"%request_dict)
   211         self.GetCTRoot().logger.write_error(
       
   212             "Modbus plugin: Invalid slaveID in TCP client request node %(locreqstr)s (Must be in the range [0..255])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
   225         return None
   213         return None
   226     if int(request_dict["address"]) not in xrange(65536):
   214     if int(request_dict["address"]) not in xrange(65536):
   227         self.GetCTRoot().logger.write_error("Modbus plugin: Invalid Start Address in TCP client request node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n"%request_dict)
   215         self.GetCTRoot().logger.write_error(
   228         return None
   216             "Modbus plugin: Invalid Start Address in TCP client request node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
   229     if int(request_dict["count"]) not in xrange(1, 1+int(request_dict["maxcount"])):
   217         return None
   230         self.GetCTRoot().logger.write_error("Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (Must be in the range [1..%(maxcount)s])\nModbus plugin: Aborting C code generation for this node\n"%request_dict)
   218     if int(request_dict["count"]) not in xrange(1, 1 + int(request_dict["maxcount"])):
   231         return None
   219         self.GetCTRoot().logger.write_error(
   232     if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1,65537):
   220             "Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (Must be in the range [1..%(maxcount)s])\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
   233         self.GetCTRoot().logger.write_error("Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (start_address + nr_channels must be less than 65536)\nModbus plugin: Aborting C code generation for this node\n"%request_dict)
   221         return None
   234         return None
   222     if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1, 65537):
   235     
   223         self.GetCTRoot().logger.write_error(
       
   224             "Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (start_address + nr_channels must be less than 65536)\nModbus plugin: Aborting C code generation for this node\n" % request_dict)
       
   225         return None
       
   226 
   236     return req_init_template % request_dict
   227     return req_init_template % request_dict