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)
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)
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)
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)
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)
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_)
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
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)
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()