Example #1
0
 def _do_close(self):
     """Close the connection with the Modbus Slave"""
     if self._sock:
         call_hooks("modbus_tcp.TcpMaster.before_close", (self, ))
         self._sock.close()
         call_hooks("modbus_tcp.TcpMaster.after_close", (self, ))
         self._sock = None
Example #2
0
    def handle_request(self, query, request):
        """
        when a request is received, handle it and returns the response pdu
        """
        request_pdu = ""
        try:
            #extract the pdu and the slave id
            (slave_id, request_pdu) = query.parse_request(request)

            #get the slave and let him executes the action
            if slave_id == 0:
                #broadcast
                for key in self._slaves:
                    self._slaves[key].handle_request(request_pdu,
                                                     broadcast=True)
                return
            else:
                slave = self.get_slave(slave_id)
                response_pdu = slave.handle_request(request_pdu)
                #make the full response
                response = query.build_response(response_pdu)
                return response
        except Exception, excpt:
            call_hooks("modbus.Databank.on_error", (self, excpt, request_pdu))
            LOGGER.error("handle request failed: " + str(excpt))
Example #3
0
    def _write_multiple_registers(self, request_pdu):
        """execute modbus function 16"""
        call_hooks("modbus.Slave.handle_write_multiple_registers_request",
                   (self, request_pdu))
        # get the starting address and the number of items from the request pdu
        (starting_address, quantity_of_x,
         byte_count) = struct.unpack(">HHB", request_pdu[1:6])

        if (quantity_of_x <= 0) or (quantity_of_x >
                                    123) or (byte_count !=
                                             (quantity_of_x * 2)):
            # maximum allowed size is 123 registers in one reading
            raise ModbusError(defines.ILLEGAL_DATA_VALUE)

        # look for the block corresponding to the request
        block, offset = self._get_block_and_offset(defines.HOLDING_REGISTERS,
                                                   starting_address,
                                                   quantity_of_x)

        count = 0
        for i in xrange(quantity_of_x):
            count += 1
            fmt = "H" if self.unsigned else "h"
            block[offset + i] = struct.unpack(
                ">" + fmt, request_pdu[6 + 2 * i:8 + 2 * i])[0]

        return struct.pack(">HH", starting_address, count)
Example #4
0
    def _write_multiple_coils(self, request_pdu):
        """execute modbus function 15"""
        call_hooks("modbus.Slave.handle_write_multiple_coils_request", (self, request_pdu))
        # get the starting address and the number of items from the request pdu
        (starting_address, quantity_of_x, byte_count) = struct.unpack(">HHB", request_pdu[1:6])

        expected_byte_count = quantity_of_x / 8
        if (quantity_of_x % 8) > 0:
            expected_byte_count += 1

        if (quantity_of_x <= 0) or (quantity_of_x > 1968) or (byte_count != expected_byte_count):
            # maximum allowed size is 1968 coils
            raise ModbusError(defines.ILLEGAL_DATA_VALUE)

        # look for the block corresponding to the request
        block, offset = self._get_block_and_offset(defines.COILS, starting_address, quantity_of_x)

        count = 0
        for i in xrange(byte_count):
            if count >= quantity_of_x:
                break
            (byte_value, ) = struct.unpack(">B", request_pdu[6+i])
            for j in xrange(8):
                if byte_value & (1 << j):
                    block[offset+i*8+j] = 1
                else:
                    block[offset+i*8+j] = 0
                if count >= quantity_of_x:
                    break
                count += 1
        return struct.pack(">HH", starting_address, count)
Example #5
0
    def _write_multiple_coils(self, request_pdu):
        """execute modbus function 15"""
        call_hooks("modbus.Slave.handle_write_multiple_coils_request", (self, request_pdu))
        # get the starting address and the number of items from the request pdu
        (starting_address, quantity_of_x, byte_count) = struct.unpack(">HHB", request_pdu[1:6])

        expected_byte_count = quantity_of_x / 8
        if (quantity_of_x % 8) > 0:
            expected_byte_count += 1

        if (quantity_of_x <= 0) or (quantity_of_x > 1968) or (byte_count != expected_byte_count):
            # maximum allowed size is 1968 coils
            raise ModbusError(defines.ILLEGAL_DATA_VALUE)

        # look for the block corresponding to the request
        block, offset = self._get_block_and_offset(defines.COILS, starting_address, quantity_of_x)

        count = 0
        for i in xrange(byte_count):
            if count >= quantity_of_x:
                break
            fmt = "B" if self.unsigned else "b"
            (byte_value, ) = struct.unpack(">"+fmt, request_pdu[6+i])
            for j in xrange(8):
                if byte_value & (1 << j):
                    block[offset+i*8+j] = 1
                else:
                    block[offset+i*8+j] = 0
                if count >= quantity_of_x:
                    break
                count += 1
        return struct.pack(">HH", starting_address, count)
Example #6
0
 def _do_close(self):
     """Close the connection with the Modbus Slave"""
     if self._sock:
         call_hooks("modbus_tcp.TcpMaster.before_close", (self, ))
         self._sock.close()
         call_hooks("modbus_tcp.TcpMaster.after_close", (self, ))
         self._sock = None
Example #7
0
    def _do_run(self):
        """main function of the server"""
        try:
            #check the status of every socket
            response = ""
            request = ""
            read_bytes = "dummy"
            while read_bytes:
                read_bytes = self._serial.read(128)
                request += read_bytes

            #parse the request
            if request:
                retval = call_hooks("modbus_rtu.RtuServer.after_read", (self, request))
                if retval <> None:
                    request = retval
                response = self._handle(request)

                #send back the response
                retval = call_hooks("modbus_rtu.RtuServer.before_write", (self, response))
                if retval <> None:
                    response = retval

                if response:
                    self._serial.write(response)
                    time.sleep(3.5 * self._t0)

        except Exception, excpt:
            LOGGER.error("Error while handling request, Exception occurred: %s", excpt)
            call_hooks("modbus_rtu.RtuServer.on_error", (self, excpt))
Example #8
0
 def __setitem__(self, r, v):
     """"""
     call_hooks("modbus.ModbusBlock.setitem", (self, r, v))
     ##We get a copy of the existing values that are about to change,
     ##  implement the changes according to type, then put the new objects
     ##  into the _data object
     item = self._data.__getitem__(r)
     try:
         for cnt in range(len(item)):
             if str(type(item[cnt])) == "<class 'point.Point'>":
                 item[cnt] = item[cnt].set(v[cnt])        
             else:
                 item[cnt] = v[cnt]
         return self._data.__setitem__(r, item)
     except TypeError: #This happens if item isn't iterable:
         if str(type(item)) == "<class 'point.Point'>":
             item = item.set(v)
         else:
             #print "BRDEBUG: In __setitem__. About to do the default", type(item)
             return self._data.__setitem__(r, v)
     finally:
         if hasattr(v,'__iter__') and (self.__getitem__(r) == list(v)):
             pass
         elif ((str(type(v)) == "<class 'point.Point'>") and 
              self.__getitem__(r) == v.get() ):
             pass
         elif self.__getitem__(r) != v:
             raise Exception("Stored value %s not equal to %s" % 
                                 (self.__getitem__(r), v) )
Example #9
0
 def _write_single_register(self, request_pdu):
     """execute modbus function 6"""
     call_hooks("modbus.Slave.handle_write_single_register_request", (self, request_pdu))
     (data_address, value) = struct.unpack(">HH", request_pdu[1:5])
     block, offset = self._get_block_and_offset(defines.HOLDING_REGISTERS, data_address, 1)
     block[offset] = value
     return request_pdu[1:] #returns echo of the command
Example #10
0
    def __getitem__(self, r):
        """"""
        call_hooks(
            "modbus.ModbusBlock.getitem",
            (self, r, self.block_name))  # Added by zhen.zhang on 2012-08-15
        # 注:参数r可能是slice类型或int类型

        return self._data.__getitem__(r)
Example #11
0
    def _write_single_register(self, request_pdu):
        """execute modbus function 6"""
        call_hooks("modbus.Slave.handle_write_single_register_request", (self, request_pdu))

        fmt = "H" if self.unsigned else "h"
        (data_address, value) = struct.unpack(">H"+fmt, request_pdu[1:5])
        block, offset = self._get_block_and_offset(defines.HOLDING_REGISTERS, data_address, 1)
        block[offset] = value
        return request_pdu[1:] #returns echo of the command
Example #12
0
 def _do_open(self):
     """Connect to the Modbus slave"""
     if self._sock:
         self._sock.close()
     self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     self.set_timeout(self.get_timeout())
     call_hooks("modbus_tcp.TcpMaster.before_connect", (self, ))
     self._sock.connect((self._host, self._port))
     call_hooks("modbus_tcp.TcpMaster.after_connect", (self, ))    
Example #13
0
    def __setitem__(self, r, v):
        """"""
        #call_hooks("modbus.ModbusBlock.setitem", (self, r, v))                 # Commented by zhen.zhang on 2012-08-14
        call_hooks(
            "modbus.ModbusBlock.setitem",
            (self, r, v, self.block_name))  # Added by zhen.zhang on 2012-08-14
        # 注:参数r可能是slice类型(此时v是list类型)或int类型(此时v是int类型)

        return self._data.__setitem__(r, v)
Example #14
0
 def _do_open(self):
     """Connect to the Modbus slave"""
     if self._sock:
         self._sock.close()
     self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     self.set_timeout(self.get_timeout())
     call_hooks("modbus_tcp.TcpMaster.before_connect", (self, ))
     self._sock.connect((self._host, self._port))
     call_hooks("modbus_tcp.TcpMaster.after_connect", (self, ))    
Example #15
0
 def _write_single_coil(self, request_pdu):
     """execute modbus function 5"""
     call_hooks("modbus.Slave.handle_write_single_coil_request", (self, request_pdu))
     (data_address, value) = struct.unpack(">HH", request_pdu[1:5])
     block, offset = self._get_block_and_offset(defines.COILS, data_address, 1)
     if value == 0:
         block[offset] = 0
     elif value == 0xff00:
         block[offset] = 1
     else:
         raise ModbusError(defines.ILLEGAL_DATA_VALUE)
     return request_pdu[1:] #returns echo of the command
Example #16
0
    def _write_single_coil(self, request_pdu):
        """execute modbus function 5"""
        fmt = "H" if self.unsigned else "h"

        call_hooks("modbus.Slave.handle_write_single_coil_request", (self, request_pdu))
        (data_address, value) = struct.unpack(">H"+fmt, request_pdu[1:5])
        block, offset = self._get_block_and_offset(defines.COILS, data_address, 1)
        if value == 0:
            block[offset] = 0
        elif value == 0xff00:
            block[offset] = 1
        else:
            raise ModbusError(defines.ILLEGAL_DATA_VALUE)
        return request_pdu[1:] #returns echo of the command
Example #17
0
    def handle_request(self, request_pdu, broadcast=False):
        """
        parse the request pdu, makes the corresponding action
        and returns the response pdu
        """
        with self._data_lock:  #thread-safe
            try:
                retval = call_hooks("modbus.Slave.handle_request",
                                    (self, request_pdu))
                if retval <> None:
                    return retval

                # get the function code
                (function_code, ) = struct.unpack(">B", request_pdu[0])

                # check if the function code is valid. If not returns error response
                if not self._fn_code_map.has_key(function_code):
                    raise ModbusError(defines.ILLEGAL_FUNCTION)

                # if read query is broadcasted raises an error
                cant_be_broadcasted = (defines.READ_COILS,
                                       defines.READ_DISCRETE_INPUTS,
                                       defines.READ_INPUT_REGISTERS,
                                       defines.READ_HOLDING_REGISTERS)
                if broadcast and (function_code in cant_be_broadcasted):
                    raise ModbusInvalidRequestError(
                        "Function %d can not be broadcasted" % function_code)

                #execute the corresponding function
                response_pdu = self._fn_code_map[function_code](request_pdu)
                if response_pdu:
                    if broadcast:
                        call_hooks("modbus.Slave.on_handle_broadcast",
                                   (self, response_pdu))
                        LOGGER.debug(
                            "broadcast: %s" %
                            (utils.get_log_buffer("!!", response_pdu)))
                        return ""
                    else:
                        return struct.pack(">B", function_code) + response_pdu
                raise Exception("No response for function %d" % function_code)

            except ModbusError, excpt:
                LOGGER.debug(str(excpt))
                call_hooks("modbus.Slave.on_exception",
                           (self, function_code, excpt))
                return struct.pack(">BB", function_code + 128,
                                   excpt.get_exception_code())
Example #18
0
    def _recv(self, expected_length=-1):
        """Receive the response from the slave"""
        response = ""
        read_bytes = "dummy"

        while read_bytes:
            read_bytes = self._serial.read(1)
            #print repr(read_bytes),1111
            response += read_bytes

            if expected_length >= 0 and len(
                    response) >= 2 * expected_length + 1:
                #if the expected number of byte is received consider that the response is done
                #improve performance by avoiding end-of-response detection by timeout
                break
        #response='3A 30 31 30 33 30 34 34 30 38 30 30 30 30 30 33 38 0D 0A'

    # response=':0103084080000038'

        retval = call_hooks("modbus_rtu.RtuMaster.after_recv",
                            (self, response))
        if retval <> None:
            return retval
        print response[1:-2], 1111

        return binascii.a2b_hex(response[1:-2])
Example #19
0
 def _recv(self, expected_length=-1):
     """
     Receive the response from the slave
     Do not take expected_length into account because the length of the response is
     written in the mbap. Used for RTU only
     """
     
     response = ""
     length = 255
     while len(response)<length:
         rcv_byte = self._sock.recv(1)
        
         if rcv_byte:
             response += rcv_byte
            
             if len(response) == 6:
                 (tr_id, pr_id, to_be_recv_length) = struct.unpack(">HHH", response)
               
                 length = to_be_recv_length + 6
         else:
             break
            
     retval = call_hooks("modbus_tcp.TcpMaster.after_recv", (self, response))
     if retval <> None:
         return response
    
     return response
Example #20
0
    def _write_multiple_registers(self, request_pdu):
        """execute modbus function 16"""
        call_hooks("modbus.Slave.handle_write_multiple_registers_request", (self, request_pdu))
        # get the starting address and the number of items from the request pdu
        (starting_address, quantity_of_x, byte_count) = struct.unpack(">HHB", request_pdu[1:6])

        if (quantity_of_x <= 0) or (quantity_of_x > 123) or (byte_count != (quantity_of_x * 2)):
            # maximum allowed size is 123 registers in one reading
            raise ModbusError(defines.ILLEGAL_DATA_VALUE)

        # look for the block corresponding to the request
        block, offset = self._get_block_and_offset(defines.HOLDING_REGISTERS, starting_address, quantity_of_x)

        count = 0
        for i in xrange(quantity_of_x):
            count += 1
            block[offset+i] = struct.unpack(">H", request_pdu[6+2*i:8+2*i])[0]

        return struct.pack(">HH", starting_address, count)
Example #21
0
    def handle_request(self, request_pdu, broadcast=False):
        """
        parse the request pdu, makes the corresponding action
        and returns the response pdu
        """
        with self._data_lock:  # thread-safe
            try:
                retval = call_hooks("modbus.Slave.handle_request", (self, request_pdu))
                if retval <> None:
                    return retval

                # get the function code
                (function_code,) = struct.unpack(">B", request_pdu[0])

                # check if the function code is valid. If not returns error response
                if not self._fn_code_map.has_key(function_code):
                    raise ModbusError(defines.ILLEGAL_FUNCTION)

                # if read query is broadcasted raises an error
                cant_be_broadcasted = (
                    defines.READ_COILS,
                    defines.READ_DISCRETE_INPUTS,
                    defines.READ_INPUT_REGISTERS,
                    defines.READ_HOLDING_REGISTERS,
                )
                if broadcast and (function_code in cant_be_broadcasted):
                    raise ModbusInvalidRequestError("Function %d can not be broadcasted" % function_code)

                # execute the corresponding function
                response_pdu = self._fn_code_map[function_code](request_pdu)
                if response_pdu:
                    if broadcast:
                        call_hooks("modbus.Slave.on_handle_broadcast", (self, response_pdu))
                        LOGGER.debug("broadcast: %s" % (utils.get_log_buffer("!!", response_pdu)))
                        return ""
                    else:
                        return struct.pack(">B", function_code) + response_pdu
                raise Exception("No response for function %d" % function_code)

            except ModbusError, excpt:
                LOGGER.debug(str(excpt))
                call_hooks("modbus.Slave.on_exception", (self, function_code, excpt))
                return struct.pack(">BB", function_code + 128, excpt.get_exception_code())
Example #22
0
    def _send(self, request):
        """Send request to the slave"""
        retval = call_hooks("modbus_rtu.RtuMaster.before_send", (self, request))
        if retval <> None:
            request = retval

        self._serial.flushInput()
        self._serial.flushOutput()

        self._serial.write(request)
        time.sleep(3.5 * self._t0)
Example #23
0
    def _send(self, request):
        """Send request to the slave"""
        retval = call_hooks("modbus_rtu.RtuMaster.before_send", (self, request))
        if retval <> None:
            request = retval

        self._serial.flushInput()
        self._serial.flushOutput()

        self._serial.write(request)
        time.sleep(3.5 * self._t0)
Example #24
0
 def _send(self, request):
     """Send request to the slave"""
     retval = call_hooks("modbus_tcp.TcpMaster.before_send", (self, request))
     if retval <> None:
         request = retval
     try:
         utils.flush_socket(self._sock, 3)
     except Exception, msg:
         #if we can't flush the socket successfully: a disconnection may happened
         #try to reconnect
         LOGGER.error('Error while flushing the socket: {0}'.format(msg))
         raise ModbusNotConnectedError(msg)
Example #25
0
    def _handle(self, request):
        """handle a received sentence"""

        if self._verbose:
            LOGGER.debug(utils.get_log_buffer("-->", request))

        #gets a query for analyzing the request
        query = self._make_query()

        retval = call_hooks("modbus.Server.before_handle_request", (self, request))
        if retval:
            request = retval

        response = self._databank.handle_request(query, request)
        retval = call_hooks("modbus.Server.after_handle_request", (self, response))
        if retval:
            response = retval

        if response and self._verbose:
            LOGGER.debug(utils.get_log_buffer("<--", response))
        return response
Example #26
0
 def _handle(self, request):
     """handle a received sentence"""
     
     if self._verbose:
         LOGGER.debug(utils.get_log_buffer("-->", request))
     
     #gets a query for analyzing the request
     query = self._make_query()
     
     retval = call_hooks("modbus.Server.before_handle_request", (self, request))
     if retval:
         request = retval
         
     response = self._databank.handle_request(query, request)
     retval = call_hooks("modbus.Server.after_handle_request", (self, response))
     if retval:
         response = retval
             
     if response and self._verbose:
         LOGGER.debug(utils.get_log_buffer("<--", response))
     return response
Example #27
0
 def _send(self, request):
     """Send request to the slave"""
     retval = call_hooks("modbus_rtu_over_tcp.RtuOverTcpMaster.before_send", (self, request))
     if retval <> None:
         request = retval
     try:
         utils.flush_socket(self._sock, 3)
     except Exception, msg:
         #if we can't flush the socket successfully: a disconnection may happened
         #try to reconnect
         LOGGER.error('Error while flushing the socket: {0}'.format(msg))
         #raise ModbusNotConnectedError(msg)
         self._do_open();
Example #28
0
    def _do_run(self):
        """main function of the server"""
        try:
            #check the status of every socket
            response = ""
            request = ""
            read_bytes = "dummy"
            while read_bytes:
                read_bytes = self._serial.read(128)
                request += read_bytes
            #rxtime = time.time()#BRDEBUG
            #parse the request
            if request:
                retval = call_hooks("modbus_rtu.RtuServer.after_read", (self, request))
                if retval <> None:
                    request = retval
                response = self._handle(request)

                #send back the response
                retval = call_hooks("modbus_rtu.RtuServer.before_write", (self, response))
                if retval <> None:
                    response = retval

                if response:
                    self._serial.write(response)
                    #txtime = time.time() #BRDEBUG
                    time.sleep(3.5 * self._t0)
                    #BRDEBUG
                    #self.avg = getattr(self, 'avg', 0)
                    #self.n = getattr(self, 'n', 0)
                    #self.avg = ((self.avg*self.n + (txtime - rxtime))/(self.n+1)) 
                    #self.n = self.n+1
                    #print "BRDEBUG Received request: %.6f"% rxtime
                    #print "BRDEBUG response sent: %.6f"% txtime
                    #print "BRDEBUG Rolling average: %.6f"% self.avg
        except Exception, excpt:
            LOGGER.error("Error while handling request, Exception occurred: %s", excpt)
            call_hooks("modbus_rtu.RtuServer.on_error", (self, excpt))
Example #29
0
 def handle_request(self, query, request):
     """
     when a request is received, handle it and returns the response pdu
     """
     request_pdu = ""
     try:
         #extract the pdu and the slave id
         (slave_id, request_pdu) = query.parse_request(request)
         
         #get the slave and let him executes the action
         if slave_id == 0:
             #broadcast
             for key in self._slaves:
                 self._slaves[key].handle_request(request_pdu, broadcast=True)
             return
         else:
             slave = self.get_slave(slave_id)
             response_pdu = slave.handle_request(request_pdu)
             #make the full response
             response = query.build_response(response_pdu)
             return response
     except Exception, excpt:
         call_hooks("modbus.Databank.on_error", (self, excpt, request_pdu))
         LOGGER.error("handle request failed: " + str(excpt))
Example #30
0
    def _recv(self, expected_length=-1):
        """Receive the response from the slave"""
        response = ""
        read_bytes = "dummy"
        while read_bytes:
            read_bytes = self._serial.read(1)
            response += read_bytes
            if expected_length>=0 and len(response)>=expected_length:
                #if the expected number of byte is received consider that the response is done
                #improve performance by avoiding end-of-response detection by timeout
                break

        retval = call_hooks("modbus_rtu.RtuMaster.after_recv", (self, response))
        if retval <> None:
            return retval
        return response
Example #31
0
    def _send(self, request):
        """Send request to the slave"""
        retval = call_hooks("modbus_rtu.RtuMaster.before_send", (self, request))
        if retval <> None:
            request = retval

        self._serial.flushInput()
        self._serial.flushOutput()

	self._serial.setRTS(True)	# MJC RS485 hack
        self._serial.write(request)
        time.sleep(1 * self._t0)      
	#time.sleep(len(request) * self._t0)
	self._serial.setRTS(False)	# MJC RS485 hack
        time.sleep(3.5 * self._t0)
	self._serial.flushInput()
Example #32
0
    def _recv(self, expected_length=-1, expected_address=None):
        """Receive the response from the slave.
        expected_address is used if there is noise or other nastiness on the 
        serial line. It is used to look for the start of a response."""
        response = ""
        # first_byte is made true when we find the exp. addr. in the data stream
        #If exp_addr isn't specified, we just take the first byte we get.
        first_byte = False if expected_address else True 
        read_bytes = "dummy"
        start_time = time.time()
        while read_bytes:
            try: #BRFIX
                read_bytes = self._serial.read(1)
                if first_byte:
                    pass #We're mid packet -- just keep processing the response
                elif read_bytes != expected_address:
                    #ignore this byte and keep looking for expected_address
                    if (time.time()-start_time) > self._serial.timeout:
                        #This call should time out
                        return ''
                    continue 
                elif read_bytes == expected_address:
                    first_byte = True
                    pass #keep going with response processing

            except OSError as error:
                if error.errno == 11: #This is error EAGAIN-> "Try again later"
                    print ("BRDEBUG: Errno 11 caught. Trying again." +
                    "Response: '%s'" % response)
                    return response + self._recv(expected_length, expected_address) #Try again
                else:
                    raise error
            response += read_bytes
            if expected_length>=0 and len(response)>=expected_length:
                #if the expected number of byte is received consider that the i
                #response is done
                #improve performance by avoiding end-of-response detection by timeout
                break

        retval = call_hooks("modbus_rtu.RtuMaster.after_recv", (self, response))
        if retval <> None:
            return retval
        return response
Example #33
0
    def _recv(self, expected_length=-1):
        """
        Receive the response from the slave
        Do not take expected_length into account because the length of the response is
        written in the mbap. Used for RTU only
        """
        
        response = ""

##################### Modified by yaoming.lin on 2013-07-09 ####################

        is_ok = True

        #read the 5 bytes of the pdu message
        while (len(response) < 5) and is_ok: 
            new_byte = self._sock.recv(1)
            if len(new_byte) == 0:
                is_ok = False
            else:
                response += new_byte
        if is_ok:
            #read the rest of the request
            #length = self._get_request_length(request)
            if ord(response[1]) < 7:  # Modified by yaoming.lin on 2015-08-17
                length = ord(response[2]) + 5
            elif ord(response[1]) < 17:
                 length = 8
            else:
                 length = 5
                        
        while (len(response) < length) and is_ok:
            new_byte = self._sock.recv(1)
            if len(new_byte) == 0:
                is_ok = False
            else:
                 response += new_byte

################################################################################

        retval = call_hooks("modbus_rtu_over_tcp.RtuOverTcpMaster.after_recv", (self, response))
        if retval <> None:
            return response
        return response
Example #34
0
 def _recv(self, expected_length=-1):
     """
     Receive the response from the slave
     Do not take expected_length into account because the length of the response is
     written in the mbap. Used for RTU only
     """
     
     response = ""
     length = 255
     while len(response)<length:
         rcv_byte = self._sock.recv(1)
         if rcv_byte:
             response += rcv_byte
             if len(response) == 6:
                 (tr_id, pr_id, to_be_recv_length) = struct.unpack(">HHH", response)
                 length = to_be_recv_length + 6
         else:
             break
     retval = call_hooks("modbus_tcp.TcpMaster.after_recv", (self, response))
     if retval <> None:
         return response
     return response
Example #35
0
    def _recv(self, expected_length=-1):
        """Receive the response from the slave"""
        response = ""
        read_bytes = self._serial.read(1)
        while read_bytes:
            #read_bytes = self._serial.read(1)
            if len(response) == 0:
                # MJC RS485 hack, 1st rx byte may be crud throw it away
                if struct.unpack(">B", read_bytes[0])[0] < 248:
                    response += read_bytes
            else:
                response += read_bytes
                if expected_length>=0 and len(response)>=expected_length:
                    #if the expected number of byte is received consider that the response is done
                    #improve performance by avoiding end-of-response detection by timeout
                    break
            read_bytes = self._serial.read(1)

        retval = call_hooks("modbus_rtu.RtuMaster.after_recv", (self, response))
        if retval <> None:
            return retval
        return response
Example #36
0
 def _recv(self, expected_length=-1, expected_address=None):
     """
     Receive the response from the slave
     Do not take expected_length into account because the length of the 
     response is written in the mbap. Used for RTU only.
     Expected address is used for parsing dirty streams in RTU mode.
     This parameter is not necessary for TCP mode. 
     """
     
     response = ""
     length = 255
     while len(response)<length:
         rcv_byte = self._sock.recv(1)
         if rcv_byte:
             response += rcv_byte
             if len(response) == 6:
                 (tr_id, pr_id, to_be_recv_length) = struct.unpack(">HHH", response)
                 length = to_be_recv_length + 6
         else:
             break
     retval = call_hooks("modbus_tcp.TcpMaster.after_recv", (self, response))
     if retval <> None:
         return response
     return response
Example #37
0
 def _do_init(self):
     """initialize the serial connection"""
     if not self._serial.isOpen():
         call_hooks("modbus_rtu.RtuServer.before_open", (self, ))
         self._serial.open()
         call_hooks("modbus_rtu.RtuServer.after_open", (self, ))
Example #38
0
 def close(self):
     """close the serial communication"""
     if self._serial.isOpen():
         call_hooks("modbus_rtu.RtuServer.before_close", (self, ))
         self._serial.close()
         call_hooks("modbus_rtu.RtuServer.after_close", (self, ))
Example #39
0
    def execute(self,
                slave,
                function_code,
                starting_address,
                quantity_of_x=0,
                output_value=0,
                data_format="",
                expected_length=-1):
        """
        Execute a modbus query and returns the data part of the answer as a tuple
        The returned tuple depends on the query function code. see modbus protocol
        specification for details
        data_format makes possible to extract the data like defined in the
        struct python module documentation
        """

        pdu = ""
        is_read_function = False
        nb_of_digits = 0

        #open the connection if it is not already done
        self.open()

        #Build the modbus pdu and the format of the expected data.
        #It depends of function code. see modbus specifications for details.
        if function_code == defines.READ_COILS or function_code == defines.READ_DISCRETE_INPUTS:
            is_read_function = True
            pdu = struct.pack(">BHH", function_code, starting_address,
                              quantity_of_x)
            byte_count = quantity_of_x / 8
            if (quantity_of_x % 8) > 0:
                byte_count += 1
            nb_of_digits = quantity_of_x
            if not data_format:
                data_format = ">" + (byte_count * "B")
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = byte_count + 5  #slave + func + bytcodeLen + bytecode + crc1 + crc2

        elif function_code == defines.READ_INPUT_REGISTERS or function_code == defines.READ_HOLDING_REGISTERS:
            is_read_function = True
            pdu = struct.pack(">BHH", function_code, starting_address,
                              quantity_of_x)
            if not data_format:
                data_format = ">" + (quantity_of_x * "H")
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 2 * quantity_of_x + 5  #slave + func + bytcodeLen + bytecode x 2 + crc1 + crc2

        elif (function_code == defines.WRITE_SINGLE_COIL) or (
                function_code == defines.WRITE_SINGLE_REGISTER):
            if function_code == defines.WRITE_SINGLE_COIL:
                if output_value != 0:
                    output_value = 0xff00
            pdu = struct.pack(">BHH", function_code, starting_address,
                              output_value)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + value1+value2 + crc1 + crc2

        elif function_code == defines.WRITE_MULTIPLE_COILS:
            byte_count = len(output_value) / 8
            if (len(output_value) % 8) > 0:
                byte_count += 1
            pdu = struct.pack(">BHHB", function_code, starting_address,
                              len(output_value), byte_count)
            i, byte_value = 0, 0
            for j in output_value:
                if j > 0:
                    byte_value += pow(2, i)
                if i == 7:
                    pdu += struct.pack(">B", byte_value)
                    i, byte_value = 0, 0
                else:
                    i += 1
            if i > 0:
                pdu += struct.pack(">B", byte_value)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + outputQuant1 + outputQuant2 + crc1 + crc2

        elif function_code == defines.WRITE_MULTIPLE_REGISTERS:
            byte_count = 2 * len(output_value)
            pdu = struct.pack(">BHHB", function_code, starting_address,
                              len(output_value), byte_count)
            for j in output_value:
                pdu += struct.pack(">H", j)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + outputQuant1 + outputQuant2 + crc1 + crc2

        else:
            raise ModbusFunctionNotSupportedError(
                "The %d function code is not supported. " % (function_code))

        # instantiate a query which implements the MAC (TCP or RTU) part of the protocol
        query = self._make_query()

        # add the mac part of the protocol to the request
        request = query.build_request(pdu, slave)

        # send the request to the slave
        retval = call_hooks("modbus.Master.before_send", (self, request))
        if retval <> None:
            request = retval
        if self._verbose:
            LOGGER.debug(utils.get_log_buffer("-> ", request))
        self._send(request)

        call_hooks("modbus.Master.after_send", (self))

        if slave != 0:
            # receive the data from the slave
            response = self._recv(expected_length)
            retval = call_hooks("modbus.Master.after_recv", (self, response))
            if retval <> None:
                response = retval
            if self._verbose:
                LOGGER.debug(utils.get_log_buffer("<- ", response))

            # extract the pdu part of the response
            response_pdu = query.parse_response(response)

            # analyze the received data
            (return_code, byte_2) = struct.unpack(">BB", response_pdu[0:2])

            if return_code > 0x80:
                # the slave has returned an error
                exception_code = byte_2
                raise ModbusError(exception_code)
            else:
                if is_read_function:
                    # get the values returned by the reading function
                    byte_count = byte_2
                    data = response_pdu[2:]
                    if byte_count != len(data):
                        # the byte count in the pdu is invalid
                        raise ModbusInvalidResponseError, "Byte count is %d while actual number of bytes is %d. " \
                            % (byte_count, len(data))
                else:
                    # returns what is returned by the slave after a writing function
                    data = response_pdu[1:]

                #returns the data as a tuple according to the data_format
                #(calculated based on the function or user-defined)
                result = struct.unpack(data_format, data)
                if nb_of_digits > 0:
                    digits = []
                    for byte_val in result:
                        for i in xrange(8):
                            if (len(digits) >= nb_of_digits):
                                break
                            digits.append(byte_val % 2)
                            byte_val = byte_val >> 1
                    result = tuple(digits)
                return result
Example #40
0
    def _do_run(self):
        """called in a almost-for-ever loop by the server"""
        #check the status of every socket
        inputready, outputready, exceptready = select.select(self._sockets, [], [], 1.0)

        for sock in inputready: #handle data on each a socket
            try:
                if sock == self._sock:
                    # handle the server socket
                    client, address = self._sock.accept()
                    client.setblocking(0)
                    LOGGER.info("%s is connected with socket %d..." % (str(address), client.fileno()))
                    self._sockets.append(client)
                    call_hooks("modbus_tcp.TcpServer.on_connect", (self, client, address))
                else:
                    if len(sock.recv(1, socket.MSG_PEEK)) == 0:
                        #socket is disconnected
                        LOGGER.info("%d is disconnected" % (sock.fileno()))
                        call_hooks("modbus_tcp.TcpServer.on_disconnect", (self, sock))
                        sock.close()
                        self._sockets.remove(sock)
                        break
                    
                    # handle all other sockets
                    sock.settimeout(1.0)
                    request = ""
                    is_ok = True
                    
                    #read the 7 bytes of the mbap
                    while (len(request) < 7) and is_ok: 
                        new_byte = sock.recv(1)
                        if len(new_byte) == 0:
                            is_ok = False    
                        else:
                            request += new_byte
                        
                    retval = call_hooks("modbus_tcp.TcpServer.after_recv", (self, sock, request))
                    if retval <> None:
                        request = retval
                    
                    if is_ok:
                        #read the rest of the request
                        length = self._get_request_length(request)
                        while (len(request) < (length + 6)) and is_ok:
                            new_byte = sock.recv(1)
                            if len(new_byte) == 0:
                                is_ok = False
                            else:
                                request += new_byte 
                    
                    if is_ok:
                        response = ""
                        #parse the request
                        try:
                            response = self._handle(request)
                        except Exception, msg:
                            LOGGER.error("Error while handling a request, Exception occurred: %s", msg)
                        
                        #send back the response
                        if response:
                            try:
                                retval = call_hooks("modbus_tcp.TcpServer.before_send", (self, sock, response))
                                if retval <> None:
                                    response = retval
                                sock.send(response)
                            except Exception, msg:
                                is_ok = False
                                LOGGER.error("Error while sending on socket %d, Exception occurred: %s", \
                                             sock.fileno(), msg)
Example #41
0
    def execute(self, slave, function_code, starting_address,
                quantity_of_x=0, output_value=0, data_format="", expected_length=-1):
        """
        Execute a modbus query and returns the data part of the answer as a tuple
        The returned tuple depends on the query function code. see modbus protocol
        specification for details
        data_format makes possible to extract the data like defined in the
        struct python module documentation
        """

        pdu = ""
        is_read_function = False
        nb_of_digits = 0

        #open the connection if it is not already done
        self.open()

        #Build the modbus pdu and the format of the expected data.
        #It depends of function code. see modbus specifications for details.
        if function_code == defines.READ_COILS or function_code == defines.READ_DISCRETE_INPUTS:
            is_read_function = True
            pdu = struct.pack(">BHH", function_code, starting_address, quantity_of_x)
            byte_count = quantity_of_x / 8
            if (quantity_of_x % 8) > 0:
                byte_count += 1
            nb_of_digits = quantity_of_x
            if not data_format:
                data_format = ">"+(byte_count*"B")
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = byte_count + 5  #slave + func + bytcodeLen + bytecode + crc1 + crc2

        elif function_code == defines.READ_INPUT_REGISTERS or function_code == defines.READ_HOLDING_REGISTERS:
            is_read_function = True
            pdu = struct.pack(">BHH", function_code, starting_address, quantity_of_x)
            if not data_format:
                data_format = ">"+(quantity_of_x*"H")
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 2*quantity_of_x + 5  #slave + func + bytcodeLen + bytecode x 2 + crc1 + crc2

        elif (function_code == defines.WRITE_SINGLE_COIL) or (function_code == defines.WRITE_SINGLE_REGISTER):
            if function_code == defines.WRITE_SINGLE_COIL:
                if output_value != 0:
                    output_value = 0xff00
            pdu = struct.pack(">BHH", function_code, starting_address, output_value)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + value1+value2 + crc1 + crc2

        elif function_code == defines.WRITE_MULTIPLE_COILS:
            byte_count = len(output_value) / 8
            if (len(output_value) % 8) > 0:
                byte_count += 1
            pdu = struct.pack(">BHHB", function_code, starting_address, len(output_value), byte_count)
            i, byte_value = 0, 0
            for j in output_value:
                if j > 0:
                    byte_value += pow(2, i)
                if i == 7:
                    pdu += struct.pack(">B", byte_value)
                    i, byte_value = 0, 0
                else:
                    i += 1
            if i > 0:
                pdu += struct.pack(">B", byte_value)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + outputQuant1 + outputQuant2 + crc1 + crc2

        elif function_code == defines.WRITE_MULTIPLE_REGISTERS:
            byte_count = 2 * len(output_value)
            pdu = struct.pack(">BHHB", function_code, starting_address, len(output_value), byte_count)
            for j in output_value:
                pdu += struct.pack(">H", j)
            if not data_format:
                data_format = ">HH"
            if expected_length < 0:  #No lenght was specified and calculated length can be used:
                expected_length = 8  #slave + func + adress1 + adress2 + outputQuant1 + outputQuant2 + crc1 + crc2

        else:
            raise ModbusFunctionNotSupportedError("The %d function code is not supported. " % (function_code))

        # instantiate a query which implements the MAC (TCP or RTU) part of the protocol
        query = self._make_query()

        # add the mac part of the protocol to the request
        request = query.build_request(pdu, slave)

        # send the request to the slave
        retval = call_hooks("modbus.Master.before_send", (self, request))
        if retval <> None:
            request = retval
        if self._verbose:
            LOGGER.debug(utils.get_log_buffer("-> ", request))
        self._send(request)

        call_hooks("modbus.Master.after_send", (self))

        if slave != 0:
            # receive the data from the slave
            response = self._recv(expected_length)
            retval = call_hooks("modbus.Master.after_recv", (self, response))
            if retval <> None:
                response = retval
            if self._verbose:
                LOGGER.debug(utils.get_log_buffer("<- ", response))

            # extract the pdu part of the response
            response_pdu = query.parse_response(response)

            # analyze the received data
            (return_code, byte_2) = struct.unpack(">BB", response_pdu[0:2])

            if return_code > 0x80:
                # the slave has returned an error
                exception_code = byte_2
                raise ModbusError(exception_code)
            else:
                if is_read_function:
                    # get the values returned by the reading function
                    byte_count = byte_2
                    data = response_pdu[2:]
                    if byte_count != len(data):
                        # the byte count in the pdu is invalid
                        raise ModbusInvalidResponseError, "Byte count is %d while actual number of bytes is %d. " \
                            % (byte_count, len(data))
                else:
                    # returns what is returned by the slave after a writing function
                    data = response_pdu[1:]

                #returns the data as a tuple according to the data_format
                #(calculated based on the function or user-defined)
                result = struct.unpack(data_format, data)
                if nb_of_digits > 0:
                    digits = []
                    for byte_val in result:
                        for i in xrange(8):
                            if (len(digits) >= nb_of_digits):
                                break
                            digits.append(byte_val % 2)
                            byte_val = byte_val >> 1
                    result = tuple(digits)
                return result
Example #42
0
 def _do_close(self):
     """Close the serial port if still opened"""
     if self._serial.isOpen():
         self._serial.close()
         call_hooks("modbus_rtu.RtuMaster.after_close", (self, ))
Example #43
0
 def _read_holding_registers(self, request_pdu):
     """handle read coils modbus function"""
     call_hooks("modbus.Slave.handle_read_holding_registers_request", (self, request_pdu))
     return self._read_registers(defines.HOLDING_REGISTERS, request_pdu)
Example #44
0
 def _read_input_registers(self, request_pdu):
     """handle read coils modbus function"""
     call_hooks("modbus.Slave.handle_read_input_registers_request", (self, request_pdu))
     return self._read_registers(defines.ANALOG_INPUTS, request_pdu)
Example #45
0
                            if len(new_byte) == 0:
                                is_ok = False
                            else:
                                request += new_byte 
                    
                    if is_ok:
                        response = ""
                        #parse the request
                        try:
                            response = self._handle(request)
                        except Exception, msg:
                            LOGGER.error("Error while handling a request, Exception occurred: %s", msg)
                        
                        #send back the response
                        if response:
                            try:
                                retval = call_hooks("modbus_tcp.TcpServer.before_send", (self, sock, response))
                                if retval <> None:
                                    response = retval
                                sock.send(response)
                            except Exception, msg:
                                is_ok = False
                                LOGGER.error("Error while sending on socket %d, Exception occurred: %s", \
                                             sock.fileno(), msg)
            except Exception, excpt:
                LOGGER.warning("Error while processing data on socket %d: %s", sock.fileno(), excpt)
                call_hooks("modbus_tcp.TcpServer.on_error", (self, sock, excpt))
                sock.close()
                self._sockets.remove(sock)
                
Example #46
0
 def _read_input_registers(self, request_pdu):
     """handle read coils modbus function"""
     call_hooks("modbus.Slave.handle_read_input_registers_request", (self, request_pdu))
     return self._read_registers(defines.ANALOG_INPUTS, request_pdu)
Example #47
0
 def _do_open(self):
     """Open the given serial port if not already opened"""
     if not self._serial.isOpen():
         call_hooks("modbus_rtu.RtuMaster.before_open", (self, ))
         self._serial.open()
Example #48
0
 def close(self):
     """close the serial communication"""
     if self._serial.isOpen():
         call_hooks("modbus_rtu.RtuServer.before_close", (self, ))
         self._serial.close()
         call_hooks("modbus_rtu.RtuServer.after_close", (self, ))
Example #49
0
                            if len(new_byte) == 0:
                                is_ok = False
                            else:
                                request += new_byte 
                    
                    if is_ok:
                        response = ""
                        #parse the request
                        try:
                            response = self._handle(request)
                        except Exception, msg:
                            LOGGER.error("Error while handling a request, Exception occurred: %s", msg)
                        
                        #send back the response
                        if response:
                            try:
                                retval = call_hooks("modbus_tcp.TcpServer.before_send", (self, sock, response))
                                if retval <> None:
                                    response = retval
                                sock.send(response)
                            except Exception, msg:
                                is_ok = False
                                LOGGER.error("Error while sending on socket %d, Exception occurred: %s", \
                                             sock.fileno(), msg)
            except Exception, excpt:
                LOGGER.warning("Error while processing data on socket %d: %s", sock.fileno(), excpt)
                call_hooks("modbus_tcp.TcpServer.on_error", (self, sock, excpt))
                sock.close()
                self._sockets.remove(sock)
                
Example #50
0
 def _do_init(self):
     """initialize the serial connection"""
     if not self._serial.isOpen():
         call_hooks("modbus_rtu.RtuServer.before_open", (self, ))
         self._serial.open()
         call_hooks("modbus_rtu.RtuServer.after_open", (self, ))
Example #51
0
 def _read_discrete_inputs(self, request_pdu):
     call_hooks("modbus.Slave.handle_read_discrete_inputs_request", (self, request_pdu))
     """handle read coils modbus function"""
     return self._read_digital(defines.DISCRETE_INPUTS, request_pdu)
Example #52
0
 def _do_open(self):
     """Open the given serial port if not already opened"""
     if not self._serial.isOpen():
         call_hooks("modbus_rtu.RtuMaster.before_open", (self, ))
         self._serial.open()
Example #53
0
    def _do_run(self):
        """called in a almost-for-ever loop by the server"""
        #check the status of every socket
        inputready, outputready, exceptready = select.select(self._sockets, [], [], 1.0)

        for sock in inputready: #handle data on each a socket
            try:
                if sock == self._sock:
                    # handle the server socket
                    client, address = self._sock.accept()
                    client.setblocking(0)
                    LOGGER.info("%s is connected with socket %d..." % (str(address), client.fileno()))
                    self._sockets.append(client)
                    call_hooks("modbus_tcp.TcpServer.on_connect", (self, client, address))
                else:
                    if len(sock.recv(1, socket.MSG_PEEK)) == 0:
                        #socket is disconnected
                        LOGGER.info("%d is disconnected" % (sock.fileno()))
                        call_hooks("modbus_tcp.TcpServer.on_disconnect", (self, sock))
                        sock.close()
                        self._sockets.remove(sock)
                        break
                    
                    # handle all other sockets
                    sock.settimeout(1.0)
                    request = ""
                    is_ok = True
                    
                    #read the 7 bytes of the mbap
                    while (len(request) < 7) and is_ok: 
                        new_byte = sock.recv(1)
                        if len(new_byte) == 0:
                            is_ok = False    
                        else:
                            request += new_byte
                        
                    retval = call_hooks("modbus_tcp.TcpServer.after_recv", (self, sock, request))
                    if retval <> None:
                        request = retval
                    
                    if is_ok:
                        #read the rest of the request
                        length = self._get_request_length(request)
                        while (len(request) < (length + 6)) and is_ok:
                            new_byte = sock.recv(1)
                            if len(new_byte) == 0:
                                is_ok = False
                            else:
                                request += new_byte 
                    
                    if is_ok:
                        response = ""
                        #parse the request
                        try:
                            response = self._handle(request)
                        except Exception, msg:
                            LOGGER.error("Error while handling a request, Exception occurred: %s", msg)
                        
                        #send back the response
                        if response:
                            try:
                                retval = call_hooks("modbus_tcp.TcpServer.before_send", (self, sock, response))
                                if retval <> None:
                                    response = retval
                                sock.send(response)
                            except Exception, msg:
                                is_ok = False
                                LOGGER.error("Error while sending on socket %d, Exception occurred: %s", \
                                             sock.fileno(), msg)
Example #54
0
 def _do_close(self):
     """Close the serial port if still opened"""
     if self._serial.isOpen():
         self._serial.close()
         call_hooks("modbus_rtu.RtuMaster.after_close", (self, ))
Example #55
0
 def __setitem__(self, r, v):
     """"""
     call_hooks("modbus.ModbusBlock.setitem", (self, r, v))
     return self._data.__setitem__(r, v)
Example #56
0
 def _read_coils(self, request_pdu):
     """handle read coils modbus function"""
     call_hooks("modbus.Slave.handle_read_coils_request", (self, request_pdu))
     return self._read_digital(defines.COILS, request_pdu)
Example #57
0
 def _read_holding_registers(self, request_pdu):
     """handle read coils modbus function"""
     call_hooks("modbus.Slave.handle_read_holding_registers_request", (self, request_pdu))
     return self._read_registers(defines.HOLDING_REGISTERS, request_pdu)
Example #58
0
 def __setitem__(self, r, v):
     """"""
     call_hooks("modbus.ModbusBlock.setitem", (self, r, v))
     return self._data.__setitem__(r, v)