Beispiel #1
0
/**
 * osp_device_get_fw_version:
 * @device: a #GUsbDevice instance
 * @error: A #GError or %NULL
 *
 * Opens the device and claims the interface
 *
 * Return value: The firmware version, or %NULL for error
 *
 * Since: 1.2.11
 **/
gchar *
osp_device_get_fw_version (GUsbDevice *device, GError **error)
{
	gsize data_len;
	g_autofree guint8 *data = NULL;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* query hardware */
	if (!osp_device_query (device, OSP_CMD_GET_FIRMWARE_VERSION,
			       NULL, 0, &data, &data_len, error))
		return NULL;

	/* check values */
	if (data_len != 2) {
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_INTERNAL,
			     "Expected %i bytes, got %" G_GSIZE_FORMAT,
			     2, data_len);
		return NULL;
	}

	/* format value */
	return g_strdup_printf ("%u.%u", data[1], data[0]);
}
Beispiel #2
0
/**
 * osp_device_get_nonlinearity_cal_for_idx:
 *
 * Since: 1.3.1
 **/
static gboolean
osp_device_get_nonlinearity_cal_for_idx (GUsbDevice *device,
					 guint idx,
					 gfloat *cal,
					 GError **error)
{
	gsize data_len;
	guint8 idx_buf[1] = { idx };
	g_autofree guint8 *data = NULL;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	/* query hardware */
	if (!osp_device_query (device, OSP_CMD_GET_NONLINEARITY_COEFFICIENT,
			       idx_buf, 1, &data, &data_len, error))
		return FALSE;

	/* check values */
	if (data_len != 4) {
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_INTERNAL,
			     "Expected %i bytes, got %" G_GSIZE_FORMAT,
			     4, data_len);
		return FALSE;
	}

	/* convert to floating point */
	if (cal != NULL)
		*cal = *((gfloat *) data);

	/* format value */
	return TRUE;
}
Beispiel #3
0
/**
 * dtp94_device_get_serial:
 *
 * Since: 0.1.29
 **/
gchar *
dtp94_device_get_serial (GUsbDevice *device, GError **error)
{
	gboolean ret;
	gchar *tmp;
	gsize reply_read;
	guint8 buffer[128];

	g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	ret = dtp94_device_send_data (device,
				      (const guint8 *) "SV\r", 3,
				      buffer, sizeof (buffer),
				      &reply_read,
				      error);
	if (!ret)
		return NULL;
	tmp = g_strstr_len ((const gchar *) buffer, reply_read, "\r");
	if (tmp == NULL || memcmp (tmp + 1, "<00>", 4) != 0) {
		buffer[reply_read] = '\0';
		g_set_error (error,
			     DTP94_DEVICE_ERROR,
			     DTP94_DEVICE_ERROR_INTERNAL,
			     "unexpected response from device: %s",
			     (const gchar *) buffer);
		return NULL;
	}
	tmp[0] = '\0';
	return g_strdup (tmp);
}
Beispiel #4
0
/**
 * osp_device_get_serial:
 * @device: a #GUsbDevice instance
 * @error: A #GError or %NULL
 *
 * Gets the device serial number.
 *
 * Return value: A string, or %NULL for failure
 *
 * Since: 1.2.11
 **/
gchar *
osp_device_get_serial (GUsbDevice *device, GError **error)
{
	gsize data_len;
	g_autofree guint8 *data = NULL;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* query hardware */
	if (!osp_device_query (device, OSP_CMD_GET_SERIAL_NUMBER,
			       NULL, 0, &data, &data_len, error))
		return NULL;

	/* check values */
	if (data_len == 0) {
		g_set_error_literal (error,
				     OSP_DEVICE_ERROR,
				     OSP_DEVICE_ERROR_INTERNAL,
				     "Expected serial number, got nothing");
		return NULL;
	}

	/* format value */
	return g_strndup ((const gchar *) data, data_len);
}
Beispiel #5
0
/**
 * dtp94_device_send_cmd:
 *
 * Since: 0.1.29
 **/
gboolean
dtp94_device_send_cmd (GUsbDevice *device,
		       const gchar *command,
		       GError **error)
{
	gboolean ret = FALSE;
	GError *error_local = NULL;
	guint error_cnt = 0;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
	g_return_val_if_fail (command != NULL, FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	/* repeat until the device is ready */
	for (error_cnt = 0; ret != TRUE; error_cnt++) {
		ret = dtp94_device_send_cmd_issue (device, command, &error_local);
		if (!ret) {
			if (error_cnt < DTP94_MAX_READ_RETRIES &&
			    g_error_matches (error_local,
					     DTP94_DEVICE_ERROR,
					     DTP94_DEVICE_ERROR_NO_DATA)) {
				g_debug ("ignoring %s", error_local->message);
				g_clear_error (&error_local);
				continue;
			}
			g_propagate_error (error, error_local);
			break;
		}
	};
	return ret;
}
Beispiel #6
0
/**
 * osp_device_get_nonlinearity_cal:
 * @device: a #GUsbDevice instance
 * @length: the size of the returned array
 * @error: A #GError or %NULL
 *
 * Gets the nonlinearity values for the sensor.
 *
 * Return value: An array of coefficients
 *
 * Since: 1.3.1
 **/
gdouble *
osp_device_get_nonlinearity_cal (GUsbDevice *device, guint *length, GError **error)
{
	gboolean ret;
	gdouble *coefs = NULL;
	gfloat cx;
	gsize data_len;
	guint i;
	g_autofree guint8 *data = NULL;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* query hardware */
	if (!osp_device_query (device, OSP_CMD_GET_NONLINEARITY_COEFFICIENT_COUNT,
			       NULL, 0, &data, &data_len, error))
		return NULL;

	/* check values */
	if (data_len != 1) {
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_INTERNAL,
			     "Expected 1 bytes, got %" G_GSIZE_FORMAT,
			     data_len);
		return NULL;
	}

	/* check sanity */
	if (data[0] != 8) {
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_INTERNAL,
			     "Expected 8 coefs, got %i", data[0]);
		return NULL;
	}

	/* get the coefs */
	coefs = g_new0 (gdouble, data[0]);
	for (i = 0; i < data[0]; i++) {
		ret = osp_device_get_nonlinearity_cal_for_idx (device,
							       i,
							       &cx,
							       error);
		if (!ret)
			return NULL;
		coefs[i] = cx;
	}

	/* this is optional */
	if (length != NULL)
		*length = data[0];

	/* success */
	return coefs;
}
Beispiel #7
0
/**
 * dtp94_device_send_data:
 *
 * Since: 0.1.29
 **/
gboolean
dtp94_device_send_data (GUsbDevice *device,
			const guint8 *request,
			gsize request_len,
			guint8 *reply,
			gsize reply_len,
			gsize *reply_read,
			GError **error)
{
	gboolean ret;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
	g_return_val_if_fail (request != NULL, FALSE);
	g_return_val_if_fail (request_len != 0, FALSE);
	g_return_val_if_fail (reply != NULL, FALSE);
	g_return_val_if_fail (reply_len != 0, FALSE);
	g_return_val_if_fail (reply_read != NULL, FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	/* request data from device */
	cd_buffer_debug (CD_BUFFER_KIND_REQUEST,
			 request, request_len);
	ret = g_usb_device_interrupt_transfer (device,
					       0x2,
					       (guint8 *) request,
					       request_len,
					       NULL,
					       DTP94_CONTROL_MESSAGE_TIMEOUT,
					       NULL,
					       error);
	if (!ret)
		return FALSE;

	/* get sync response */
	ret = g_usb_device_interrupt_transfer (device,
					       0x81,
					       (guint8 *) reply,
					       reply_len,
					       reply_read,
					       DTP94_CONTROL_MESSAGE_TIMEOUT,
					       NULL,
					       error);
	if (!ret)
		return FALSE;
	if (reply_read == 0) {
		g_set_error_literal (error,
				     DTP94_DEVICE_ERROR,
				     DTP94_DEVICE_ERROR_INTERNAL,
				     "failed to get data from device");
		return FALSE;
	}
	cd_buffer_debug (CD_BUFFER_KIND_RESPONSE,
			 reply, *reply_read);
	return TRUE;
}
Beispiel #8
0
/**
 * osp_device_take_spectrum_full:
 * @device: a #GUsbDevice instance
 * @sample_duration: the sample duration in µs
 * @error: A #GError or %NULL
 *
 * Returns a spectrum for a set sample duration.
 *
 * Return value: A #CdSpectrum, or %NULL for error
 *
 * Since: 1.3.1
 **/
CdSpectrum *
osp_device_take_spectrum_full (GUsbDevice *device,
			       guint64 sample_duration,
			       GError **error)
{
	CdSpectrum *sp;
	gdouble start;
	guint8 bin_factor = 0;
	g_autofree gdouble *cx = NULL;
	g_autoptr(CdSpectrum) sp_dc = NULL;
	g_autoptr(CdSpectrum) sp_raw = NULL;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* return every pixel */
	if (!osp_device_send_command (device, OSP_CMD_SET_PIXEL_BINNING_FACTOR,
				      &bin_factor, 1, error))
		return NULL;

	/* get spectrum */
	sp_raw = osp_device_take_spectrum_internal (device, sample_duration, error);
	if (sp_raw == NULL)
		return NULL;
	cd_spectrum_set_id (sp_raw, "raw");

	/* remove any DC offset from the sensor by doing a 10us reading --
	 * ideally this would be 0us, but we have to use what we have */
	sp_dc = osp_device_take_spectrum_internal (device, 10, error);
	if (sp_dc == NULL)
		return NULL;
	cd_spectrum_set_id (sp_dc, "dc");

	/* get coefficients */
	cx = osp_device_get_wavelength_cal (device, NULL, error);
	if (cx == NULL)
		return NULL;

	/* get start */
	start = osp_device_get_wavelength_start (device, error);
	if (start < 0)
		return NULL;

	/* return the reading without a DC component */
	sp = cd_spectrum_subtract (sp_raw, sp_dc, 5);
	cd_spectrum_set_start (sp, start);
	cd_spectrum_set_norm (sp, 4);
	cd_spectrum_set_wavelength_cal (sp, cx[0], cx[1], cx[2]);
	return sp;
}
Beispiel #9
0
static gboolean
dtp94_device_send_cmd_issue (GUsbDevice *device,
			     const gchar *command,
			     GError **error)
{
	gboolean ret;
	gsize reply_read;
	guint8 buffer[128];
	guint8 rc;
	guint command_len;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	/* sent command raw */
	command_len = strlen (command);
	ret = dtp94_device_send_data (device,
				      (const guint8 *) command,
				      command_len,
				      buffer,
				      sizeof (buffer),
				      &reply_read,
				      error);
	if (!ret)
		return FALSE;

	/* device busy */
	rc = dtp94_rc_parse (buffer, reply_read);
	if (rc == DTP94_RC_BAD_COMMAND) {
		g_set_error_literal (error,
				     DTP94_DEVICE_ERROR,
				     DTP94_DEVICE_ERROR_NO_DATA,
				     "device busy");
		return FALSE;
	}

	/* no success */
	if (rc != DTP94_RC_OK) {
		buffer[reply_read] = '\0';
		g_set_error (error,
			     DTP94_DEVICE_ERROR,
			     DTP94_DEVICE_ERROR_INTERNAL,
			     "unexpected response from device: %s [%s]",
			     (const gchar *) buffer,
			     dtp94_rc_to_string (rc));
		return FALSE;
	}
	return TRUE;
}
Beispiel #10
0
/**
 * osp_device_open:
 * @device: a #GUsbDevice instance
 * @error: A #GError or %NULL
 *
 * Opens the device and claims the interface
 *
 * Return value: %TRUE for success
 *
 * Since: 1.2.11
 **/
gboolean
osp_device_open (GUsbDevice *device, GError **error)
{
	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	if (!g_usb_device_open (device, error))
		return FALSE;
	if (!g_usb_device_claim_interface (device, 0x00, 0, error)) {
		g_prefix_error (error, "Failed to claim interface: ");
		return FALSE;
	}

	return TRUE;
}
Beispiel #11
0
/**
 * dtp94_device_setup:
 *
 * Since: 0.1.29
 **/
gboolean
dtp94_device_setup (GUsbDevice *device, GError **error)
{
	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

	/* reset device */
	if (!dtp94_device_send_cmd (device, "0PR\r", error))
		return FALSE;

	/* reset device again */
	if (!dtp94_device_send_cmd (device, "0PR\r", error))
		return FALSE;

	/* set color data separator to '\t' */
	if (!dtp94_device_send_cmd (device, "0207CF\r", error))
		return FALSE;

	/* set delimeter to CR */
	if (!dtp94_device_send_cmd (device, "0008CF\r", error))
		return FALSE;

	/* set extra digit resolution */
	if (!dtp94_device_send_cmd (device, "010ACF\r", error))
		return FALSE;

	/* no black point subtraction */
	if (!dtp94_device_send_cmd (device, "0019CF\r", error))
		return FALSE;

	/* set to factory calibration */
	if (!dtp94_device_send_cmd (device, "EFC\r", error))
		return FALSE;

	/* compensate for offset drift */
	if (!dtp94_device_send_cmd (device, "0117CF\r", error))
		return FALSE;

	return TRUE;
}
Beispiel #12
0
/**
 * osp_device_get_irradiance_cal:
 * @device: a #GUsbDevice instance
 * @length: the size of the returned array
 * @error: A #GError or %NULL
 *
 * Gets the irradiance spectrum for the sensor.
 *
 * Return value: An array of coefficients
 *
 * Since: 1.3.1
 **/
gdouble *
osp_device_get_irradiance_cal (GUsbDevice *device, guint *length, GError **error)
{
	gdouble *coefs = NULL;
	gsize data_len;
	guint i;
	g_autofree guint8 *data = NULL;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* query hardware */
	if (!osp_device_query (device, OSP_CMD_GET_IRRADIANCE_CALIBRATION,
			       NULL, 0, &data, &data_len, error))
		return NULL;

	/* check values */
	if (data_len != 4096 * 4) {
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_INTERNAL,
			     "Expected %i bytes, got %" G_GSIZE_FORMAT,
			     4096 * 4, data_len);
		return NULL;
	}

	/* copy out the coefs */
	coefs = g_new0 (gdouble, 4096);
	for (i = 0; i < 4096; i++)
		coefs[i] = *((gfloat *) &data[i*4]);

	/* this is optional */
	if (length != NULL)
		*length = 4096;

	/* success */
	return coefs;
}
Beispiel #13
0
/**
 * osp_device_query:
 *
 * Since: 1.2.11
 **/
static gboolean
osp_device_query (GUsbDevice *device, OspCmd cmd,
		  const guint8 *data_in, gsize data_in_length,
		  guint8 **data_out, gsize *data_out_length,
		  GError **error)
{
	OspProtocolFooter *ftr;
	OspProtocolHeader *hdr;
	gsize actual_length;
	gsize checksum_length = 16; /* always for MD5 */
	gsize payload_length = 0;
	gsize offset_rd = 0;
	gsize offset_wr = 0;
	guint i;
	g_autoptr(GChecksum) csum = NULL;
	g_autofree guint8 *buffer_in = NULL;
	g_autofree guint8 *buffer_out = NULL;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
	g_return_val_if_fail (data_in_length <= 16, FALSE); //FIXME
	g_assert (sizeof(OspProtocolHeader) + sizeof(OspProtocolFooter) == 64);

	/* write header to buffer */
	buffer_in = g_new0 (guint8, OSP_DEVICE_MAX_MSG_LENGTH);
	hdr = (OspProtocolHeader *) buffer_in;
	hdr->start_bytes = GUINT16_TO_BE (0xc1c0);
	hdr->protocol_version = 0x1000;
	hdr->checksum_type = OSP_HEADER_CHECKSUM_KIND_MD5;
	hdr->message_type = cmd;
	hdr->bytes_remaining = sizeof(OspProtocolFooter);
	if (data_out == NULL)
		hdr->flags = OSP_HEADER_FLAG_ACK_REQUIRED;
	if (data_in_length > 0) {
		if (data_in_length <= 16) {
			/* avoid another USB packet if we can */
			hdr->immediate_data_length = data_in_length;
			memcpy (hdr->immediate_data, data_in, data_in_length);
		} else {
			payload_length = data_in_length;
		}
	}
	offset_wr += sizeof(OspProtocolHeader);
	hdr->bytes_remaining = sizeof(OspProtocolFooter) + payload_length;

	/* write payload to buffer, if any */
	if (payload_length > 0) {
		memcpy (buffer_in + offset_wr, data_in, data_in_length);
		offset_wr += payload_length;
	}

	/* write footer to buffer */
	ftr = (OspProtocolFooter *) (buffer_in + offset_wr);
	ftr->end_bytes = GUINT32_TO_BE (0xc5c4c3c2);
	csum = g_checksum_new (G_CHECKSUM_MD5);
	g_checksum_update (csum, (const guchar *) buffer_in, offset_wr);
	g_checksum_get_digest (csum, ftr->checksum, &checksum_length);
	offset_wr += sizeof(OspProtocolFooter);

	/* send data */
	if (g_getenv ("SPARK_PROTOCOL_DEBUG") != NULL)
		cd_buffer_debug (CD_BUFFER_KIND_REQUEST, buffer_in, offset_wr);
	if (!g_usb_device_bulk_transfer (device, 0x01,
					 buffer_in, offset_wr,
					 &actual_length,
					 OSP_USB_TIMEOUT_MS, NULL, error))
		return FALSE;

	/* get reply */
	buffer_out = g_new0 (guint8, 64);
	if (!g_usb_device_bulk_transfer (device, 0x81,
					 buffer_out, OSP_DEVICE_EP_SIZE,
					 &actual_length,
					 OSP_USB_TIMEOUT_MS, NULL, error))
		return FALSE;
	if (g_getenv ("SPARK_PROTOCOL_DEBUG") != NULL)
		cd_buffer_debug (CD_BUFFER_KIND_RESPONSE, buffer_out, actual_length);

	/* check the error code */
	hdr = (OspProtocolHeader *) buffer_out;
	switch (hdr->error_code) {
	case OSP_ERROR_CODE_SUCCESS:
		break;
	case OSP_ERROR_CODE_MESSAGE_TOO_LARGE:
	case OSP_ERROR_CODE_UNKNOWN_CHECKSUM_TYPE:
	case OSP_ERROR_CODE_UNSUPPORTED_PROTOCOL:
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_NO_SUPPORT,
			     "Failed to %s",
			     osp_cmd_to_string (cmd));
		return FALSE;
		break;
	case OSP_ERROR_CODE_COMMAND_DATA_MISSING:
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_NO_DATA,
			     "Failed to %s",
			     osp_cmd_to_string (cmd));
		return FALSE;
		break;
	default:
		g_set_error (error,
			     OSP_DEVICE_ERROR,
			     OSP_DEVICE_ERROR_INTERNAL,
			     "Failed to %s: %s",
			     osp_cmd_to_string (cmd),
			     osp_error_code_to_string (hdr->error_code));
		return FALSE;
		break;
	}

	/* copy out the data */
	offset_rd = sizeof(OspProtocolHeader);
	if (data_out != NULL && data_out_length != NULL) {
		if (hdr->immediate_data_length > 0) {
			*data_out_length = hdr->immediate_data_length;
			*data_out = g_memdup (hdr->immediate_data,
					      hdr->immediate_data_length);
		} else if (hdr->bytes_remaining >= sizeof(OspProtocolFooter)) {
			*data_out_length = hdr->bytes_remaining - sizeof(OspProtocolFooter);
			*data_out = g_new0 (guint8, hdr->bytes_remaining);

			/* copy the first chunk of data */
			offset_wr = 64 - offset_rd;
			memcpy (*data_out, buffer_out + offset_rd, offset_wr);
		} else {
			g_assert_not_reached ();
		}
	}

	/* read the rest of the payload */
	payload_length = hdr->bytes_remaining - sizeof(OspProtocolFooter);
	for (i = 0; i < payload_length / 64; i++) {
		if (!g_usb_device_bulk_transfer (device, 0x81,
						 buffer_out, OSP_DEVICE_EP_SIZE,
						 &actual_length,
						 OSP_USB_TIMEOUT_MS, NULL, error))
			return FALSE;
		if (data_out != NULL) {
			memcpy (*data_out + offset_wr,
				buffer_out, OSP_DEVICE_EP_SIZE);
		}
		if (g_getenv ("SPARK_PROTOCOL_DEBUG") != NULL)
			cd_buffer_debug (CD_BUFFER_KIND_RESPONSE, buffer_out, OSP_DEVICE_EP_SIZE);
		offset_wr += 64;
	}
	offset_rd += payload_length;

	/* verify the footer is intact */
	ftr = (OspProtocolFooter *) (buffer_out + OSP_DEVICE_EP_SIZE - sizeof(OspProtocolFooter));
	if (ftr->end_bytes != GUINT32_TO_BE (0xc5c4c3c2)) {
		g_set_error_literal (error,
				     OSP_DEVICE_ERROR,
				     OSP_DEVICE_ERROR_INTERNAL,
				     "Footer invalid");
		return FALSE;
	}

	return TRUE;
}
Beispiel #14
0
/**
 * osp_device_take_spectrum:
 * @device: a #GUsbDevice instance.
 * @error: A #GError or %NULL
 *
 * Returns a spectrum. The optimal sample duration is calculated automatically.
 *
 * Return value: A #CdSpectrum, or %NULL for error
 *
 * Since: 1.2.11
 **/
CdSpectrum *
osp_device_take_spectrum (GUsbDevice *device, GError **error)
{
	const guint sample_duration_max_secs = 3;
	gboolean relax_requirements = FALSE;
	gdouble max;
	gdouble scale = 0.f;
	guint64 sample_duration = 10000; /* us */
	CdSpectrum *sp = NULL;
	guint i;

	g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* loop until we're in 1/4 to 3/4 FSD */
	for (i = 0; i < 5; i++) {
		g_autoptr(CdSpectrum) sp_probe = NULL;

		/* for the last try, relax what we deem acceptable so we can
		 * measure very black things with a long integration time */
		if (i == 4)
			relax_requirements = TRUE;

		/* take a measurement */
		sp_probe = osp_device_take_spectrum_full (device,
							  sample_duration,
							  error);
		if (sp_probe == NULL)
			return NULL;

		/* sensor picked up nothing, take action */
		max = cd_spectrum_get_value_max (sp_probe);
		if (max < 0.001f) {
			sample_duration *= 100.f;
			g_debug ("sensor read no data, setting duration "
				 "to %" G_GUINT64_FORMAT ,
				 sample_duration);
			continue;
		}

		/* sensor is saturated, take action */
		if (max > 0.99f) {
			sample_duration /= 100.f;
			g_debug ("sensor saturated, setting duration "
				 "to %" G_GUINT64_FORMAT,
				 sample_duration);
			continue;
		}

		/* break out if we got valid readings */
		if (max > 0.25f && max < 0.75f) {
			sp = cd_spectrum_dup (sp_probe);
			break;
		}

		/* be more accepting */
		if (relax_requirements && max > 0.01f) {
			sp = cd_spectrum_dup (sp_probe);
			break;
		}

		/* aim for FSD / 2 */
		scale = (gdouble) 0.5 / max;
		sample_duration *= scale;
		g_debug ("for max of %f, using scale=%f for duration %" G_GUINT64_FORMAT,
			 max, scale, sample_duration);

		/* limit this to something sane */
		if (sample_duration / G_USEC_PER_SEC > sample_duration_max_secs) {
			g_debug ("limiting duration from %us to %us",
				 (guint) (sample_duration / G_USEC_PER_SEC),
				 (guint) (sample_duration_max_secs));
			sample_duration = sample_duration_max_secs * G_USEC_PER_SEC;
			relax_requirements = TRUE;
		}
	}

	/* no suitable readings */
	if (sp == NULL) {
		g_set_error_literal (error,
				     OSP_DEVICE_ERROR,
				     OSP_DEVICE_ERROR_NO_DATA,
				     "Got no valid data");
		return NULL;
	}

	/* scale with the new integral time */
	cd_spectrum_set_norm (sp, cd_spectrum_get_norm (sp) / scale);
	g_debug ("normalised spectral max is %f", cd_spectrum_get_value_max (sp));
	return sp;
}
Beispiel #15
0
/**
 * dtp94_device_take_sample:
 *
 * Since: 0.1.29
 **/
CdColorXYZ *
dtp94_device_take_sample (GUsbDevice *device, CdSensorCap cap, GError **error)
{
	CdColorXYZ *result = NULL;
	gboolean ret = FALSE;
	gchar *tmp;
	gsize reply_read;
	guint8 buffer[128];

	g_return_val_if_fail (G_USB_IS_DEVICE (device), NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* set hardware support */
	switch (cap) {
	case CD_SENSOR_CAP_CRT:
	case CD_SENSOR_CAP_PLASMA:
		/* CRT = 01 */
		ret = dtp94_device_send_cmd (device, "0116CF\r", error);
		break;
	case CD_SENSOR_CAP_LCD:
		/* LCD = 02 */
		ret = dtp94_device_send_cmd (device, "0216CF\r", error);
		break;
	default:
		g_set_error (error,
			     DTP94_DEVICE_ERROR,
			     DTP94_DEVICE_ERROR_NO_SUPPORT,
			     "DTP94 cannot measure in %s mode",
			     cd_sensor_cap_to_string (cap));
		break;
	}
	if (!ret)
		return NULL;

	/* get sample */
	ret = dtp94_device_send_data (device,
				      (const guint8 *) "RM\r", 3,
				      buffer, sizeof (buffer),
				      &reply_read,
				      error);
	if (!ret)
		return NULL;
	tmp = g_strstr_len ((const gchar *) buffer, reply_read, "\r");
	if (tmp == NULL || memcmp (tmp + 1, "<00>", 4) != 0) {
		buffer[reply_read] = '\0';
		g_set_error (error,
			     DTP94_DEVICE_ERROR,
			     DTP94_DEVICE_ERROR_INTERNAL,
			     "unexpected response from device: %s",
			     (const gchar *) buffer);
		return NULL;
	}

	/* format is raw ASCII with fixed formatting:
	 * 'X     10.29	Y     10.33	Z      4.65\u000d<00>' */
	tmp = (gchar *) buffer;
	g_strdelimit (tmp, "\t\r", '\0');

	/* success */
	result = cd_color_xyz_new ();
	cd_color_xyz_set (result,
			  g_ascii_strtod (tmp + 1, NULL),
			  g_ascii_strtod (tmp + 13, NULL),
			  g_ascii_strtod (tmp + 25, NULL));
	return result;
}