class ModbusWrapperServer(): def __init__(self, port=1234, sub_topic="modbus_server/write_to_registers", pub_topic="modbus_server/read_from_registers"): """ Creates a Modbus TCP Server object .. note:: The default port for modbus is 502. This modbus server uses port 1234 by default, otherwise superuser rights are required. .. note:: Use "startServer" to start the listener. :param port: Port for the modbus TCP server :type port: int :param sub_topic: ROS topic name for the subscriber that updates the modbus registers :type sub_topic: string :param pub_topic: ROS topic name for the publisher that publishes a message, once there is something written to the writeable modbus registers :type pub_topic: string """ chr = CustomHoldingRegister(ADDRESS_WRITE_START, [17] * 100, sub_topic, pub_topic) self.store = ModbusSlaveContext( di=ModbusSequentialDataBlock(ADDRESS_WRITE_START, [17] * 100), co=ModbusSequentialDataBlock(ADDRESS_WRITE_START, [17] * 100), hr=chr, ir=ModbusSequentialDataBlock(ADDRESS_WRITE_START, [17] * 100)) self.context = ModbusServerContext(slaves=self.store, single=True) self.identity = ModbusDeviceIdentification() self.identity.VendorName = 'Pymodbus' self.identity.ProductCode = 'PM' self.identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' self.identity.ProductName = 'Pymodbus Server' self.identity.ModelName = 'Pymodbus Server' self.identity.MajorMinorRevision = '1.0' self.store.setValues(2, 0, [0] * 1) self.post = Post(self) framer = ModbusSocketFramer self.server = ModbusTcpServer(self.context, framer, self.identity, address=("0.0.0.0", port)) def startServer(self): """ Non blocking call to start the server """ self.post.__startServer() rospy.loginfo("Modbus server started") def __startServer(self): self.server.serve_forever() def stopServer(self): """ Closes the server """ self.server.server_close() self.server.shutdown() def waitForCoilOutput(self, address, timeout=2): """ Blocks for the timeout in seconds (or forever) until the specified address becomes true. Adapt this to your needs :param address: Address of the register that wanted to be read. :type address: int :param timeout: The time in seconds until the function should return latest. :type: float/int """ now = time.time() while True: values = self.store.getValues(1, address, 1) if values[0] is True: return True else: if timeout <= 0 or now + timeout > time.time(): time.sleep(1 / 50) else: return False def setDigitalInput(self, address, values): """ Writes to the digital input of the modbus server :param address: Starting address of the values to write :type: int :param values: List of values to write :type list/boolean/int """ if not values is list: values = [values] self.store.setValues(2, address, values)
class ModbusWrapperServer(): def __init__(self,port=1234,sub_topic="modbus_server/write_to_registers",pub_topic="modbus_server/read_from_registers"): """ Creates a Modbus TCP Server object .. note:: The default port for modbus is 502. This modbus server uses port 1234 by default, otherwise superuser rights are required. .. note:: Use "startServer" to start the listener. :param port: Port for the modbus TCP server :type port: int :param sub_topic: ROS topic name for the subscriber that updates the modbus registers :type sub_topic: string :param pub_topic: ROS topic name for the publisher that publishes a message, once there is something written to the writeable modbus registers :type pub_topic: string """ chr = CustomHoldingRegister(ADDRESS_WRITE_START, [17]*100,sub_topic,pub_topic) self.store = ModbusSlaveContext( di = ModbusSequentialDataBlock(ADDRESS_WRITE_START, [17]*100), co = ModbusSequentialDataBlock(ADDRESS_WRITE_START, [17]*100), hr = chr, ir = ModbusSequentialDataBlock(ADDRESS_WRITE_START, [17]*100)) self.context = ModbusServerContext(slaves=self.store, single=True) self.identity = ModbusDeviceIdentification() self.identity.VendorName = 'Pymodbus' self.identity.ProductCode = 'PM' self.identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' self.identity.ProductName = 'Pymodbus Server' self.identity.ModelName = 'Pymodbus Server' self.identity.MajorMinorRevision = '1.0' self.store.setValues(2,0,[0]*1) self.post = Post(self) framer = ModbusSocketFramer self.server = ModbusTcpServer(self.context, framer, self.identity, address=("0.0.0.0", port)) def startServer(self): """ Non blocking call to start the server """ self.post.__startServer() rospy.loginfo("Modbus server started") def __startServer(self): self.server.serve_forever() def stopServer(self): """ Closes the server """ self.server.server_close() self.server.shutdown() def waitForCoilOutput(self,address,timeout=2): """ Blocks for the timeout in seconds (or forever) until the specified address becomes true. Adapt this to your needs :param address: Address of the register that wanted to be read. :type address: int :param timeout: The time in seconds until the function should return latest. :type: float/int """ now = time.time() while True: values = self.store.getValues(1,address, 1) if values[0] is True: return True else: if timeout <=0 or now + timeout > time.time(): time.sleep(1/50) else: return False def setDigitalInput(self,address,values): """ Writes to the digital input of the modbus server :param address: Starting address of the values to write :type: int :param values: List of values to write :type list/boolean/int """ if not values is list: values = [values] self.store.setValues(2,address,values)