def adsSyncReadReqEx2(<EOL>port, address, index_group, index_offset, data_type, return_ctypes=False<EOL>):<EOL>
sync_read_request = _adsDLL.AdsSyncReadReqEx2<EOL>ams_address_pointer = ctypes.pointer(address.amsAddrStruct())<EOL>index_group_c = ctypes.c_ulong(index_group)<EOL>index_offset_c = ctypes.c_ulong(index_offset)<EOL>if data_type == PLCTYPE_STRING:<EOL><INDENT>data = (STRING_BUFFER * PLCTYPE_STRING)()<EOL><DEDENT>else:<EOL><INDENT>data = data_type()<EOL><DEDENT>data_pointer = ctypes.pointer(data)<EOL>data_length = ctypes.c_ulong(ctypes.sizeof(data))<EOL>bytes_read = ctypes.c_ulong()<EOL>bytes_read_pointer = ctypes.pointer(bytes_read)<EOL>error_code = sync_read_request(<EOL>port,<EOL>ams_address_pointer,<EOL>index_group_c,<EOL>index_offset_c,<EOL>data_length,<EOL>data_pointer,<EOL>bytes_read_pointer,<EOL>)<EOL>if error_code:<EOL><INDENT>raise ADSError(error_code)<EOL><DEDENT>if data_type != PLCTYPE_STRING and bytes_read.value != data_length.value:<EOL><INDENT>raise RuntimeError(<EOL>"<STR_LIT>".format(<EOL>data_length.value, bytes_read.value<EOL>)<EOL>)<EOL><DEDENT>if return_ctypes:<EOL><INDENT>return data<EOL><DEDENT>if data_type == PLCTYPE_STRING:<EOL><INDENT>return data.value.decode("<STR_LIT:utf-8>")<EOL><DEDENT>if type(data_type).__name__ == "<STR_LIT>":<EOL><INDENT>return [i for i in data]<EOL><DEDENT>if hasattr(data, "<STR_LIT:value>"):<EOL><INDENT>return data.value<EOL><DEDENT>return data<EOL>
Read data synchronous from an ADS-device.

    :param int port: local AMS port as returned by adsPortOpenEx()
    :param pyads.structs.AmsAddr address: local or remote AmsAddr
    :param int index_group: PLC storage area, according to the INDEXGROUP
        constants
    :param int index_offset: PLC storage address
    :param Type data_type: type of the data given to the PLC, according to
        PLCTYPE constants
    :param bool return_ctypes: return ctypes instead of python types if True
        (default: False)
    :rtype: data_type
    :return: value: **value**