Esempio n. 1
0
    def __init__(self, host, port, timeout=None, connect=None):
        """Create a TurbosatoriNetworkInterface.

        Parameters:
        -----------
        host : str
            The hostname or IPv4 address of the TBV server to connect to.
        port : int
            The port on the Turbo-Satori server to connect to.
        timeout : int, optional
            The maximal time to wait for a response from the server for each
            request.
        connect : bool, optional
            If True, connect immediately.

        """

        Input.__init__(self)
        Output.__init__(self)

        self._host = host
        self._port = port
        self._is_connected = False
        self._turbosatori_plugin_version = None
        self._tcp = TcpClient(host, port, None, False)
        if timeout is None:
            timeout = defaults.turbosatorinetworkinterface_timeout
        self._timeout = timeout
        if connect is None:
            connect = defaults.turbosatorinetworkinterface_connect
        if connect:
            self.connect()
    def __init__(self, host, port, timeout=None, connect=None):
        """Create a TbvNetworkInterface.

        Parameters:
        -----------
        host : str
            The hostname or IPv4 address of the TBV server to connect to.
        port : int
            The port on the TBV server to connect to.
        timeout : int, optional
            The maximal time to wait for a response from the server for each
            request.
        connect : bool, optional
            If True, connect immediately.

        """

        Input.__init__(self)
        Output.__init__(self)

        self._host = host
        self._port = port
        self._is_connected = False
        self._tbv_plugin_version = None
        self._tcp = TcpClient(host, port, None, False)
        if timeout is None:
            timeout = defaults.tbvnetworkinterface_timeout
        self._timeout = timeout
        if connect is None:
            connect = defaults.tbvnetworkinterface_connect
        if connect:
            self.connect()
class TbvNetworkInterface(Input, Output):
    """A class implementing a network interface to Turbo Brain Voyager.

    See http://www.brainvoyager.com/products/turbobrainvoyager.html
    for more information.

     """

    def __init__(self, host, port, timeout=None, connect=None):
        """Create a TbvNetworkInterface.

        Parameters:
        -----------
        host : str
            The hostname or IPv4 address of the TBV server to connect to.
        port : int
            The port on the TBV server to connect to.
        timeout : int, optional
            The maximal time to wait for a response from the server for each
            request.
        connect : bool, optional
            If True, connect immediately.

        """

        Input.__init__(self)
        Output.__init__(self)

        self._host = host
        self._port = port
        self._is_connected = False
        self._tbv_plugin_version = None
        self._tcp = TcpClient(host, port, None, False)
        if timeout is None:
            timeout = defaults.tbvnetworkinterface_timeout
        self._timeout = timeout
        if connect is None:
            connect = defaults.tbvnetworkinterface_connect
        if connect:
            self.connect()

    _getter_exception_message = "Cannot set {0} if connected!"

    @property
    def host(self):
        """Getter for host."""

        return self._host

    @host.setter
    def host(self, value):
        """Setter for host."""

        if self._is_connected:
            raise AttributeError(TbvNetworkInterface._getter_exception_message.format("host"))
        else:
            self._host = value

    @property
    def port(self):
        """Getter for port."""

        return self._port

    @port.setter
    def port(self, value):
        """Setter for port."""

        if self._is_connected:
            raise AttributeError(TbvNetworkInterface._getter_exception_message.format("port"))
        else:
            self._port = value

    @property
    def is_connected(self):
        """Getter for is_connected."""

        return self._is_connected

    @property
    def tbv_plugin_version(self):
        """Getter for tbv_plugin_version."""

        return self._tbv_plugin_version

    @property
    def timeout(self):
        """Getter for timeout."""

        return self._timeout

    @timeout.setter
    def timeout(self, value):
        """Setter for timeout."""

        if self._is_connected:
            raise AttributeError(TbvNetworkInterface._getter_exception_message.format("timeout"))
        else:
            self._timeout = value

    def connect(self):
        """Connect to the TBV server."""

        if not self._is_connected:
            self._tcp.connect()
            data, rt = self.request_data("Request Socket")
            try:
                self._tbv_plugin_version = (
                    struct.unpack("!i", data[:4])[0],
                    struct.unpack("!i", data[4:8])[0],
                    struct.unpack("!i", data[8:])[0],
                )
            except:
                raise RuntimeError("Requesting a socket failed!")
            self._is_connected = True
            if self._logging:
                expyriment._active_exp._event_file_log(
                    "TbvNetworkInterface,connected,{0}:{1}".format(self._host, self._port)
                )

    def _send(self, message, *args):
        length = len(message)
        arg_length = 0
        if len(args) > 0:
            for arg in args:
                arg_length += len(arg)
        data = struct.pack("!q", length + 5 + arg_length) + "\x00\x00\x00{0}{1}\x00".format(chr(length + 1), message)
        if len(args) > 0:
            for arg in args:
                data += arg
        self._tcp.send(data)

    def _wait(self):
        receive, rt = self._tcp.wait(package_size=8, duration=self.timeout, check_control_keys=False)
        data = None
        if receive is not None:
            length = struct.unpack("!q", receive)[0]
            data, rt = self._tcp.wait(package_size=length, duration=self._timeout, check_control_keys=False)
        if receive is None or data is None:
            return None
        else:
            return data[4:]

    def request_data(self, request, *args):
        """Request data from Turbo Brain Voyager.

        Parameters:
        -----------
        request : str
            The request to be sent to Turbo Brain Voyager.

        Returns:
        --------
        data : str
            The byte string of the received data.
        rt : int
            The time it took to get the data.

        """

        start = get_time()
        self._tcp.clear()
        self._send(request, *args)
        data = self._wait()
        if data is None:
            return None, None
        elif data[0 : len(request)] != request:
            return data, None
        else:
            return data[len(request) + 1 :], int((get_time() - start) * 1000)

    def close(self):
        """Close the connection."""

        self._tcp.close()
        self._is_connected = False

    # Basic Project Queries
    def get_current_time_point(self):
        """Get the current time point.

        Returns:
        --------
        data : int
            The current time point.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetCurrentTimePoint")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!i", data)[0], rt

    def get_expected_nr_of_time_points(self):
        """Get the expected number of time points.

        Returns:
        --------
        data : int
            The expected number of time points.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetExpectedNrOfTimePoints")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!i", data)[0], rt

    def get_dims_of_functional_data(self):
        """Get the dimensions of the functional data.

        Returns:
        --------
        dims : list
            The dimension of the functional volume.
            [x, y, z]
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetDimsOfFunctionalData")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return (
                [struct.unpack("!i", data[:4])[0], struct.unpack("!i", data[4:8])[0], struct.unpack("!i", data[8:])[0]],
                rt,
            )

    def get_project_name(self):
        """Get the project name.

        Returns:
        --------
        name : str
            The project name.
        rt : int
            The time it took to get the data.

        """

        name, rt = self.request_data("tGetProjectName")
        if name is None:
            return None, rt
        elif name[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(name[19:-1]))
        else:
            return str2unicode(name[4:-1]), rt

    def get_watch_folder(self):
        """Get the watch folder.

        Returns:
        --------
        folder : str
            The watch folder.
        rt : int
            The time it took to get the data.

        """

        folder, rt = self.request_data("tGetWatchFolder")
        if folder is None:
            return None, rt
        elif folder[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(folder[19:-1]))
        else:
            return str2unicode(folder[4:-1]), rt

    def get_target_folder(self):
        """Get the target folder.

        Returns:
        --------
        folder : str
            The target folder.
        rt : int
            The time it took to get the data.

        """

        folder, rt = self.request_data("tGetTargetFolder")
        if folder is None:
            return None, rt
        elif folder[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(folder[19:] - 1))
        else:
            return str2unicode(folder[4:-1]), rt

    def get_feedback_folder(self):
        """Get the feedback folder.

        Returns:
        --------
        folder : str
            The feedback folder.
        rt : int
            The time it took to get the data.

        """

        folder, rt = self.request_data("tGetFeedbackFolder")
        if folder is None:
            return None, rt
        elif folder[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(folder[19:-1]))
        else:
            return str2unicode(folder[4:-1]), rt

    # Protocol, DM, GLM Queries
    def get_current_protocol_condition(self):
        """Get the current protocol condition.

        Returns:
        --------
        condition_nr : int
            The current protocol condition.
        rt : int
            The time it took to get the data.

        """

        condition_nr, rt = self.request_data("tGetCurrentProtocolCondition")
        if condition_nr is None:
            return None, rt
        elif condition_nr[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(condition_nr[19:-1]))
        else:
            return struct.unpack("!i", condition_nr)[0], rt

    def get_full_nr_of_predictors(self):
        """Get the full number of predictors.

        Returns:
        --------
        nr_predictors : int
            The number of predictors.
        rt : int
            The time it took to get the data.

        """

        nr_predictors, rt = self.request_data("tGetFullNrOfPredictors")
        if nr_predictors is None:
            return None, rt
        elif nr_predictors[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(nr_predictors[19:-1]))
        else:
            return struct.unpack("!i", nr_predictors)[0], rt

    def get_current_nr_of_predictors(self):
        """Get the current number of predictors.

        Returns:
        --------
        nr_predictors : int
            The number of predictors.
        rt : int
            The time it took to get the data.

        """

        nr_predictors, rt = self.request_data("tGetCurrentNrOfPredictors")
        if nr_predictors is None:
            return None, rt
        elif nr_predictors[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(nr_predictors[19:-1]))
        else:
            return struct.unpack("!i", nr_predictors)[0], rt

    def get_nr_of_confound_predictors(self):
        """Get the number of confound predictors.

        Returns:
        --------
        nr_predictors : int
            The number of predictors.
        rt : int
            The time it took to get the data.

        """

        nr_predictors, rt = self.request_data("tGetNrOfConfoundPredictors")
        if nr_predictors is None:
            return None, rt
        elif nr_predictors[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(nr_predictors[19:-1]))
        else:
            return struct.unpack("!i", nr_predictors)[0], rt

    def get_value_of_design_matrix(self, pred, time_point):
        """Get the value of the design matrix.

        Parameters:
        ----------
        pred : int
            The predictor.
        time_point : int
            The time point.

        Returns:
        --------
        value : float
            The design matrix value.
        rt : int
            The time it took to get the data.

        """

        pred = struct.pack("!i", pred)
        time_point = struct.pack("!i", time_point)
        data, rt = self.request_data("tGetValueOfDesignMatrix", pred, time_point)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!f", data[8:])[0], rt

    def get_nr_of_contrasts(self):
        """Get the number of contrasts.

        Returns:
        --------
        nr_contrasts : int
            The number of contrasts.
        rt : int
            The time it took to get the data.

        """

        nr_contrasts, rt = self.request_data("tGetNrOfContrasts")
        if nr_contrasts is None:
            return None, rt
        elif nr_contrasts[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(nr_contrasts[19:-1]))
        else:
            return struct.unpack("!i", nr_contrasts)[0], rt

    # ROI Queries
    def get_nr_of_rois(self):
        """Get the number of ROIs.

        Returns:
        --------
        nr_rois : int
            The number of ROIs.
        rt : int
            The time it took to get the data.

        """

        nr_rois, rt = self.request_data("tGetNrOfROIs")
        if nr_rois is None:
            return None, rt
        elif nr_rois[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(nr_rois[19:-1]))
        else:
            return struct.unpack("!i", nr_rois)[0], rt

    def get_mean_of_roi(self, roi):
        """Get the mean of a ROI.

        Parameters:
        -----------
        roi : int
            The ROI.

        Returns:
        --------
        mean : float
            The mean of the ROI.
        rt : int
            The time it took to get the data.

        """

        roi = struct.pack("!i", roi)
        data, rt = self.request_data("tGetMeanOfROI", roi)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!f", data[4:])[0], rt

    def get_existing_means_of_roi(self, roi, to_time_point):
        """Get the existing means of a ROI.

        Parameters:
        ----------
        roi : int
            The ROI.
        to_time_point : int
            Get all the means up to this point.

        Returns:
        --------
        means : list
            The means of the ROI.
        rt : int
            The time it took to get the data.

        """

        roi = struct.pack("!i", roi)
        to_time_point = struct.pack("!i", to_time_point)
        data, rt = self.request_data("tGetExistingMeansOfROI", roi, to_time_point)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return ([struct.unpack("!f", data[8 + x * 4 : 8 + x * 4 + 4])[0] for x in range(0, len(data[8:]) / 4)], rt)

    def get_mean_of_roi_at_time_point(self, roi, time_point):
        """Get the mean of a ROI at a time point.

        Parameters:
        ----------
        roi : int
            The ROI.
        time_point : int
            The time point.

        Returns:
        --------
        mean : float
            The mean of the ROI.
        rt : int
            The time it took to get the data.

        """

        roi = struct.pack("!i", roi)
        time_point = struct.pack("!i", time_point)
        data, rt = self.request_data("tGetMeanOfROIAtTimePoint", roi, time_point)

        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!f", data[8:])[0], rt

    def get_nr_of_voxels_of_roi(self, roi):
        """Get the number of voxels of a ROI.

        Parameters:
        -----------
        roi : int
            The ROI.

        Returns:
        --------
        nr_voxels : int
            The number of voxels of the ROI.
        rt : int
            The time it took to get the data.

        """

        roi = struct.pack("!i", roi)
        data, rt = self.request_data("tGetNrOfVoxelsOfROI", roi)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!i", data[4:])[0], rt

    def get_beta_of_roi(self, roi, beta):
        """Get the value of a beta of a ROI.

        Parameters:
        ----------
        roi : int
            The ROI.
        beta : int
            The beta.

        Returns:
        --------
        value : float
            The value of the beta of the ROI.
        rt : int
            The time it took to get the data.

        """

        roi = struct.pack("!i", roi)
        beta = struct.pack("!i", beta)
        data, rt = self.request_data("tGetBetaOfROI", roi, beta)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!f", data[8:])[0], rt

    def get_coord_of_voxel_of_roi(self, roi, voxel):  # TODO: Return as one list?
        """Get the coordinates of a voxel of a ROI.

        Parameters:
        ----------
        roi : int
            The ROI.
        voxel : int
            The voxel.

        Returns:
        --------
        coords : list
            The coordinates of the voxel.
            [x, y, z]
        rt : int
            The time it took to get the data.

        """

        roi = struct.pack("!i", roi)
        voxel = struct.pack("!i", voxel)
        data, rt = self.request_data("tGetCoordsOfVoxelOfROI", roi, voxel)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return (
                [
                    struct.unpack("!i", data[8:12])[0],
                    struct.unpack("!i", data[12:16])[0],
                    struct.unpack("!i", data[16:])[0],
                ],
                rt,
            )

    def get_all_coords_of_voxels_of_roi(self, roi):  # TODO: Put into lists?
        """Get coordinates for all voxels for a ROI.

        Parameters:
        ----------
        roi : int
            The ROI.

        Returns:
        --------
        coords : list
            The coordinates of all voxels of the ROI.
            [[v1_x, v1_y, v1_z], [v2_x, v2_z, v2_y], ..., [vn_x, vn_y, _vn_z]]
        rt : int
            The time it took to get the data.

        """

        roi = struct.pack("!i", roi)
        data, rt = self.request_data("tGetAllCoordsOfVoxelsOfROI", roi)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            _all = [struct.unpack("!i", data[4 + x * 4 : 4 + x * 4 + 4])[0] for x in range(0, len(data[4:]) / 4)]
            return [_all[x : x + 3] for x in range(0, len(_all), 3)], rt

    # Volume Data Access Queries
    def get_value_of_voxel_at_time(self, coords, time_point):
        """Get the value of a voxel at a certain time point.

        Parameters:
        ----------
        coords : list
            The coordinates of the voxel.
            [x, y, z]
        time_point : int
            The time point.

        Returns:
        --------
        value : float
            The voxel value.
        rt : int
            The time it took to get the data.

        """

        x = struct.pack("!i", coords[0])
        y = struct.pack("!i", coords[1])
        z = struct.pack("!i", coords[2])
        time_point = struct.pack("!i", time_point)
        data, rt = self.request_data("tGetValueOfVoxelAtTime", x, y, z, time_point)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!f", data[16:])[0], rt

    def get_value_of_all_voxels_at_time(self, time_point):
        """Get the value of all voxels at a certain time point.

        Parameters:
        ----------
        time_point : int
            The time point.

        Returns:
        --------
        voxels : list
            The data of all voxel values.
            [x1_y1_z1, ..., xn_y1_y1, ..., xn_yn_z1, ..., xn_yn_zn]
            The value of a single voxel can be accessed at:
                z_coord*dim_x*dim_y + y_coord*dim_x + x_coord
        rt : int
            The time it took to get the data.

        """

        time_point = struct.pack("!i", time_point)
        data, rt = self.request_data("tGetValueOfAllVoxelsAtTime", time_point)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return ([struct.unpack("!h", data[4 + x * 2 : 4 + x * 2 + 2])[0] for x in range(0, len(data[4:]) / 2)], rt)

    def get_raw_value_of_all_voxels_at_time(self, time_point):
        """Get the raw value of all voxels at a certain time point.

        Parameters:
        ----------
        time_point : int
            The time point.

        Returns:
        --------
        voxels : list
            The data of all raw voxel values.
            [x1_y1_z1, ..., xn_y1_y1, ..., xn_yn_z1, ..., xn_yn_zn]
            The value of a single voxel can be accessed at:
                z_coord*dim_x*dim_y + y_coord*dim_x + x_coord
        rt : int
            The time it took to get the data.

        """

        time_point = struct.pack("!i", time_point)
        data, rt = self.request_data("tGetRawValueOfAllVoxelsAtTime", time_point)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return ([struct.unpack("!h", data[4 + x * 2 : 4 + x * 2 + 2])[0] for x in range(0, len(data[4:]) / 2)], rt)

    def get_beta_of_voxel(self, beta, coords):
        """Get a specific beta value of a voxel.

        Parameters:
        ----------
        beta : int
            The beta.
        coords : list
            The coordinates of the voxel.
            [x, y, z]

        Returns:
        --------
        value : double
            The beta value.
        rt : int
            The time it took to get the data.

        """

        beta = struct.pack("!i", beta)
        x = struct.pack("!i", coords[0])
        y = struct.pack("!i", coords[1])
        z = struct.pack("!i", coords[2])
        data, rt = self.request_data("tGetBetaOfVoxel", beta, x, y, z)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!d", data[16:])[0], rt

    def get_beta_maps(self):
        """Get the beta maps.

        Returns:
        --------
        beta_maps : list
            The data of all raw voxel values.
                [x1_y1_z_p1, ..., xn_y1_y1_p1, ..., xn_yn_z1_p1, ..., xn_yn_zn_p1, ..., xn_yn_zn_pn]
            A beta value of a single predictor can be accessed at:
                beta_i*dim_xyz + z_coord*dim_xy + y_coord*dim_x + x_coord
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetBetaMaps")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return ([struct.unpack("!d", data[x * 8 : x * 8 + 8])[0] for x in range(0, len(data) / 8)], rt)

    def get_map_value_of_voxel(self, map, coords):
        """Get a specific map value of a voxel.

        Parameters:
        ----------
        map : int
            The map.
        coords : list
            The coordinates of the voxel.
            [x, y, z]

        Returns:
        --------
        value : float
            The map value.
        rt : int
            The time it took to get the data.

        """

        map = struct.pack("!i", map)
        x = struct.pack("!i", coords[0])
        y = struct.pack("!i", coords[1])
        z = struct.pack("!i", coords[2])
        data, rt = self.request_data("tGetMapValueOfVoxel", map, x, y, z)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack("!f", data[16:])[0], rt

    def get_contrast_maps(self):
        """Get the contrast maps.

        Returns:
        --------
        contrast_maps : list
            The data of all contrast maps values.
                [x1_y1_z_c1, ..., xn_y1_y1_c1, ..., xn_yn_z1_c1, ..., xn_yn_zn_cn]
            A t value of a specific contrast map of a voxel with specific
            coordinates can be accessed at:
                map_i*dim_xyz + z_coord*dim_xy + y_coord*dim_x + x_coord
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetContrastMaps")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return ([struct.unpack("!f", data[x * 4 : x * 4 + 4])[0] for x in range(0, len(data) / 4)], rt)

    # SVM Access Functions
    def get_number_of_classes(self):
        """Get the number of classes.

        Returns:
        --------
        nr_classes : int
            The number of classes.
        rt : int
            The time it took to get the data.

        """

        nr_classes, rt = self.request_data("tGetNumberOfClasses")
        if nr_classes is None:
            return None, rt
        elif nr_classes[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(nr_classes[19:-1]))
        else:
            return struct.unpack("!i", nr_classes)[0], rt

    def get_current_classifier_output(self):  # TODO: Needs testing!
        """Get the current classifier output.

        Returns:
        --------
        output : list
            The current classifier output.
            NOTE: Output is 1-based!
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetCurrentClassifierOutput")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return ([struct.unpack("!f", data[x * 4 : x * 4 + 4])[0] for x in range(0, len(data) / 4)], rt)
Esempio n. 4
0
class TurbosatoriNetworkInterface(Input, Output):
    """A class implementing a network interface to Turbo-Satori.

    See http://www.brainvoyager.com/products/turbosatori.html
    for more information.

     """
    def __init__(self, host, port, timeout=None, connect=None):
        """Create a TurbosatoriNetworkInterface.

        Parameters:
        -----------
        host : str
            The hostname or IPv4 address of the TBV server to connect to.
        port : int
            The port on the Turbo-Satori server to connect to.
        timeout : int, optional
            The maximal time to wait for a response from the server for each
            request.
        connect : bool, optional
            If True, connect immediately.

        """

        Input.__init__(self)
        Output.__init__(self)

        self._host = host
        self._port = port
        self._is_connected = False
        self._turbosatori_plugin_version = None
        self._tcp = TcpClient(host, port, None, False)
        if timeout is None:
            timeout = defaults.turbosatorinetworkinterface_timeout
        self._timeout = timeout
        if connect is None:
            connect = defaults.turbosatorinetworkinterface_connect
        if connect:
            self.connect()

    _getter_exception_message = "Cannot set {0} if connected!"

    @property
    def host(self):
        """Getter for host."""

        return self._host

    @host.setter
    def host(self, value):
        """Setter for host."""

        if self._is_connected:
            raise AttributeError(
                TurbosatoriNetworkInterface._getter_exception_message.format(
                    "host"))
        else:
            self._host = value

    @property
    def port(self):
        """Getter for port."""

        return self._port

    @port.setter
    def port(self, value):
        """Setter for port."""

        if self._is_connected:
            raise AttributeError(
                TurbosatoriNetworkInterface._getter_exception_message.format(
                    "port"))
        else:
            self._port = value

    @property
    def is_connected(self):
        """Getter for is_connected."""

        return self._is_connected

    @property
    def turbosatori_plugin_version(self):
        """Getter for turbosatori_plugin_version."""

        return self._turbosatori_plugin_version

    @property
    def timeout(self):
        """Getter for timeout."""

        return self._timeout

    @timeout.setter
    def timeout(self, value):
        """Setter for timeout."""

        if self._is_connected:
            raise AttributeError(
                TurbosatoriNetworkInterface._getter_exception_message.format(
                    "timeout"))
        else:
            self._timeout = value

    def connect(self):
        """Connect to the TBV server."""

        if not self._is_connected:
            self._tcp.connect()
            data, rt = self.request_data("Request Socket")
            try:
                self._turbosatori_plugin_version = (struct.unpack(
                    '!i', data[:4])[0], struct.unpack(
                        '!i', data[4:8])[0], struct.unpack('!i', data[8:])[0])
            except:
                raise RuntimeError("Requesting a socket failed!")
            self._is_connected = True
            if self._logging:
                expyriment._active_exp._event_file_log(
                    "TurbosatoriNetworkInterface,connected,{0}:{1}".format(
                        self._host, self._port))

    def _send(self, message, *args):
        length = len(message)
        arg_length = 0
        if len(args) > 0:
            for arg in args:
                arg_length += len(arg)
        data = struct.pack('!q', length + 5 + arg_length) + \
            "\x00\x00\x00{0}{1}\x00".format(chr(length + 1), message)
        if len(args) > 0:
            for arg in args:
                data += arg
        self._tcp.send(data)

    def _wait(self):
        receive, rt = self._tcp.wait(package_size=8,
                                     duration=self.timeout,
                                     check_control_keys=False)
        data = None
        if receive is not None:
            length = struct.unpack('!q', receive)[0]
            data, rt = self._tcp.wait(package_size=length,
                                      duration=self._timeout,
                                      check_control_keys=False)
        if receive is None or data is None:
            return None
        else:
            return data[4:]

    def request_data(self, request, *args):
        """Request data from Turbo-Satori.

        Parameters:
        -----------
        request : str
            The request to be sent to Turbo-Satori.

        Returns:
        --------
        data : str
            The byte string of the received data.
        rt : int
            The time it took to get the data.

        """

        start = get_time()
        self._tcp.clear()
        self._send(request, *args)
        data = self._wait()
        if data is None:
            return None, None
        elif data[0:len(request)] != request:
            return data, None
        else:
            return data[len(request) + 1:], int((get_time() - start) * 1000)

    def close(self):
        """Close the connection."""

        self._tcp.close()
        self._is_connected = False

    # Basic Project Queries
    def get_current_time_point(self):
        """Get the current time point.

        Returns:
        --------
        time_point : int
            The current time point.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetCurrentTimePoint")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!i', data)[0], rt

    def get_nr_of_channels(self):
        """Get the number of channels.

        Returns:
        --------
        nr_channels : int
            The number of channels.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetNrOfChannels")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!i', data)[0], rt

    def get_values_feedback_folder(self):
        """Get the feedback folder for the values.

        Returns:
        --------
        folder : str
            The feedback folder.
        rt : int
            The time it took to get the data.

        """

        folder, rt = self.request_data("tGetValuesFeedbackFolder")
        if folder is None:
            return None, rt
        elif folder[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(folder[19:-1]))
        else:
            return str2unicode(folder[4:-1]), rt

    def get_images_feedback_folder(self):
        """Get the feedback folder for the images.

        Returns:
        --------
        folder : str
            The feedback folder.
        rt : int
            The time it took to get the data.

        """

        folder, rt = self.request_data("tGetImagesFeedbackFolder")
        if folder is None:
            return None, rt
        elif folder[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(folder[19:-1]))
        else:
            return str2unicode(folder[4:-1]), rt

    def get_nr_of_selected_channels(self):
        """Get the number of selected channels.

        Returns:
        --------
        nr_selected_channels : int
            The number of selected channels.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetNrOfSelectedChannels")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!i', data)[0], rt

    def get_selected_channels(self):
        """Get the selected channels.

        Returns:
        --------
        channels : list
            The selected channels.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetSelectedChannels")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return ([
                struct.unpack('!i', data[x * 4:x * 4 + 4])[0]
                for x in range(0,
                               len(data) / 4)
            ], rt)

    def get_raw_data_scale_factor(self):
        """Get the scale factor set in the GUI for raw data.

        Returns:
        --------
        scale_factor : float
            The scale factor.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetRawDataScaleFactor")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data)[0], rt

    def get_raw_data_wl1(self, channel, frame):
        """Get raw data for wavelength 1.

        Parameters:
        ----------
        channel : int
            The channel.
        frame : int
            The time point.

        Returns:
        --------
        data : float
            The raw data.
        rt : int
            The time it took to get the data.

        """

        channel = struct.pack('!i', channel)
        frame = struct.pack('!i', frame)
        data, rt = self.request_data("tGetRawDataWL1", channel, frame)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data[8:])[0], rt

    def get_raw_data_wl2(self, channel, frame):
        """Get raw data for wavelength 2.

        Parameters:
        ----------
        channel : int
            The channel.
        frame : int
            The time point.

        Returns:
        --------
        data : float
            The raw data.
        rt : int
            The time it took to get the data.

        """

        channel = struct.pack('!i', channel)
        frame = struct.pack('!i', frame)
        data, rt = self.request_data("tGetRawDataWL2", channel, frame)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data[8:])[0], rt

    def is_data_oxy_deoxy_converted(self):
        """Check if oxy/deoxy values are requested and have been calculated.

        Returns:
        --------
        is_converted : bool
            True if oxy/deoxy converted, False otherwise
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tIsDataOxyDeoxyConverted")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return bool(struct.unpack('!i', data)[0]), rt

    def get_oxy_data_scale_factor(self):
        """Get the scale factor set in the GUI for oxy/deoxy data.

        Returns:
        --------
        scale_factor : float
            The scale factor.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetOxyDataScaleFactor")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data)[0], rt

    def get_data_oxy(self, channel, frame):
        """Get oxy data.

        Parameters:
        ----------
        channel : int
            The channel.
        frame : int
            The time point.

        Returns:
        --------
        data : float
            The raw data.
        rt : int
            The time it took to get the data.

        """

        channel = struct.pack('!i', channel)
        frame = struct.pack('!i', frame)
        data, rt = self.request_data("tGetDataOxy", channel, frame)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data[8:])[0], rt

    def get_data_deoxy(self, channel, frame):
        """Get deoxy data.

        Parameters:
        ----------
        channel : int
            The channel.
        frame : int
            The time point.

        Returns:
        --------
        data : float
            The raw data.
        rt : int
            The time it took to get the data.

        """

        channel = struct.pack('!i', channel)
        frame = struct.pack('!i', frame)
        data, rt = self.request_data("tGetDataDeoxy", channel, frame)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data[8:])[0], rt
class TurbosatoriNetworkInterface(Input, Output):
    """A class implementing a network interface to Turbo-Satori.

    See http://www.brainvoyager.com/products/turbosatori.html
    for more information.

     """

    def __init__(self, host, port, timeout=None, connect=None):
        """Create a TurbosatoriNetworkInterface.

        Parameters:
        -----------
        host : str
            The hostname or IPv4 address of the TBV server to connect to.
        port : int
            The port on the Turbo-Satori server to connect to.
        timeout : int, optional
            The maximal time to wait for a response from the server for each
            request.
        connect : bool, optional
            If True, connect immediately.

        """

        Input.__init__(self)
        Output.__init__(self)

        self._host = host
        self._port = port
        self._is_connected = False
        self._turbosatori_plugin_version = None
        self._tcp = TcpClient(host, port, None, False)
        if timeout is None:
            timeout = defaults.turbosatorinetworkinterface_timeout
        self._timeout = timeout
        if connect is None:
            connect = defaults.turbosatorinetworkinterface_connect
        if connect:
            self.connect()

    _getter_exception_message = "Cannot set {0} if connected!"

    @property
    def host(self):
        """Getter for host."""

        return self._host

    @host.setter
    def host(self, value):
        """Setter for host."""

        if self._is_connected:
            raise AttributeError(
                TurbosatoriNetworkInterface._getter_exception_message.format("host"))
        else:
            self._host = value

    @property
    def port(self):
        """Getter for port."""

        return self._port

    @port.setter
    def port(self, value):
        """Setter for port."""

        if self._is_connected:
            raise AttributeError(
                TurbosatoriNetworkInterface._getter_exception_message.format("port"))
        else:
            self._port = value

    @property
    def is_connected(self):
        """Getter for is_connected."""

        return self._is_connected

    @property
    def turbosatori_plugin_version(self):
        """Getter for turbosatori_plugin_version."""

        return self._turbosatori_plugin_version

    @property
    def timeout(self):
        """Getter for timeout."""

        return self._timeout

    @timeout.setter
    def timeout(self, value):
        """Setter for timeout."""

        if self._is_connected:
            raise AttributeError(
                TurbosatoriNetworkInterface._getter_exception_message.format(
                    "timeout"))
        else:
            self._timeout = value

    def connect(self):
        """Connect to the TBV server."""

        if not self._is_connected:
            self._tcp.connect()
            data, rt = self.request_data("Request Socket")
            try:
                self._turbosatori_plugin_version = (
                    struct.unpack('!i', data[:4])[0],
                    struct.unpack('!i', data[4:8])[0],
                    struct.unpack('!i', data[8:])[0])
            except:
                raise RuntimeError("Requesting a socket failed!")
            self._is_connected = True
            if self._logging:
                expyriment._active_exp._event_file_log(
                    "TurbosatoriNetworkInterface,connected,{0}:{1}".format(
                        self._host, self._port))

    def _send(self, message, *args):
        length = len(message)
        arg_length = 0
        if len(args) > 0:
            for arg in args:
                arg_length += len(arg)
        data = struct.pack('!q', length + 5 + arg_length) + \
            "\x00\x00\x00{0}{1}\x00".format(chr(length + 1), message)
        if len(args) > 0:
            for arg in args:
                data += arg
        self._tcp.send(data)

    def _wait(self):
        receive, rt = self._tcp.wait(package_size=8, duration=self.timeout,
                                     check_control_keys=False)
        data = None
        if receive is not None:
            length = struct.unpack('!q', receive)[0]
            data, rt = self._tcp.wait(package_size=length, duration=self._timeout,
                                      check_control_keys=False)
        if receive is None or data is None:
            return None
        else:
            return data[4:]

    def request_data(self, request, *args):
        """Request data from Turbo-Satori.

        Parameters:
        -----------
        request : str
            The request to be sent to Turbo-Satori.

        Returns:
        --------
        data : str
            The byte string of the received data.
        rt : int
            The time it took to get the data.

        """

        start = get_time()
        self._tcp.clear()
        self._send(request, *args)
        data = self._wait()
        if data is None:
            return None, None
        elif data[0:len(request)] != request:
            return data, None
        else:
            return data[len(request) + 1:], int((get_time() - start) * 1000)

    def close(self):
        """Close the connection."""

        self._tcp.close()
        self._is_connected = False

    # Basic Project Queries
    def get_current_time_point(self):
        """Get the current time point.

        Returns:
        --------
        time_point : int
            The current time point.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetCurrentTimePoint")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!i', data)[0], rt

    def get_nr_of_channels(self):
        """Get the number of channels.

        Returns:
        --------
        nr_channels : int
            The number of channels.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetNrOfChannels")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!i', data)[0], rt

    def get_values_feedback_folder(self):
        """Get the feedback folder for the values.

        Returns:
        --------
        folder : str
            The feedback folder.
        rt : int
            The time it took to get the data.

        """

        folder, rt = self.request_data("tGetValuesFeedbackFolder")
        if folder is None:
            return None, rt
        elif folder[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(folder[19:-1]))
        else:
            return str2unicode(folder[4:-1]), rt

    def get_images_feedback_folder(self):
        """Get the feedback folder for the images.

        Returns:
        --------
        folder : str
            The feedback folder.
        rt : int
            The time it took to get the data.

        """

        folder, rt = self.request_data("tGetImagesFeedbackFolder")
        if folder is None:
            return None, rt
        elif folder[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(folder[19:-1]))
        else:
            return str2unicode(folder[4:-1]), rt

    def get_nr_of_selected_channels(self):
        """Get the number of selected channels.

        Returns:
        --------
        nr_selected_channels : int
            The number of selected channels.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetNrOfSelectedChannels")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!i', data)[0], rt

    def get_selected_channels(self):
        """Get the selected channels.

        Returns:
        --------
        channels : list
            The selected channels.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetSelectedChannels")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return ([struct.unpack('!i', data[x * 4:x * 4 + 4])[0]
                     for x in range(0, len(data) / 4)], rt)

    def get_raw_data_scale_factor(self):
        """Get the scale factor set in the GUI for raw data.

        Returns:
        --------
        scale_factor : float
            The scale factor.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetRawDataScaleFactor")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data)[0], rt

    def get_raw_data_wl1(self, channel, frame):
        """Get raw data for wavelength 1.

        Parameters:
        ----------
        channel : int
            The channel.
        frame : int
            The time point.

        Returns:
        --------
        data : float
            The raw data.
        rt : int
            The time it took to get the data.

        """

        channel = struct.pack('!i', channel)
        frame = struct.pack('!i', frame)
        data, rt = self.request_data("tGetRawDataWL1", channel, frame)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data[8:])[0], rt

    def get_raw_data_wl2(self, channel, frame):
        """Get raw data for wavelength 2.

        Parameters:
        ----------
        channel : int
            The channel.
        frame : int
            The time point.

        Returns:
        --------
        data : float
            The raw data.
        rt : int
            The time it took to get the data.

        """

        channel = struct.pack('!i', channel)
        frame = struct.pack('!i', frame)
        data, rt = self.request_data("tGetRawDataWL2", channel, frame)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data[8:])[0], rt

    def is_data_oxy_deoxy_converted(self):
        """Check if oxy/deoxy values are requested and have been calculated.

        Returns:
        --------
        is_converted : bool
            True if oxy/deoxy converted, False otherwise
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tIsDataOxyDeoxyConverted")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return bool(struct.unpack('!i', data)[0]), rt

    def get_oxy_data_scale_factor(self):
        """Get the scale factor set in the GUI for oxy/deoxy data.

        Returns:
        --------
        scale_factor : float
            The scale factor.
        rt : int
            The time it took to get the data.

        """

        data, rt = self.request_data("tGetOxyDataScaleFactor")
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data)[0], rt

    def get_data_oxy(self, channel, frame):
        """Get oxy data.

        Parameters:
        ----------
        channel : int
            The channel.
        frame : int
            The time point.

        Returns:
        --------
        data : float
            The raw data.
        rt : int
            The time it took to get the data.

        """

        channel = struct.pack('!i', channel)
        frame = struct.pack('!i', frame)
        data, rt = self.request_data("tGetDataOxy", channel, frame)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data[8:])[0], rt

    def get_data_deoxy(self, channel, frame):
        """Get deoxy data.

        Parameters:
        ----------
        channel : int
            The channel.
        frame : int
            The time point.

        Returns:
        --------
        data : float
            The raw data.
        rt : int
            The time it took to get the data.

        """

        channel = struct.pack('!i', channel)
        frame = struct.pack('!i', frame)
        data, rt = self.request_data("tGetDataDeoxy", channel, frame)
        if data is None:
            return None, rt
        elif data[:14] == "Wrong request!":
            raise Exception("Wrong request!: '{0}'".format(data[19:-1]))
        else:
            return struct.unpack('!f', data[8:])[0], rt