예제 #1
0
class LoggingContextReader(object):
    def __init__(self, output):
        """ Initialize a new instance of the logger

        :param output: The output file to save to
        """
        self.output = output
        self.context = ModbusSlaveContext(
            di=ModbusSequentialDataBlock.create(),
            co=ModbusSequentialDataBlock.create(),
            hr=ModbusSequentialDataBlock.create(),
            ir=ModbusSequentialDataBlock.create())

    def write(self, response):
        """ Handle the next modbus response

        :param response: The response to process
        """
        log.info("Read Data: %s" % str(response))
        fx, address, values = response
        self.context.setValues(fx, address, values)

    def finalize(self):
        with open(self.output, "wb") as handle:
            pickle.dump(self.context, handle)
예제 #2
0
class LoggingContextReader(object):

    def __init__(self, output):
        """ Initialize a new instance of the logger

        :param output: The output file to save to
        """
        self.output  = output
        self.context = ModbusSlaveContext(
            di = ModbusSequentialDataBlock.create(),
            co = ModbusSequentialDataBlock.create(),
            hr = ModbusSequentialDataBlock.create(),
            ir = ModbusSequentialDataBlock.create())

    def write(self, response):
        """ Handle the next modbus response

        :param response: The response to process
        """
        log.info("Read Data: %s" % str(response))
        fx, address, values = response
        self.context.setValues(fx, address, values)

    def finalize(self):
        with open(self.output, "w") as handle:
            pickle.dump(self.context, handle)
예제 #3
0
class VirtualModbusTCPServer:

    def __init__(self, port):
        self.port = port

        self.block = ModbusSequentialDataBlock.create()
        self.store = ModbusSlaveContext(ir=self.block)
        self.context = ModbusServerContext(slaves=self.store, single=True)

        self.scheduler = BackgroundScheduler()
        params = {
            'hour': os.environ.get("VIRTUAL_SERVER_UPDATE_CRON_HOUR_TRIGGER"),
            'minute': os.environ.get("VIRTUAL_SERVER_UPDATE_CRON_MINUTE_TRIGGER"),
            'second': os.environ.get("VIRTUAL_SERVER_UPDATE_CRON_SECOND_TRIGGER"),
        }
        self.main_job = self.scheduler.add_job(**params, func=self.set_datastore, trigger='cron')
        
        

    def set_datastore(self):
        FUNCTION_CODE = 0x04
        ADDRESS = 0x00

        builder = BinaryPayloadBuilder(byteorder=Endian.Big, wordorder=Endian.Big)
        builder.add_32bit_float(3.14)

        self.store.setValues(FUNCTION_CODE, ADDRESS, builder.to_registers())


    def start(self):
        self.scheduler.start()
        StartTcpServer(self.context, address=("0.0.0.0", self.port))
예제 #4
0
 def test_decode(self):
     test_store = ModbusSlaveContext(t=ModbusSequentialDataBlock.create())
     test_env = {'fields':
                     {'scale_8_int':
                          {'reg_type': CO, 'address': 1,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': INT8}
                           },
                      'scale_8_uint':
                          {'reg_type': CO, 'address': 4,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': UINT8}
                           },
                      'scale_16_int':
                          {'reg_type': CO, 'address': 6,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': INT16}
                           },
                      'scale_16_uint':
                          {'reg_type': CO, 'address': 8,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': UINT16}
                           }},
                 'byte_order': '<',
                 'word_order': '<',
                 'default_scaling_factor': 1000}
     test_fields = test_env['fields']
     test_handler = PayloadHandler(test_env, test_store)
     test_builder = BinaryPayloadBuilder('<', '<')
     test_builder.reset()
     test_builder.add_8bit_int(100)
     test_store.setValues(1, 1, test_builder.to_registers())
     self.assertEqual(10,
                      test_handler.decode(1, 1, test_fields['scale_8_int']['encode']))
     test_builder.reset()
     test_builder.add_8bit_uint(100)
     test_store.setValues(1, 4, test_builder.to_registers())
     self.assertEqual(10,
                      test_handler.decode(1, 4, test_fields['scale_8_uint']['encode']))
     test_builder.reset()
     test_builder.add_16bit_int(1350)
     test_store.setValues(1, 6, test_builder.to_registers())
     self.assertEqual(13.5,
                      test_handler.decode(1, 6, test_fields['scale_16_int']['encode']))
     test_builder.reset()
     test_builder.add_16bit_uint(3287)
     test_store.setValues(1, 8, test_builder.to_registers())
     self.assertEqual(32.87,
                      test_handler.decode(1, 8, test_fields['scale_16_uint']['encode']))
     test_builder.reset()
예제 #5
0
def run_server():
    store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [0] * 10000),
                               co=ModbusSequentialDataBlock(0, [0] * 10000),
                               hr=ModbusSequentialDataBlock(0, [0] * 10000),
                               ir=ModbusSequentialDataBlock(0, [0] * 10000))

    context = ModbusServerContext(slaves=store, single=True)
    identity = ModbusDeviceIdentification()
    identity.VendorName = 'Pymodbus'
    identity.ProductCode = 'PM'
    # identity.VendorUrl = 'http://github.com/riptideio/pymodbus/'
    identity.ProductName = 'Pymodbus Server'
    identity.ModelName = 'Pymodbus Server'
    identity.MajorMinorRevision = '1.5'
    #-----------------------------------------------------
    print("debug started\n\n")

    print(dir(store))
    store.setValues(3, 53, [30000])

    print("\n\ndebug finished")
    #-----------------------------------------------------
    print("Listening on {}:{}".format(HOST, PORT))
    StartTcpServer(context, identity=identity, address=(HOST, PORT))
예제 #6
0
 def test_no_e_type(self):
     test_store = ModbusSlaveContext(t=ModbusSequentialDataBlock.create())
     test_env = {'fields':
                     {'8_int':
                          {'reg_type': CO, 'address': 1,
                           'encode': {'d_type': INT8}
                           },
                      '8_uint':
                          {'reg_type': CO, 'address': 2,
                           'encode': {'d_type': UINT8}
                           },
                      '16_int':
                          {'reg_type': CO, 'address': 3,
                           'encode': {'d_type': INT16}
                           },
                      '16_uint':
                          {'reg_type': CO, 'address': 4,
                           'encode': {'d_type': UINT16}
                           },
                      '32_int':
                          {'reg_type': CO, 'address': 5,
                           'encode': {'d_type': INT32}
                           },
                      '32_uint':
                          {'reg_type': CO, 'address': 6,
                           'encode': {'d_type': UINT32}
                           }},
                 'byte_order': '<',
                 'word_order': '<',
                 'default_scaling_factor': 1000}
     test_fields = test_env['fields']
     test_handler = PayloadHandler(test_env, test_store)
     test_store.setValues(1, 1, test_handler.encode(1, test_fields['8_int']['encode']))
     self.assertEqual(1, test_handler.decode(1, 1, test_fields['8_int']['encode']))
     test_store.setValues(1, 2, test_handler.encode(10, test_fields['8_uint']['encode']))
     self.assertEqual(10, test_handler.decode(1, 2, test_fields['8_uint']['encode']))
     test_store.setValues(1, 3, test_handler.encode(12, test_fields['16_int']['encode']))
     self.assertEqual(12, test_handler.decode(1, 3, test_fields['16_int']['encode']))
     test_store.setValues(1, 4, test_handler.encode(32, test_fields['16_uint']['encode']))
     self.assertEqual(32, test_handler.decode(1, 4, test_fields['16_uint']['encode']))
     test_store.setValues(1, 5, test_handler.encode(1000, test_fields['32_int']['encode']))
     self.assertEqual(1000, test_handler.decode(1, 5, test_fields['32_int']['encode']))
     test_store.setValues(1, 6, test_handler.encode(63, test_fields['32_uint']['encode']))
     self.assertEqual(63, test_handler.decode(1, 6, test_fields['32_uint']['encode']))
예제 #7
0
 def test_combo(self):
     test_store = ModbusSlaveContext(t=ModbusSequentialDataBlock.create())
     test_env = {'fields':
                     {'scale_8_int':
                          {'reg_type': CO, 'address': 1,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': INT8}
                           },
                      'scale_8_uint':
                          {'reg_type': CO, 'address': 2,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': UINT8}
                           },
                      'scale_16_int':
                          {'reg_type': CO, 'address': 3,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': INT16}
                           },
                      'scale_16_uint':
                          {'reg_type': CO, 'address': 4,
                           'encode': {'e_type': SCALE, 's_factor': 100, 'd_type': UINT16}
                           },
                      'scale_32_int':
                          {'reg_type': CO, 'address': 5, 'encode': {'e_type': SCALE, 'd_type': INT32}
                           },
                      'scale_32_uint':
                          {'reg_type': CO, 'address': 6, 'encode': {'e_type': SCALE, 'd_type': UINT32}
                           },
                      'scale_32_float':
                          {'reg_type': CO, 'address': 7,
                           'encode': {'e_type': SCALE, 's_factor': 10, 'd_type': FLOAT32}
                           },
                      'comb_32_float':
                          {'reg_type': CO, 'address': 8, 'encode': {'e_type': COMB, 'd_type': FLOAT32}
                           }},
                 'byte_order': '<',
                 'word_order': '<',
                 'default_scaling_factor': 1000}
     test_fields = test_env['fields']
     test_handler = PayloadHandler(test_env, test_store)
     test_store.setValues(1, 1, test_handler.encode(1, test_fields['scale_8_int']['encode']))
     self.assertEqual(1, test_handler.decode(1, 1, test_fields['scale_8_int']['encode']))
     test_store.setValues(1, 2, test_handler.encode(10, test_fields['scale_8_uint']['encode']))
     self.assertEqual(10, test_handler.decode(1, 2, test_fields['scale_8_uint']['encode']))
     test_store.setValues(1, 3, test_handler.encode(12.5, test_fields['scale_16_int']['encode']))
     self.assertEqual(12.5, test_handler.decode(1, 3, test_fields['scale_16_int']['encode']))
     test_store.setValues(1, 4, test_handler.encode(32.991, test_fields['scale_16_uint']['encode']))
     self.assertEqual(32.99, test_handler.decode(1, 4, test_fields['scale_16_uint']['encode']))
     test_store.setValues(1, 5, test_handler.encode(1000, test_fields['scale_32_int']['encode']))
     self.assertEqual(1000, test_handler.decode(1, 5, test_fields['scale_32_int']['encode']))
     test_store.setValues(1, 6, test_handler.encode(63.2, test_fields['scale_32_uint']['encode']))
     self.assertEqual(63.2, test_handler.decode(1, 6, test_fields['scale_32_uint']['encode']))
     test_store.setValues(1, 7, test_handler.encode(1.333, test_fields['scale_32_float']['encode']))
     self.assertEqual(1.3, test_handler.decode(1, 7, test_fields['scale_32_float']['encode']))
     test_store.setValues(1, 8, test_handler.encode(789.4375, test_fields['comb_32_float']['encode']))
     self.assertEqual(789.4375, test_handler.decode(1, 8, test_fields['comb_32_float']['encode']))
예제 #8
0
                block_1601.add_16bit_int(10000)  # power/energy adjustment l1
                block_1601.add_16bit_int(10000)  # power/energy adjustment l2
                block_1601.add_16bit_int(10000)  # power/energy adjustment l3
                block_1601.add_16bit_int(-1000)  # ct phase angle adjustment l1
                block_1601.add_16bit_int(-1000)  # ct phase angle adjustment l2
                block_1601.add_16bit_int(-1000)  # ct phase angle adjustment l3
                block_1601.add_16bit_int(1500)  # minimum power reading
                block_1601.add_16bit_int(
                    confparser[meter].getint("phase_offset",
                                             fallback=default_config["meters"]
                                             ["phase_offset"]))  # phase offset
                block_1601.add_16bit_int(0)  # reset energy
                block_1601.add_16bit_int(0)  # reset demand
                block_1601.add_16bit_int(20000)  # current scale
                block_1601.add_16bit_int(0)  # io pin mode
                slave_ctx.setValues(3, 1600, block_1601.to_registers())

                block_1651 = BinaryPayloadBuilder(byteorder=Endian.Big,
                                                  wordorder=Endian.Little)
                block_1651.add_16bit_int(0)  # apply config
                block_1651.add_16bit_int(address)  # modbus address
                block_1651.add_16bit_int(4)  # baud rate
                block_1651.add_16bit_int(0)  # parity mode
                block_1651.add_16bit_int(0)  # modbus mode
                block_1651.add_16bit_int(5)  # message delay
                slave_ctx.setValues(3, 1650, block_1651.to_registers())

                block_1701 = BinaryPayloadBuilder(byteorder=Endian.Big,
                                                  wordorder=Endian.Little)
                block_1701.add_32bit_int(confparser[meter].getint(
                    "serial_number",
예제 #9
0
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)
예제 #10
0
def run_server():
    store = ModbusSlaveContext(di=ModbusSequentialDataBlock(0, [0] * 10000),
                               co=ModbusSequentialDataBlock(0, [0] * 10000),
                               hr=ModbusSequentialDataBlock(0, [0] * 10000),
                               ir=ModbusSequentialDataBlock(0, [0] * 10000))

    context = ModbusServerContext(slaves=store, single=True)
    identity = ModbusDeviceIdentification()
    identity.VendorName = 'Pymodbus'
    identity.ProductCode = 'PM'
    # identity.VendorUrl = 'http://github.com/riptideio/pymodbus/'
    identity.ProductName = 'Pymodbus Server'
    identity.ModelName = 'Pymodbus Server'
    identity.MajorMinorRevision = '1.5'
    #-----------------------------------------------------
    # print("debug started\n\n")

    # print(dir(store))
    store.setValues(3, 53, [30000])
    store.setValues(3, 32, [14373])
    store.setValues(3, 33, [28911])
    store.setValues(3, 61, [59626])
    store.setValues(3, 26, [22288])
    store.setValues(3, 89, [59530])
    store.setValues(3, 90, [22198])
    store.setValues(3, 2, [27306])
    store.setValues(3, 10, [24285])
    store.setValues(3, 52, [9160])
    store.setValues(3, 32, [8707])
    store.setValues(3, 74, [41718])
    store.setValues(3, 78, [40553])
    store.setValues(3, 93, [44444])
    store.setValues(3, 65, [45136])
    store.setValues(3, 24, [39191])

    store.setValues(2, 1, [1])
    store.setValues(2, 12, [1])
    store.setValues(2, 101, [1])
    store.setValues(2, 8, [1])
    store.setValues(2, 94, [1])
    store.setValues(2, 23, [1])
    store.setValues(2, 34, [1])
    store.setValues(2, 65, [1])
    store.setValues(2, 66, [1])
    store.setValues(2, 67, [1])
    store.setValues(2, 97, [1])
    store.setValues(2, 99, [1])
    store.setValues(2, 14, [1])
    store.setValues(2, 76, [1])

    store.setValues(1, 1, [1])
    store.setValues(1, 11, [1])
    store.setValues(1, 21, [1])
    store.setValues(1, 31, [1])
    store.setValues(1, 41, [1])
    store.setValues(1, 42, [1])
    store.setValues(1, 101, [1])
    store.setValues(1, 129, [1])
    store.setValues(1, 259, [1])
    store.setValues(1, 111, [1])
    store.setValues(1, 192, [1])

    store.setValues(4, 0, [22])
    store.setValues(4, 19, [69])
    store.setValues(4, 40, [99])
    store.setValues(4, 51, [14])
    store.setValues(4, 17, [35])
    store.setValues(4, 28, [24])
    store.setValues(4, 54, [31])
    store.setValues(4, 7, [84])
    store.setValues(4, 12, [31])
    store.setValues(4, 43, [7])
    store.setValues(4, 53, [54])
    store.setValues(4, 2, [69])
    store.setValues(4, 35, [38])
    store.setValues(4, 53, [50])
    store.setValues(4, 17, [99])

    # print("\n\ndebug finished")
    #-----------------------------------------------------
    print("Listening on {}:{}".format(HOST, PORT))
    StartTcpServer(context, identity=identity, address=(HOST, PORT))
class plcSlave():
	def __init__(self, plcIP, plcPort, initialRegisters, plcName):
		self.plcIP=plcIP
		self.plcPort=plcPort
		self.dataStore = 0
		self.context = 0
		self.identity = 0
		self.initialRegisters =  initialRegisters
		self.plcName = plcName
		self.run_async_server(address=(self.plcIP,self.plcPort))
	def run_async_server(self, address):
		# ----------------------------------------------------------------------- # 
		# initialize your data store
		# ----------------------------------------------------------------------- # 
		# The datastores only respond to the addresses that they are initialized to
		# Therefore, if you initialize a DataBlock to addresses from 0x00 to 0xFF,
		# a request to 0x100 will respond with an invalid address exception.
		# This is because many devices exhibit this kind of behavior (but not all)
		#
		#     block = ModbusSequentialDataBlock(0x00, [0]*0xff)
		#
		# Continuing, you can choose to use a sequential or a sparse DataBlock in
		# your data context.  The difference is that the sequential has no gaps in
		# the data while the sparse can. Once again, there are devices that exhibit
		# both forms of behavior::
		#
		#     block = ModbusSparseDataBlock({0x00: 0, 0x05: 1})
		#     block = ModbusSequentialDataBlock(0x00, [0]*5)
		#
		# Alternately, you can use the factory methods to initialize the DataBlocks
		# or simply do not pass them to have them initialized to 0x00 on the full
		# address range::
		#
		#     store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create())
		#     store = ModbusSlaveContext()
		#
		# Finally, you are allowed to use the same DataBlock reference for every
		# table or you you may use a seperate DataBlock for each table.
		# This depends if you would like functions to be able to access and modify
		# the same data or not::
		#
		#     block = ModbusSequentialDataBlock(0x00, [0]*0xff)
		#     store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block)
		#
		# The server then makes use of a server context that allows the server to
		# respond with different slave contexts for different unit ids. By default
		# it will return the same context for every unit id supplied (broadcast
		# mode).
		# However, this can be overloaded by setting the single flag to False
		# and then supplying a dictionary of unit id to context mapping::
		#
		#     slaves  = {
		#         0x01: ModbusSlaveContext(...),
		#         0x02: ModbusSlaveContext(...),
		#         0x03: ModbusSlaveContext(...),
		#     }
		#     context = ModbusServerContext(slaves=slaves, single=False)
		#
		# The slave context can also be initialized in zero_mode which means that a
		# request to address(0-7) will map to the address (0-7). The default is
		# False which is based on section 4.4 of the specification, so address(0-7)
		# will map to (1-8)::
		#
		#     store = ModbusSlaveContext(..., zero_mode=True)
		# ----------------------------------------------------------------------- # 
		self.dataStore = ModbusSlaveContext(
			di=ModbusSequentialDataBlock(0, [17]*100),
			co=ModbusSequentialDataBlock(0, [17]*100),
			hr=ModbusSequentialDataBlock(0, [17]*100),
			ir=ModbusSequentialDataBlock(0, [17]*100))
		self.context = ModbusServerContext(slaves=self.dataStore, single=True)
		
		# ----------------------------------------------------------------------- # 
		# initialize the server information
		# ----------------------------------------------------------------------- # 
		# If you don't set this or any fields, they are defaulted to empty strings.
		# ----------------------------------------------------------------------- # 
		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'
		
		# ----------------------------------------------------------------------- # 
		# run the server (listener)
		# ----------------------------------------------------------------------- # 

		framer  = ModbusSocketFramer
		factory = ModbusServerFactory(self.context, framer, self.identity)
		reactor.listenTCP(address[1], factory, interface=address[0])

	def start(self):
		coil_list = 1
		holdregister = 3

		self.setCoils(0x00,[1,0,0,0,0,0,0,0,0,0,0,0,0])
		self.setHoldingRegisters(0x00,self.initialRegisters) 
		threading.Thread(target = self.operateLightTimer).start()

	def getHoldingRegisters(self, startByte, bytesCount):
	    return self.dataStore.getValues(3, startByte,count=bytesCount)
		
	def getCoils(self, startBit, bitCount):
	    return self.dataStore.getValues(1,startBit,count=bitCount)

	def setHoldingRegisters(self,address,values):
		
		self.dataStore.setValues(3,address,values)
	def setCoils(self, address, values):
		self.dataStore.setValues(1,address,values)
	
	def changeLightColor(self,northsouth, color):
		
	    registers = self.getHoldingRegisters(0x00,4)
	    if northsouth == 1:
		    registers[0] = color
		    registers[2] = color
	    else:
		    registers[1] = color
		    registers[3] = color
	    self.dataStore.setValues(3,0x00,registers)
	    
	def operateLightTimer(self):
		#################################
		# coils[0] = 1 - machine initialization (move to normal operations)
		# coils[1] = 1 - machine moved to normal operations
		# coils[2] = 1 - east/west side is green or yellow
		# coils[3] = 1 - north/south side is green yellow
		# coils[4] = 1 - put the machine into maintenancemode (ALL FLASHING RED LIGHTS)
		# coils[5] = 1 - machine moved to mainteance mode
		# coils[6] = 1 - puts the machine into TEST Mode (ALL LIGHTS ON)
		# coils[7] = 1 - machine moved to TEST mode
		# holdingRegister[0,2] - north/south light state	0 = red, 1 = yellow, 2 = green, 3 = ALL OFF, 4 = ALL ON
		# holdingRegister[1,3] - east/west light state
		# holdingRegister [4] - timer/counter
		# holdingRegisters [5,6,7] - timer values that cause an increment in logic
		################
		
		coils = self.getCoils(0,10)
		
		#this is the main operation loop
		while True:
			coils = self.getCoils(0,10)
			regs = self.getHoldingRegisters(0,10)

			if coils[0] == 1: 			#initialize NORMAL OPS
				print("The traffic light at: " + str(self.plcName) + " is starting")
				self.setCoils(0x00,[0,1,1,0,0,0,0,0,0])
				self.setHoldingRegisters(0x00,[0,2,0,2,0,10,12,14]) 
			elif coils[4] == 1:			#move into MAINTENANCE
				print("The traffic light at: " + str(self.plcName) + " is going into MAINTENANCE")
				self.setCoils(0x00,[0,0,0,0,0,1,0,0,0])
				self.setHoldingRegisters(0x00,[0,0,0,0,0])
			elif coils[6] == 1:			#move into TEST
				print("The traffic light at: " + str(self.plcName) + " is going into TEST mode")
				self.setCoils(0x00,[0,0,0,0,0,0,0,1,0])
				self.setHoldingRegisters(0x00,[0,0,0,0,0])
			counter = regs[4]
			print(self.plcName + "....Coils: " + str(coils[0:10]) +"\t\tRegisters: " + str(regs[0:10]))
			if coils[1] == True:						##standard traffic light operation		
				
				self.setHoldingRegisters(4,[counter + 1])
				if counter == regs[5]: #change the green to yellow
					sys.stdout.write("X")
					sys.stdout.flush() 
					if coils[2] == 1:
						self.changeLightColor(0, 1)		#change the east west side to yellow
					if coils[3] == 1:
						self.changeLightColor(1,1)		#change the north/south side to yellow
						
				elif counter == regs[6]: #everyone goes to red
					sys.stdout.write("X")
					sys.stdout.flush()
					self.changeLightColor(1,0)
					self.changeLightColor(0,0)
					
				elif counter == regs[7]: #change the red light to green (for the favored side)
					sys.stdout.write("X")
					sys.stdout.flush()
					if coils[2] == 1:	#east/west was green, change it to red
						self.setCoils(0x02,[0,1])
						self.changeLightColor(1,2)
					elif coils[3] == 1:	#north/south was green, change it to red
						self.setCoils(0x02,[1,0])
						self.changeLightColor(0,2)
					self.setHoldingRegisters(0x04,[0])
				else:
					sys.stdout.write(".")
					sys.stdout.flush()
				time.sleep(1)
			elif coils[5] == True:							##maintenance
				if regs[0] == 0: 	#displaying a red light, make it flash
					self.setHoldingRegisters(0,[3,3,3,3])
				elif regs[0] == 3:							#blank light, change to red
					self.setHoldingRegisters(0,[0,0,0,0])
				else:
					self.setHoldingRegisters(0,[3,3,3,3])
				time.sleep(1)
			elif coils[7] == True:						#test mode
				if regs[0] == 3: 	#displaying a red light, make it flash
					self.setHoldingRegisters(0,[4,4,4,4])
				elif regs[0] == 4:							#blank light, change to red
					self.setHoldingRegisters(0,[3,3,3,3])
				else:
					self.setHoldingRegisters(0,[3,3,3,3])
				time.sleep(1)
예제 #12
0
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):
        """
            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
                        
        """
#         chr = CustomHoldingRegister(ADDRESS_WRITE_START, [16]*100)
#         cdi = CustomHoldingRegister(ADDRESS_WRITE_START, [16]*100)
        self.onShutdown=False;
        self.state_changed = Signal()
        cco = CustomHoldingRegister(ADDRESS_WRITE_START, [16]*100)
        self.store = ModbusSlaveContext(
            di = ModbusSequentialDataBlock(ADDRESS_WRITE_START, [16]*100),
            co = cco,
            hr = ModbusSequentialDataBlock(ADDRESS_WRITE_START, [16]*100), 
            ir = ModbusSequentialDataBlock(ADDRESS_WRITE_START, [16]*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()
        
    def _startServer(self):
        print "Modbus server started"
        self.server.serve_forever()
        
    def stopServer(self):
        """
            Closes the server
        """
        self.onShutdown = True
        self.server.server_close()
        self.server.shutdown()
        
    def waitForCoilOutput(self,address,timeout=2):
        now = time.time()
        while not self.onShutdown:
            values = self.store.getValues(1,address, 1)
            if values[0] is True:
                return True
            else:
                if timeout > 0 and now + timeout > time.time():
                    time.sleep(1/50)
                else:
                    return False
    
    def stateChangeListener(self,address):
        self.post.__stateChangeListener(address)
    
    def __stateChangeListener(self,address):
        old_state = 0;
        while not self.onShutdown:
            value = self.store.getValues(1,address, 1)[0]
            
            if old_state != value:
                old_state = value
                self.state_changed(address,value)
                #print "state has changed"
            time.sleep(1/50) 
    
    def setDigitalInput(self,address,values):
        if not values is list:
            values = [values]
        self.store.setValues(2,address,values)
        
    def triggerInput(self,address,timeout=0.5):
        self.setDigitalInput(address, True)
        self.post.resetInput(address, timeout)
        
    def resetInput(self,address,timeout):
        time.sleep(timeout)
        self.setDigitalInput(address, False)