def set_rotational_speed(self, address, data):
     self.log.info("Setting frequency")
     self.log.info("Data = {}".format(data))
     freq = raw_bytes_to_int(data)
     self.log.info("Setting frequency to {}".format(freq))
     self._device.set_frequency(freq)
     return general_status_response_packet(address, self.device, 0x60)
 def set_gate_width(self, address, data):
     self.log.info("Setting gate width")
     self.log.info("Data = {}".format(data))
     width = raw_bytes_to_int(data)
     self.log.info("Setting gate width to {}".format(width))
     self._device.set_phase_repeatability(width / 10.)
     return general_status_response_packet(address, self.device, 0x8E)
 def set_nominal_phase(self, address, data):
     self.log.info("Setting phase")
     self.log.info("Data = {}".format(data))
     nominal_phase = raw_bytes_to_int(data) / 1000.
     self.log.info("Setting nominal phase to {}".format(nominal_phase))
     self._device.set_nominal_phase(nominal_phase)
     return general_status_response_packet(address, self.device, 0x90)
 def set_rotator_angle(self, address, data):
     self.log.info("Setting rotator angle")
     self.log.info("Data = {}".format(data))
     angle_times_ten = raw_bytes_to_int(data)
     self.log.info("Setting rotator angle to {}".format(angle_times_ten /
                                                        10.))
     self._device.set_rotator_angle(angle_times_ten / 10.)
     return general_status_response_packet(address, self.device, 0x82)
Exemple #5
0
def convert_to_ints(command, start, end):
    """
    Converts an incoming set of bytes into a list of ints. Assuming there are BYTES_IN_INT bytes in an int.

    Args:
        command: The incoming bytes.
        start: The index at which to start
        end: The index at which to end

    Returns: A list of integers converted from the command.
    """
    return [raw_bytes_to_int(command[x:x + BYTES_IN_INT]) for x in range(start, end, BYTES_IN_INT)]
Exemple #6
0
    def any_command(self, command):
        response = ''

        if not self.device.connected:
            # Used rather than conditional_reply decorator to improve error message
            raise ValueError("Device simulating disconnection")

        while command:
            # Length doesn't include itself
            length = raw_bytes_to_int(command[:BYTES_IN_INT]) + BYTES_IN_INT

            response += self.handle_single_command(command[:length])

            command = command[length:]

        return response
Exemple #7
0
    def handle_single_command(self, command):
        length = raw_bytes_to_int(command[:BYTES_IN_INT])

        opcode, address, index, correlation_num = convert_to_ints(command, BYTES_IN_INT, HEADER_LENGTH + 1)

        if length > HEADER_LENGTH:
            # This is probably a set command
            data = convert_to_ints(command, HEADER_LENGTH + BYTES_IN_INT, len(command))

        # Length should describe command minus itself
        if len(command) - BYTES_IN_INT != length:
            raise ValueError("Told I would receive {} bytes but received {}".format(length, len(command) - BYTES_IN_INT))

        if opcode == UC_GET:
            return self.get(address, index, correlation_num)
        elif opcode == UC_SET:
            return self.set(address, index, correlation_num, data)
        else:
            raise ValueError("Unrecognised opcode {}".format(opcode))
    def any_command(self, command):
        """
        Handles all command sent to this emulator. It checks the validity of the command, and raises an error if it
        finds something invalid. If the command is valid, then it returns a string representing the response to the
        command.
        
        Args:
            command (bytes): A string where every character represents a byte from the received FINS command frame.

        Returns:
            bytes: a string where each character represents a byte from the FINS response frame.
        """
        self._log_fins_frame(command, False)

        self._check_fins_frame_header_validity(command[:10])

        # We extract information necessary for building the FINS response header
        self.device.network_address = command[3]
        self.device.unit_address = command[5]

        client_network_address = command[6]
        client_node_address = command[7]
        client_unit_address = command[8]

        service_id = command[9]

        if command[10] != 0x01 or command[11] != 0x01:
            raise ValueError("The command code should be 0x0101, for memory area read command!")

        if command[12] != 0x82:
            raise ValueError("The emulator only supports reading words from the DM area, for which the code is 82.")

        # the address of the starting word from where reading is done. Addresses are stored in two bytes.
        memory_start_address = raw_bytes_to_int(command[13:15], low_bytes_first=False)

        # The FINS PLC supports reading either a certain number of words, or can also read individual bits in a word.
        # The helium recovery memory map implies that that PLC uses word designated reading. When bit designated
        # reading is not used, the 16th byte of the command is 0x00.
        if command[15] != 0x00:
            raise ValueError("The emulator only supports word designated memory reading. The bit address must "
                             "be 0x00.")

        number_of_words_to_read = raw_bytes_to_int(command[16:18], low_bytes_first=False)

        # The helium recovery PLC memory map has addresses that store types that take up either one word (16 bits) or
        # two. Most take up one word, so if the number of words to read is two we check that the client wants to read
        # from a memory location from where a 32 bit value starts.
        if number_of_words_to_read == 2 and memory_start_address not in self.device.int32_memory.keys():
            raise ValueError("The memory start address {} corresponds to a single word in the memory map, "
                             "not two.".format(memory_start_address))
        # The PLC also stores 32 bit floating point numbers, but the asyn device support makes the IOC ask for 4 bytes
        # instead of two.
        elif number_of_words_to_read == 4 and memory_start_address not in self.device.float_memory.keys():
            raise ValueError("The only commands that should ask for 4 words are for reading memory locations that "
                             "store real numbers, which {} is not.".format(memory_start_address))
        elif number_of_words_to_read > 4 or number_of_words_to_read == 3:
            raise ValueError("The memory map only specifies data types for which commands should ask for one, two or "
                             "four words at most .")

        self._log_command_contents(client_network_address, client_node_address, client_unit_address, service_id,
                                   memory_start_address, number_of_words_to_read)

        reply = dm_memory_area_read_response_fins_frame(self.device, client_network_address,
                                                        client_node_address, client_unit_address, service_id,
                                                        memory_start_address, number_of_words_to_read)

        self._log_fins_frame(reply, True)

        return reply