예제 #1
0
    def respond(self, response_adu):
        """ Send response ADU back to client.

        :param response_adu: A bytearray containing the response of an ADU.
        """
        log.debug('--> {0}'.format(hexlify(response_adu)))
        self.serial_port.write(response_adu)
예제 #2
0
    def respond(self, response_adu):
        """ Send response ADU back to client.

        :param response_adu: A bytearray containing the response of an ADU.
        """
        log.debug('--> {0} - {1}.'.format(self.client_address[0],
                                          hexlify(response_adu)))
        self.request.sendall(response_adu)
예제 #3
0
    def serve_once(self):
        """ Listen and handle 1 request. """
        # 256 is the maximum size of a Modbus RTU frame.
        request_adu = self.serial_port.read(256)
        log.debug("<-- {0}".format(hexlify(request_adu)))

        response_adu = self.process(request_adu)
        self.respond(response_adu)
예제 #4
0
    def serve_once(self):
        """ Listen and handle 1 request. """
        # 256 is the maximum size of a Modbus RTU frame.
        request_adu = self.serial_port.read(256)
        log.debug('<-- {0}'.format(hexlify(request_adu)))

        response_adu = self.process(request_adu)
        self.respond(response_adu)
예제 #5
0
    def create_response_pdu(self, data):
        """ Create response pdu.

        :param data: A list with values.
        :return: Byte array of at least 4 bytes.
        """
        log.debug('Create multi bit response pdu {0}.'.format(data))
        fmt = '>BB' + conf.TYPE_CHAR * len(data)

        return struct.pack(fmt, self.function_code, len(data) * 2, *data)
예제 #6
0
    def create_response_pdu(self, data):
        """ Create response pdu.

        :param data: A list with values.
        :return: Byte array of at least 4 bytes.
        """
        log.debug('Create multi bit response pdu {0}.'.format(data))
        fmt = '>BB' + conf.TYPE_CHAR * len(data)

        return struct.pack(fmt, self.function_code, len(data) * 2, *data)
예제 #7
0
    def create_response_pdu(self, data):
        """ Create response pdu.

        :param data: A list with 0's and/or 1's.
        :return: Byte array of at least 3 bytes.
        """
        log.debug('Create single bit response pdu {0}.'.format(data))
        bytes_ = [data[i:i + 8] for i in range(0, len(data), 8)]

        # Reduce each all bits per byte to a number. Byte
        # [0, 0, 0, 0, 0, 1, 1, 1] is intepreted as binary en is decimal 3.
        for index, byte in enumerate(bytes_):
            bytes_[index] = \
                reduce(lambda a, b: (a << 1) + b, list(reversed(byte)))

        log.debug('Reduced single bit data to {0}.'.format(bytes_))
        # The first 2 B's of the format encode the function code (1 byte) and
        # the length (1 byte) of the following byte series. Followed by # a B
        # for every byte in the series of bytes. 3 lead to the format '>BBB'
        # and 257 lead to the format '>BBBB'.
        fmt = '>BB' + self.format_character * len(bytes_)
        return struct.pack(fmt, self.function_code, len(bytes_), *bytes_)
예제 #8
0
    def create_response_pdu(self, data):
        """ Create response pdu.

        :param data: A list with 0's and/or 1's.
        :return: Byte array of at least 3 bytes.
        """
        log.debug('Create single bit response pdu {0}.'.format(data))
        bytes_ = [data[i:i + 8] for i in range(0, len(data), 8)]

        # Reduce each all bits per byte to a number. Byte
        # [0, 0, 0, 0, 0, 1, 1, 1] is intepreted as binary en is decimal 3.
        for index, byte in enumerate(bytes_):
            bytes_[index] = \
                reduce(lambda a, b: (a << 1) + b, list(reversed(byte)))

        log.debug('Reduced single bit data to {0}.'.format(bytes_))
        # The first 2 B's of the format encode the function code (1 byte) and
        # the length (1 byte) of the following byte series. Followed by # a B
        # for every byte in the series of bytes. 3 lead to the format '>BBB'
        # and 257 lead to the format '>BBBB'.
        fmt = '>BB' + self.format_character * len(bytes_)
        return struct.pack(fmt, self.function_code, len(bytes_), *bytes_)
예제 #9
0
    def process(self, request_adu):
        """ Process request ADU and return response.

        :param request_adu: A bytearray containing the ADU request.
        :return: A bytearray containing the response of the ADU request.
        """
        log.debug('Lenght of received ADU is {0}.'.format(len(request_adu)))
        log.info('<-- {0} - {1}.'.format(self.client_address[0],
                 hexlify(request_adu)))
        try:
            transaction_id, protocol_id, _, unit_id = \
                unpack_mbap(request_adu[:7])

            function = function_factory(request_adu[7:])
            results = function.execute(unit_id, self.server.route_map)

            try:
                # ReadFunction's use results of callbacks to build response
                # PDU...
                response_pdu = function.create_response_pdu(results)
            except TypeError:
                # ...other functions don't.
                response_pdu = function.create_response_pdu()
        except ModbusError as e:
            function_code = get_function_code_from_request_pdu(request_adu[7:])
            response_pdu = pack_exception_pdu(function_code, e.error_code)
        except Exception as e:
            log.exception('Could not handle request: {0}.'.format(e))
            function_code = get_function_code_from_request_pdu(request_adu[7:])
            response_pdu = \
                pack_exception_pdu(function_code,
                                   ServerDeviceFailureError.error_code)

        response_mbap = pack_mbap(transaction_id, protocol_id,
                                  len(response_pdu) + 1, unit_id)

        log.debug('Response MBAP {0}'.format(response_mbap))
        log.debug('Response PDU {0}'.format(response_pdu))

        response_adu = response_mbap + response_pdu

        return response_adu
예제 #10
0
파일: master.py 프로젝트: petonic/rsdriver
def main():
    global serial_port
    try:
        serial_port = get_serial_port()
    except:
        e = sys.exec_info()[0]
        print("Error opening serial port <{}>".format(repr(e)))
        sys.exit(1)

    # Print out initial commands
    for i in cmds:
        print("{}{} {}".format(i[0], " <device>" if i[1] else "", i[2]))

    while True:
        line = input(
            'master: <cmd> <dev> [<opt_data>] ("stop" to quit, ? = help): ')
        if line == 'stop':
            break
        if line == 'help' or line == '?':
            for i in cmds:
                print("{}{} {}".format(i[0], " <device>" if i[1] else "",
                                       i[2]))
            continue

        # FIXME: Get a better, more modular parsing routine, but this hack
        # will work for not.
        lineArr = line.split(' ', 2)
        import pdb
        pdb.set_trace()
        try:
            (cmd, device_s, remainder) = line.split(" ", 2)
        except ValueError:
            import pdb
            pdb.set_trace()
            print("Not enough arguments provided")
            continue

        # Get the device number
        try:
            device = int(device_s)
        except:
            print("Device can only be integer: <{}>".format(device_s))
            continue

        foundCommand = False
        # Match which command
        for i in cmds:
            if i[0] == cmd:
                # Get remaining parms, if any
                cmdArgs = remainder.split(" ", i[1] - 2)
                print("Found command {} with dev {:d} and parms <{}>".format(
                    i[0], device, repr(cmdArgs)))
                if len(cmdArgs) < (i[1] - 1):
                    print(
                        "Error, not enough arguments for command, need %d, got %d"
                        % (i[1], len(cmdArgs) + 1))
                    break
                foundCommand = True
                break
        # Must not have found a match
        if not foundCommand:
            print("Invalid command line: <{}>".format(line))
            continue

        # Dynamically call the processing function for the command
        log.debug("Calling command %s on dev %d with args <%s>" %
                  (cmd, device, repr(cmdArgs)))

        getattr(sys.modules[__name__], "do_%s" % cmd)(device, cmdArgs)
예제 #11
0
파일: master.py 프로젝트: petonic/rsdriver
from umodbus.utils import log_to_stream
import re
try:
    import gnureadline as readline
except ImportError:
    import readline

ignore_timeouts = True

########################################################
# Set up logging
########################################################
log = getLogger('uModbus')
log.setLevel(logging.DEBUG)
log_to_stream(stream=sys.stderr, level=logging.DEBUG)
log.debug("Logging is set to debug")

baud = 9600
rsdev = "/dev/rs485"


def get_serial_port():
    """ Return serial.Serial instance, ready to use for RS485."""
    port = Serial(port=rsdev,
                  baudrate=baud,
                  parity=PARITY_NONE,
                  stopbits=1,
                  bytesize=8,
                  timeout=1)

    fh = port.fileno()