1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2012-2013 Richard Hughes <richard@hughsie.com>
4  *
5  * Licensed under the GNU General Public License Version 2
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #include "config.h"
23 
24 #include <glib-object.h>
25 #include <gio/gio.h>
26 #include <gusb.h>
27 #include <string.h>
28 #include <lcms2.h>
29 
30 #include "ch-common.h"
31 #include "ch-device.h"
32 #include "ch-device-queue.h"
33 #include "ch-math.h"
34 
35 static void	ch_device_queue_finalize	(GObject     *object);
36 
37 #define GET_PRIVATE(o) (ch_device_queue_get_instance_private (o))
38 
39 /**
40  * ChDeviceQueuePrivate:
41  *
42  * Private #ChDeviceQueue data
43  **/
44 typedef struct
45 {
46 	GPtrArray		*data_array;
47 	GHashTable		*devices_in_use;
48 } ChDeviceQueuePrivate;
49 
50 enum {
51 	SIGNAL_DEVICE_FAILED,
52 	SIGNAL_PROGRESS_CHANGED,
53 	SIGNAL_LAST
54 };
55 
56 G_DEFINE_TYPE_WITH_PRIVATE (ChDeviceQueue, ch_device_queue, G_TYPE_OBJECT)
57 
58 typedef gboolean (*ChDeviceQueueParseFunc)	(guint8		*output_buffer,
59 						 gsize		 output_buffer_size,
60 						 gpointer	 user_data,
61 						 GError		**error);
62 
63 typedef enum {
64 	CH_DEVICE_QUEUE_DATA_STATE_PENDING,
65 	CH_DEVICE_QUEUE_DATA_STATE_WAITING_FOR_HW,
66 	CH_DEVICE_QUEUE_DATA_STATE_CANCELLED,
67 	CH_DEVICE_QUEUE_DATA_STATE_COMPLETE,
68 	CH_DEVICE_QUEUE_DATA_STATE_UNKNOWN
69 } ChDeviceQueueDataState;
70 
71 typedef struct {
72 	ChDeviceQueueDataState	 state;
73 	GUsbDevice		*device;
74 	guint8			 cmd;
75 	guint8			*buffer_in;
76 	gsize			 buffer_in_len;
77 	guint8			*buffer_out;
78 	gsize			 buffer_out_len;
79 	GDestroyNotify		 buffer_out_destroy_func;
80 	ChDeviceQueueParseFunc	 parse_func;
81 	gpointer		 user_data;
82 	GDestroyNotify		 user_data_destroy_func;
83 } ChDeviceQueueData;
84 
85 typedef struct {
86 	ChDeviceQueue		*device_queue;
87 	ChDeviceQueueProcessFlags process_flags;
88 	GCancellable		*cancellable;
89 	GSimpleAsyncResult	*res;
90 	GPtrArray		*failures;
91 } ChDeviceQueueTaskData;
92 
93 static guint signals[SIGNAL_LAST] = { 0 };
94 
95 static gboolean ch_device_queue_process_data (GTask *task, ChDeviceQueueData *data);
96 
97 /**
98  * ch_device_queue_data_free:
99  **/
100 static void
ch_device_queue_data_free(ChDeviceQueueData * data)101 ch_device_queue_data_free (ChDeviceQueueData *data)
102 {
103 	if (data->buffer_out_destroy_func != NULL)
104 		data->buffer_out_destroy_func (data->buffer_out);
105 	if (data->user_data_destroy_func != NULL)
106 		data->user_data_destroy_func (data->user_data);
107 	g_free (data->buffer_in);
108 	g_object_unref (data->device);
109 	g_free (data);
110 }
111 
112 /**
113  * ch_device_queue_task_data_free:
114  **/
115 static void
ch_device_queue_task_data_free(ChDeviceQueueTaskData * data)116 ch_device_queue_task_data_free (ChDeviceQueueTaskData *data)
117 {
118 	g_object_unref (data->device_queue);
119 	g_ptr_array_unref (data->failures);
120 	g_free (data);
121 }
122 
123 /**
124  * ch_device_queue_device_force_complete:
125  **/
126 static void
ch_device_queue_device_force_complete(ChDeviceQueue * device_queue,GUsbDevice * device)127 ch_device_queue_device_force_complete (ChDeviceQueue *device_queue, GUsbDevice *device)
128 {
129 	ChDeviceQueuePrivate *priv = GET_PRIVATE (device_queue);
130 	ChDeviceQueueData *data;
131 	const gchar *device_id;
132 	const gchar *device_id_tmp;
133 	guint i;
134 
135 	/* go through the list of commands and cancel them all */
136 	device_id = g_usb_device_get_platform_id (device);
137 	for (i = 0; i < priv->data_array->len; i++) {
138 		data = g_ptr_array_index (priv->data_array, i);
139 		device_id_tmp = g_usb_device_get_platform_id (data->device);
140 		if (g_strcmp0 (device_id_tmp, device_id) == 0)
141 			data->state = CH_DEVICE_QUEUE_DATA_STATE_CANCELLED;
142 	}
143 }
144 
145 /**
146  * ch_device_queue_update_progress:
147  **/
148 static void
ch_device_queue_update_progress(ChDeviceQueue * device_queue)149 ch_device_queue_update_progress (ChDeviceQueue *device_queue)
150 {
151 	ChDeviceQueuePrivate *priv = GET_PRIVATE (device_queue);
152 	guint complete = 0;
153 	guint i;
154 	guint percentage;
155 	ChDeviceQueueData *data;
156 
157 	/* no devices */
158 	if (priv->data_array->len == 0)
159 		return;
160 
161 	/* find out how many commands are complete */
162 	for (i = 0; i < priv->data_array->len; i++) {
163 		data = g_ptr_array_index (priv->data_array, i);
164 		if (data->state == CH_DEVICE_QUEUE_DATA_STATE_COMPLETE ||
165 		    data->state == CH_DEVICE_QUEUE_DATA_STATE_CANCELLED)
166 			complete++;
167 	}
168 
169 	/* emit a signal with our progress */
170 	percentage = (complete * 100) / priv->data_array->len;
171 	g_signal_emit (device_queue,
172 		       signals[SIGNAL_PROGRESS_CHANGED], 0,
173 		       percentage);
174 }
175 
176 /**
177  * ch_device_queue_count_in_state:
178  **/
179 static guint
ch_device_queue_count_in_state(ChDeviceQueue * device_queue,ChDeviceQueueDataState state)180 ch_device_queue_count_in_state (ChDeviceQueue *device_queue,
181 				ChDeviceQueueDataState state)
182 {
183 	ChDeviceQueuePrivate *priv = GET_PRIVATE (device_queue);
184 	guint i;
185 	guint cnt = 0;
186 	ChDeviceQueueData *data;
187 
188 	/* find any data objects in a specific state */
189 	for (i = 0; i < priv->data_array->len; i++) {
190 		data = g_ptr_array_index (priv->data_array, i);
191 		if (data->state == state)
192 			cnt++;
193 	}
194 	return cnt;
195 }
196 
197 /**
198  * ch_device_queue_process_write_command_cb:
199  **/
200 static void
ch_device_queue_process_write_command_cb(GObject * source,GAsyncResult * res,gpointer user_data)201 ch_device_queue_process_write_command_cb (GObject *source,
202 					  GAsyncResult *res,
203 					  gpointer user_data)
204 {
205 	ChDeviceQueueData *data;
206 	GTask *task = G_TASK (user_data);
207 	ChDeviceQueueTaskData *tdata = g_task_get_task_data (task);
208 	ChDeviceQueue *device_queue = CH_DEVICE_QUEUE (tdata->device_queue);
209 	ChDeviceQueuePrivate *priv = GET_PRIVATE (device_queue);
210 	const gchar *device_id;
211 	const gchar *tmp;
212 	gboolean ret;
213 	g_autoptr(GError) error = NULL;
214 	guint i;
215 	guint pending_commands;
216 	ChError last_error_code = 0;
217 	GUsbDevice *device = G_USB_DEVICE (source);
218 	g_autofree gchar *error_msg = NULL;
219 
220 	/* mark it as not in use */
221 	device_id = g_usb_device_get_platform_id (device);
222 	data = g_hash_table_lookup (priv->devices_in_use, device_id);
223 	g_hash_table_remove (priv->devices_in_use, device_id);
224 
225 	/* get data */
226 	ret = ch_device_write_command_finish (device, res, &error);
227 	if (ret && data->parse_func != NULL) {
228 		/* do any conversion function */
229 		ret = data->parse_func (data->buffer_out,
230 					data->buffer_out_len,
231 					data->user_data,
232 					&error);
233 	}
234 	if (!ret) {
235 		/* tell the client the device has failed */
236 		g_debug ("emit device-failed: %s", error->message);
237 		g_signal_emit (device_queue,
238 			       signals[SIGNAL_DEVICE_FAILED], 0,
239 			       device,
240 			       error->message);
241 
242 		/* save this so we can possibly use when we're done */
243 		last_error_code = error->code;
244 		g_ptr_array_add (tdata->failures,
245 				 g_strdup_printf ("%s: %s",
246 						  g_usb_device_get_platform_id (device),
247 						  error->message));
248 
249 		/* should we mark complete other commands as complete */
250 		if ((tdata->process_flags & CH_DEVICE_QUEUE_PROCESS_FLAGS_CONTINUE_ERRORS) == 0) {
251 			ch_device_queue_device_force_complete (device_queue, device);
252 			ch_device_queue_update_progress (device_queue);
253 			goto out;
254 		}
255 	}
256 
257 	/* update progress */
258 	data->state = CH_DEVICE_QUEUE_DATA_STATE_COMPLETE;
259 	ch_device_queue_update_progress (device_queue);
260 
261 	/* is there another pending command for this device */
262 	for (i = 0; i < priv->data_array->len; i++) {
263 		data = g_ptr_array_index (priv->data_array, i);
264 		ret = ch_device_queue_process_data (task, data);
265 		if (ret)
266 			break;
267 	}
268 out:
269 	/* any more pending commands? */
270 	pending_commands = ch_device_queue_count_in_state (device_queue,
271 							   CH_DEVICE_QUEUE_DATA_STATE_PENDING);
272 	pending_commands += ch_device_queue_count_in_state (device_queue,
273 							    CH_DEVICE_QUEUE_DATA_STATE_WAITING_FOR_HW);
274 	g_debug ("Pending commands: %u", pending_commands);
275 	if (pending_commands == 0) {
276 
277 		/* should we return the process with an error, or just
278 		 * rely on the signal? */
279 		if (tdata->failures->len == 1 &&
280 		    (tdata->process_flags & CH_DEVICE_QUEUE_PROCESS_FLAGS_NONFATAL_ERRORS) == 0) {
281 			tmp = g_ptr_array_index (tdata->failures, 0);
282 			g_task_return_new_error (task,
283 						 CH_DEVICE_ERROR,
284 						 last_error_code,
285 						 "%s", tmp);
286 		} else if (tdata->failures->len > 1 &&
287 			   (tdata->process_flags & CH_DEVICE_QUEUE_PROCESS_FLAGS_NONFATAL_ERRORS) == 0) {
288 			g_ptr_array_add (tdata->failures, NULL);
289 			error_msg = g_strjoinv (", ", (gchar**) tdata->failures->pdata);
290 			g_task_return_new_error (task,
291 						 CH_DEVICE_ERROR,
292 						 last_error_code,
293 						 "There were %u failures: %s",
294 						 tdata->failures->len - 1,
295 						 error_msg);
296 		} else {
297 			g_task_return_boolean (task, TRUE);
298 		}
299 
300 		/* remove all commands from the queue, as they are done */
301 #if 0
302 /* FIXME: some sort of race uncovered in the port to GTask means that we try
303  * to remove data objects before they are marked complete; for now disable */
304 
305 		g_ptr_array_set_size (priv->data_array, 0);
306 #endif
307 		g_object_unref (task);
308 	}
309 }
310 
311 /**
312  * ch_device_queue_process_data:
313  *
314  * Returns TRUE if the command was submitted
315  **/
316 static gboolean
ch_device_queue_process_data(GTask * task,ChDeviceQueueData * data)317 ch_device_queue_process_data (GTask *task, ChDeviceQueueData *data)
318 {
319 	ChDeviceQueue *device_queue = CH_DEVICE_QUEUE (g_task_get_source_object (task));
320 	ChDeviceQueuePrivate *priv = GET_PRIVATE (device_queue);
321 	ChDeviceQueueData *data_tmp;
322 	const gchar *device_id;
323 
324 	/* is this command already complete? */
325 	if (data->state == CH_DEVICE_QUEUE_DATA_STATE_COMPLETE)
326 		return FALSE;
327 
328 	/* is this device already busy? */
329 	device_id = g_usb_device_get_platform_id (data->device);
330 	data_tmp = g_hash_table_lookup (priv->devices_in_use, device_id);
331 	if (data_tmp != NULL)
332 		return FALSE;
333 
334 	/* write this command and wait for a response */
335 	ch_device_write_command_async (data->device,
336 				       data->cmd,
337 				       data->buffer_in,
338 				       data->buffer_in_len,
339 				       data->buffer_out,
340 				       data->buffer_out_len,
341 				       g_task_get_cancellable (task),
342 				       ch_device_queue_process_write_command_cb,
343 				       task);
344 	/* mark this as in use */
345 	g_hash_table_insert (priv->devices_in_use, g_strdup (device_id), data);
346 
347 	/* remove this from the command queue -- TODO: retries? */
348 	data->state = CH_DEVICE_QUEUE_DATA_STATE_WAITING_FOR_HW;
349 	return TRUE;
350 }
351 
352 /**
353  * ch_device_queue_process_async:
354  * @device_queue:		A #ChDeviceQueue
355  * @cancellable:	A #GCancellable, or %NULL
356  * @callback:		A #GAsyncReadyCallback that will be called when finished.
357  * @user_data:		User data passed to @callback
358  *
359  * Processes all commands in the command queue.
360  *
361  * Since: 0.1.29
362  **/
363 void
ch_device_queue_process_async(ChDeviceQueue * device_queue,ChDeviceQueueProcessFlags process_flags,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)364 ch_device_queue_process_async (ChDeviceQueue		*device_queue,
365 			       ChDeviceQueueProcessFlags process_flags,
366 			       GCancellable		*cancellable,
367 			       GAsyncReadyCallback	 callback,
368 			       gpointer			 user_data)
369 {
370 	ChDeviceQueuePrivate *priv = GET_PRIVATE (device_queue);
371 	ChDeviceQueueTaskData *tdata;
372 	ChDeviceQueueData *data;
373 	GTask *task = NULL;
374 	guint i;
375 
376 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
377 	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
378 
379 	task = g_task_new (device_queue, cancellable, callback, user_data);
380 	tdata = g_new0 (ChDeviceQueueTaskData, 1);
381 	tdata->process_flags = process_flags;
382 	tdata->device_queue = g_object_ref (device_queue);
383 	tdata->failures = g_ptr_array_new_with_free_func (g_free);
384 	g_task_set_task_data (task, tdata, (GDestroyNotify) ch_device_queue_task_data_free);
385 
386 	/* go through the list of commands and try to submit them all */
387 	ch_device_queue_update_progress (device_queue);
388 	for (i = 0; i < priv->data_array->len; i++) {
389 		data = g_ptr_array_index (priv->data_array, i);
390 		ch_device_queue_process_data (task, data);
391 	}
392 
393 	/* is anything pending? */
394 	if (g_hash_table_size (priv->devices_in_use) == 0) {
395 		g_task_return_boolean (task, TRUE);
396 		g_object_unref (task);
397 	}
398 }
399 
400 /**
401  * ch_device_queue_process_finish:
402  * @device_queue: a #ChDeviceQueue instance.
403  * @res: the #GAsyncResult
404  * @error: A #GError or %NULL
405  *
406  * Gets the result from the asynchronous function.
407  *
408  * Return value: %TRUE if the request was fulfilled.
409  *
410  * Since: 0.1.29
411  **/
412 gboolean
ch_device_queue_process_finish(ChDeviceQueue * device_queue,GAsyncResult * res,GError ** error)413 ch_device_queue_process_finish (ChDeviceQueue	*device_queue,
414 				GAsyncResult	*res,
415 				GError		**error)
416 {
417 	g_return_val_if_fail (g_task_is_valid (res, device_queue), FALSE);
418 	return g_task_propagate_boolean (G_TASK (res), error);
419 }
420 
421 /**********************************************************************/
422 
423 /* tiny helper to help us do the async operation */
424 typedef struct {
425 	GError		**error;
426 	GMainLoop	*loop;
427 	gboolean	 ret;
428 } ChDeviceQueueSyncHelper;
429 
430 /**
431  * ch_device_queue_process_finish_cb:
432  **/
433 static void
ch_device_queue_process_finish_cb(GObject * source,GAsyncResult * res,gpointer user_data)434 ch_device_queue_process_finish_cb (GObject *source,
435 				   GAsyncResult *res,
436 				   gpointer user_data)
437 {
438 	ChDeviceQueue *device_queue = CH_DEVICE_QUEUE (source);
439 	ChDeviceQueueSyncHelper *helper = (ChDeviceQueueSyncHelper *) user_data;
440 	helper->ret = ch_device_queue_process_finish (device_queue, res, helper->error);
441 	g_main_loop_quit (helper->loop);
442 }
443 
444 /**
445  * ch_device_queue_process:
446  * @device_queue:	A #ChDeviceQueue
447  * @process_flags:	Flags how to process the queue, e.g. %CH_DEVICE_QUEUE_PROCESS_FLAGS_CONTINUE_ERRORS
448  * @cancellable:	#GCancellable or %NULL
449  * @error:		A #GError, or %NULL
450  *
451  * Processes all commands in the command queue.
452  * WARNING: this function is syncronous and will block.
453  *
454  * Return value: %TRUE if the commands were executed successfully.
455  *
456  * Since: 0.1.29
457  **/
458 gboolean
ch_device_queue_process(ChDeviceQueue * device_queue,ChDeviceQueueProcessFlags process_flags,GCancellable * cancellable,GError ** error)459 ch_device_queue_process (ChDeviceQueue	*device_queue,
460 			 ChDeviceQueueProcessFlags process_flags,
461 			 GCancellable	*cancellable,
462 			 GError		**error)
463 {
464 	ChDeviceQueueSyncHelper helper;
465 
466 	g_return_val_if_fail (CH_IS_DEVICE_QUEUE (device_queue), FALSE);
467 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
468 
469 	/* create temp object */
470 	helper.ret = FALSE;
471 	helper.loop = g_main_loop_new (NULL, FALSE);
472 	helper.error = error;
473 
474 	/* run async method */
475 	ch_device_queue_process_async (device_queue,
476 				       process_flags,
477 				       cancellable,
478 				       ch_device_queue_process_finish_cb,
479 				       &helper);
480 	g_main_loop_run (helper.loop);
481 
482 	/* free temp object */
483 	g_main_loop_unref (helper.loop);
484 
485 	return helper.ret;
486 }
487 
488 /**********************************************************************/
489 
490 /**
491  * ch_device_queue_add_internal:
492  **/
493 static void
ch_device_queue_add_internal(ChDeviceQueue * device_queue,GUsbDevice * device,guint8 cmd,const guint8 * buffer_in,gsize buffer_in_len,guint8 * buffer_out,gsize buffer_out_len,GDestroyNotify buffer_out_destroy_func,ChDeviceQueueParseFunc parse_func,gpointer user_data,GDestroyNotify user_data_destroy_func)494 ch_device_queue_add_internal (ChDeviceQueue		*device_queue,
495 			      GUsbDevice		*device,
496 			      guint8			 cmd,
497 			      const guint8		*buffer_in,
498 			      gsize			 buffer_in_len,
499 			      guint8			*buffer_out,
500 			      gsize			 buffer_out_len,
501 			      GDestroyNotify		 buffer_out_destroy_func,
502 			      ChDeviceQueueParseFunc	 parse_func,
503 			      gpointer			 user_data,
504 			      GDestroyNotify		 user_data_destroy_func)
505 {
506 	ChDeviceQueueData *data;
507 	ChDeviceQueuePrivate *priv = GET_PRIVATE (device_queue);
508 
509 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
510 	g_return_if_fail (G_USB_IS_DEVICE (device));
511 
512 	data = g_new0 (ChDeviceQueueData, 1);
513 	data->state = CH_DEVICE_QUEUE_DATA_STATE_PENDING;
514 	data->parse_func = parse_func;
515 	data->user_data = user_data;
516 	data->user_data_destroy_func = user_data_destroy_func;
517 	data->cmd = cmd;
518 	data->device = g_object_ref (device);
519 	if (buffer_in != NULL)
520 		data->buffer_in = g_memdup (buffer_in, buffer_in_len);
521 	data->buffer_in_len = buffer_in_len;
522 	data->buffer_out = buffer_out;
523 	data->buffer_out_len = buffer_out_len;
524 	data->buffer_out_destroy_func = buffer_out_destroy_func;
525 	g_ptr_array_add (priv->data_array, data);
526 }
527 
528 /**
529  * ch_device_queue_add:
530  * @device_queue:	A #ChDeviceQueue
531  * @device:		A #GUsbDevice
532  * @cmd:		The command, e.g. %CH_CMD_TAKE_READINGS
533  * @buffer_in:		The input buffer, or %NULL
534  * @buffer_in_len:	The size of @buffer_in
535  * @buffer_out:		The output buffer, or %NULL
536  * @buffer_out_len:	The size of @buffer_out
537  *
538  * Adds a raw command to the device queue.
539  *
540  * Since: 0.1.29
541  **/
542 void
ch_device_queue_add(ChDeviceQueue * device_queue,GUsbDevice * device,guint8 cmd,const guint8 * buffer_in,gsize buffer_in_len,guint8 * buffer_out,gsize buffer_out_len)543 ch_device_queue_add (ChDeviceQueue	*device_queue,
544 		     GUsbDevice		*device,
545 		     guint8		 cmd,
546 		     const guint8	*buffer_in,
547 		     gsize		 buffer_in_len,
548 		     guint8		*buffer_out,
549 		     gsize		 buffer_out_len)
550 {
551 	ch_device_queue_add_internal (device_queue,
552 				      device,
553 				      cmd,
554 				      buffer_in,
555 				      buffer_in_len,
556 				      buffer_out,
557 				      buffer_out_len,
558 				      NULL,
559 				      NULL,
560 				      NULL,
561 				      NULL);
562 }
563 
564 /**********************************************************************/
565 
566 
567 
568 /**
569  * ch_device_queue_get_color_select:
570  * @device_queue:	A #ChDeviceQueue
571  * @device:		A #GUsbDevice
572  * @color_select:	The color select, e.g. %CH_COLOR_SELECT_RED
573  *
574  * Gets the selected sensor color.
575  *
576  * NOTE: This command is available on hardware version: 1 & 2
577  *
578  * Since: 0.1.29
579  **/
580 void
ch_device_queue_get_color_select(ChDeviceQueue * device_queue,GUsbDevice * device,ChColorSelect * color_select)581 ch_device_queue_get_color_select (ChDeviceQueue *device_queue,
582 				  GUsbDevice *device,
583 				  ChColorSelect *color_select)
584 {
585 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
586 	g_return_if_fail (G_USB_IS_DEVICE (device));
587 	g_return_if_fail (color_select != NULL);
588 
589 	ch_device_queue_add (device_queue,
590 			     device,
591 			     CH_CMD_GET_COLOR_SELECT,
592 			     NULL,
593 			     0,
594 			     (guint8 *) color_select,
595 			     1);
596 }
597 
598 /**
599  * ch_device_queue_set_color_select:
600  * @device_queue:	A #ChDeviceQueue
601  * @device:		A #GUsbDevice
602  * @color_select:	The color select, e.g. %CH_COLOR_SELECT_RED
603  *
604  * Sets the sensor measurement color.
605  *
606  * NOTE: This command is available on hardware version: 1 & 2
607  *
608  * Since: 0.1.29
609  **/
610 void
ch_device_queue_set_color_select(ChDeviceQueue * device_queue,GUsbDevice * device,ChColorSelect color_select)611 ch_device_queue_set_color_select (ChDeviceQueue *device_queue,
612 				  GUsbDevice *device,
613 				  ChColorSelect color_select)
614 {
615 	guint8 csel8 = color_select;
616 
617 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
618 	g_return_if_fail (G_USB_IS_DEVICE (device));
619 
620 	ch_device_queue_add (device_queue,
621 			     device,
622 			     CH_CMD_SET_COLOR_SELECT,
623 			     &csel8,
624 			     1,
625 			     NULL,
626 			     0);
627 }
628 
629 /**
630  * ch_device_queue_get_multiplier:
631  * @device_queue:	A #ChDeviceQueue
632  * @device:		A #GUsbDevice
633  * @multiplier:		The device multiplier, e.g. %CH_FREQ_SCALE_100
634  *
635  * Gets the sensor multiplier.
636  *
637  * NOTE: This command is available on hardware version: 1 & 2
638  *
639  * Since: 0.1.29
640  **/
641 void
ch_device_queue_get_multiplier(ChDeviceQueue * device_queue,GUsbDevice * device,ChFreqScale * multiplier)642 ch_device_queue_get_multiplier (ChDeviceQueue *device_queue,
643 				GUsbDevice *device,
644 				ChFreqScale *multiplier)
645 {
646 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
647 	g_return_if_fail (G_USB_IS_DEVICE (device));
648 	g_return_if_fail (multiplier != NULL);
649 
650 	ch_device_queue_add (device_queue,
651 			     device,
652 			     CH_CMD_GET_MULTIPLIER,
653 			     NULL,
654 			     0,
655 			     (guint8 *) multiplier,
656 			     1);
657 }
658 
659 /**
660  * ch_device_queue_set_multiplier:
661  * @device_queue:	A #ChDeviceQueue
662  * @device:		A #GUsbDevice
663  * @multiplier:		The device multiplier, e.g. %CH_FREQ_SCALE_100
664  *
665  * Sets the sensor multiplier.
666  *
667  * NOTE: This command is available on hardware version: 1 & 2
668  *
669  * Since: 0.1.29
670  **/
671 void
ch_device_queue_set_multiplier(ChDeviceQueue * device_queue,GUsbDevice * device,ChFreqScale multiplier)672 ch_device_queue_set_multiplier (ChDeviceQueue *device_queue,
673 				GUsbDevice *device,
674 				ChFreqScale multiplier)
675 {
676 	guint8 mult8 = multiplier;
677 
678 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
679 	g_return_if_fail (G_USB_IS_DEVICE (device));
680 
681 	ch_device_queue_add (device_queue,
682 			     device,
683 			     CH_CMD_SET_MULTIPLIER,
684 			     &mult8,
685 			     1,
686 			     NULL,
687 			     0);
688 }
689 
690 /**
691  * ch_device_queue_buffer_uint16_from_le_cb:
692  **/
693 static gboolean
ch_device_queue_buffer_uint16_from_le_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)694 ch_device_queue_buffer_uint16_from_le_cb (guint8 *output_buffer,
695 					  gsize output_buffer_size,
696 					  gpointer user_data,
697 					  GError **error)
698 {
699 	guint16 tmp;
700 
701 	/* check buffer size */
702 	if (output_buffer_size != sizeof (guint16)) {
703 		g_set_error (error, 1, 0,
704 			     "Wrong output buffer size, expected %" G_GSIZE_FORMAT ", got %" G_GSIZE_FORMAT,
705 			     sizeof (guint16), output_buffer_size);
706 		return FALSE;
707 	}
708 	tmp = cd_buffer_read_uint16_le (output_buffer);
709 	memcpy (output_buffer, &tmp, sizeof (tmp));
710 	return TRUE;
711 }
712 
713 /**
714  * ch_device_queue_buffer_uint32_from_le_cb:
715  **/
716 static gboolean
ch_device_queue_buffer_uint32_from_le_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)717 ch_device_queue_buffer_uint32_from_le_cb (guint8 *output_buffer,
718 					  gsize output_buffer_size,
719 					  gpointer user_data,
720 					  GError **error)
721 {
722 	guint32 tmp;
723 
724 	/* check buffer size */
725 	if (output_buffer_size != sizeof (guint32)) {
726 		g_set_error (error, 1, 0,
727 			     "Wrong output buffer size, expected %" G_GSIZE_FORMAT ", got %" G_GSIZE_FORMAT,
728 			     sizeof (guint32), output_buffer_size);
729 		return FALSE;
730 	}
731 	tmp = cd_buffer_read_uint32_le (output_buffer);
732 	memcpy (output_buffer, &tmp, sizeof (tmp));
733 	return TRUE;
734 }
735 
736 /**
737  * ch_device_queue_get_integral_time:
738  * @device_queue:	A #ChDeviceQueue
739  * @device:		A #GUsbDevice
740  * @integral_time:	The sensor integral time in device units
741  *
742  * Gets the reading integral time.
743 
744  * NOTE: This command is available on hardware version: 1 & 2
745  *
746  * Since: 0.1.29
747  **/
748 void
ch_device_queue_get_integral_time(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 * integral_time)749 ch_device_queue_get_integral_time (ChDeviceQueue *device_queue,
750 				   GUsbDevice *device,
751 				   guint16 *integral_time)
752 {
753 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
754 	g_return_if_fail (G_USB_IS_DEVICE (device));
755 	g_return_if_fail (integral_time != NULL);
756 
757 	ch_device_queue_add_internal (device_queue,
758 				      device,
759 				      CH_CMD_GET_INTEGRAL_TIME,
760 				      NULL,
761 				      0,
762 				      (guint8 *) integral_time,
763 				      2,
764 				      NULL,
765 				      ch_device_queue_buffer_uint16_from_le_cb,
766 				      NULL,
767 				      NULL);
768 }
769 
770 /**
771  * ch_device_queue_set_integral_time:
772  * @device_queue:	A #ChDeviceQueue
773  * @device:		A #GUsbDevice
774  * @integral_time:	The sensor integral time in device units
775  *
776  * Sets the reading integral time.
777  *
778  * NOTE: This command is available on hardware version: 1 & 2
779  *
780  * Since: 0.1.29
781  **/
782 void
ch_device_queue_set_integral_time(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 integral_time)783 ch_device_queue_set_integral_time (ChDeviceQueue *device_queue,
784 				   GUsbDevice *device,
785 				   guint16 integral_time)
786 {
787 	guint16 integral_le;
788 
789 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
790 	g_return_if_fail (G_USB_IS_DEVICE (device));
791 	g_return_if_fail (integral_time > 0);
792 
793 	integral_le = GUINT16_TO_LE (integral_time);
794 
795 	ch_device_queue_add (device_queue,
796 			     device,
797 			     CH_CMD_SET_INTEGRAL_TIME,
798 			     (const guint8 *) &integral_le,
799 			     sizeof(guint16),
800 			     NULL,
801 			     0);
802 }
803 
804 /**
805  * ch_device_queue_get_calibration_map:
806  * @device_queue:	A #ChDeviceQueue
807  * @device:		A #GUsbDevice
808  * @calibration_map:	An array of slot positions
809  *
810  * Gets the calibration map.
811  *
812  * NOTE: This command is available on hardware version: 1 & 2
813  *
814  * Since: 0.1.29
815  **/
816 void
ch_device_queue_get_calibration_map(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 * calibration_map)817 ch_device_queue_get_calibration_map (ChDeviceQueue *device_queue,
818 				     GUsbDevice *device,
819 				     guint16 *calibration_map)
820 {
821 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
822 	g_return_if_fail (G_USB_IS_DEVICE (device));
823 	g_return_if_fail (calibration_map != NULL);
824 
825 	ch_device_queue_add (device_queue,
826 			     device,
827 			     CH_CMD_GET_CALIBRATION_MAP,
828 			     NULL,
829 			     0,
830 			     (guint8 *) calibration_map,
831 			     CH_CALIBRATION_INDEX_MAX * sizeof(guint16));
832 }
833 
834 /**
835  * ch_device_queue_set_calibration_map:
836  * @device_queue:	A #ChDeviceQueue
837  * @device:		A #GUsbDevice
838  * @calibration_map:	An array of slot positions
839  *
840  * Sets the calibration map.
841  *
842  * NOTE: This command is available on hardware version: 1 & 2
843  *
844  * Since: 0.1.29
845  **/
846 void
ch_device_queue_set_calibration_map(ChDeviceQueue * device_queue,GUsbDevice * device,const guint16 * calibration_map)847 ch_device_queue_set_calibration_map (ChDeviceQueue *device_queue,
848 				     GUsbDevice *device,
849 				     const guint16 *calibration_map)
850 {
851 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
852 	g_return_if_fail (G_USB_IS_DEVICE (device));
853 	g_return_if_fail (calibration_map != NULL);
854 
855 	ch_device_queue_add (device_queue,
856 			     device,
857 			     CH_CMD_SET_CALIBRATION_MAP,
858 			     (const guint8 *) calibration_map,
859 			     CH_CALIBRATION_INDEX_MAX * sizeof(guint16),
860 			     NULL,
861 			     0);
862 }
863 
864 /* tiny helper */
865 typedef struct {
866 	guint16		*major;
867 	guint16		*minor;
868 	guint16		*micro;
869 } ChDeviceQueueGetFirmwareVerHelper;
870 
871 /**
872  * ch_device_queue_buffer_to_firmware_ver_cb:
873  **/
874 static gboolean
ch_device_queue_buffer_to_firmware_ver_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)875 ch_device_queue_buffer_to_firmware_ver_cb (guint8 *output_buffer,
876 					   gsize output_buffer_size,
877 					   gpointer user_data,
878 					   GError **error)
879 {
880 	ChDeviceQueueGetFirmwareVerHelper *helper = (void *) user_data;
881 
882 	/* check buffer size */
883 	if (output_buffer_size != sizeof (guint16) * 3) {
884 		g_set_error (error, 1, 0,
885 			     "Wrong output buffer size, expected %" G_GSIZE_FORMAT ", got %" G_GSIZE_FORMAT,
886 			     sizeof (guint16) * 3, output_buffer_size);
887 		return FALSE;
888 	}
889 
890 	*helper->major = cd_buffer_read_uint16_le (output_buffer + 0);
891 	*helper->minor = cd_buffer_read_uint16_le (output_buffer + 2);
892 	*helper->micro = cd_buffer_read_uint16_le (output_buffer + 4);
893 	return TRUE;
894 }
895 
896 /**
897  * ch_device_queue_get_firmware_ver:
898  * @device_queue:	A #ChDeviceQueue
899  * @device:		A #GUsbDevice
900  * @major:		The firmware major version
901  * @minor:		The firmware minor version
902  * @micro:		The firmware micro version
903  *
904  * Gets the firmware version.
905  *
906  * NOTE: This command is available on hardware version: 1 & 2
907  *
908  * Since: 0.1.29
909  **/
910 void
ch_device_queue_get_firmware_ver(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 * major,guint16 * minor,guint16 * micro)911 ch_device_queue_get_firmware_ver (ChDeviceQueue *device_queue,
912 				  GUsbDevice *device,
913 				  guint16 *major,
914 				  guint16 *minor,
915 				  guint16 *micro)
916 {
917 	guint8 *buffer;
918 	ChDeviceQueueGetFirmwareVerHelper *helper;
919 
920 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
921 	g_return_if_fail (G_USB_IS_DEVICE (device));
922 	g_return_if_fail (major != NULL);
923 	g_return_if_fail (minor != NULL);
924 	g_return_if_fail (micro != NULL);
925 
926 	/* create a helper structure */
927 	helper = g_new0 (ChDeviceQueueGetFirmwareVerHelper, 1);
928 	helper->major = major;
929 	helper->minor = minor;
930 	helper->micro = micro;
931 
932 	buffer = g_new0 (guint8, sizeof (guint16) * 3);
933 	ch_device_queue_add_internal (device_queue,
934 				      device,
935 				      CH_CMD_GET_FIRMWARE_VERSION,
936 				      NULL,
937 				      0,
938 				      buffer,
939 				      sizeof (guint16) * 3,
940 				      g_free,
941 				      ch_device_queue_buffer_to_firmware_ver_cb,
942 				      helper,
943 				      g_free);
944 }
945 
946 /* tiny helper */
947 typedef struct {
948 	CdMat3x3	*calibration;
949 	guint8		*types;
950 	gchar		*description;
951 } ChDeviceQueueGetCalibrationHelper;
952 
953 /**
954  * ch_device_queue_buffer_to_get_calibration_cb:
955  **/
956 static gboolean
ch_device_queue_buffer_to_get_calibration_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)957 ch_device_queue_buffer_to_get_calibration_cb (guint8 *output_buffer,
958 					      gsize output_buffer_size,
959 					      gpointer user_data,
960 					      GError **error)
961 {
962 	ChDeviceQueueGetCalibrationHelper *helper = (void *) user_data;
963 	ChPackedFloat pf_tmp;
964 	gdouble *calibration_tmp;
965 	guint i;
966 
967 	/* check buffer size */
968 	if (output_buffer_size != 60) {
969 		g_set_error (error, 1, 0,
970 			     "Wrong output buffer size, expected %i, got %" G_GSIZE_FORMAT,
971 			     60, output_buffer_size);
972 		return FALSE;
973 	}
974 
975 	/* convert back into floating point */
976 	if (helper->calibration != NULL) {
977 		calibration_tmp = cd_mat33_get_data (helper->calibration);
978 		for (i = 0; i < 9; i++) {
979 			memcpy (&pf_tmp, &output_buffer[i*4], sizeof (pf_tmp));
980 			ch_packed_float_to_double (&pf_tmp, &calibration_tmp[i]);
981 		}
982 	}
983 
984 	/* get the supported types */
985 	if (helper->types != NULL)
986 		*helper->types = output_buffer[9*4];
987 
988 	/* get the description */
989 	if (helper->description != NULL) {
990 		strncpy (helper->description,
991 			 (const char *) output_buffer + 9*4 + 1,
992 			 CH_CALIBRATION_DESCRIPTION_LEN);
993 	}
994 	return TRUE;
995 }
996 
997 /**
998  * ch_device_queue_get_calibration:
999  * @device_queue:	A #ChDeviceQueue
1000  * @device:		A #GUsbDevice
1001  * @calibration_index:	The slot position
1002  * @calibration:	the 3x3 calibration matrix
1003  * @types:		The types the matrix supports
1004  * @description:	The description of the calibration
1005  *
1006  * Gets the calibration data.
1007  *
1008  * NOTE: This command is available on hardware version: 1 & 2
1009  *
1010  * Since: 0.1.29
1011  **/
1012 void
ch_device_queue_get_calibration(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 calibration_index,CdMat3x3 * calibration,guint8 * types,gchar * description)1013 ch_device_queue_get_calibration (ChDeviceQueue *device_queue,
1014 				 GUsbDevice *device,
1015 				 guint16 calibration_index,
1016 				 CdMat3x3 *calibration,
1017 				 guint8 *types,
1018 				 gchar *description)
1019 {
1020 	guint8 *buffer;
1021 	ChDeviceQueueGetCalibrationHelper *helper;
1022 
1023 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1024 	g_return_if_fail (G_USB_IS_DEVICE (device));
1025 	g_return_if_fail (calibration_index < CH_CALIBRATION_MAX);
1026 
1027 	/* create a helper structure */
1028 	helper = g_new0 (ChDeviceQueueGetCalibrationHelper, 1);
1029 	helper->calibration = calibration;
1030 	helper->types = types;
1031 	helper->description = description;
1032 
1033 	buffer = g_new0 (guint8, 9*4 + 1 + CH_CALIBRATION_DESCRIPTION_LEN);
1034 	ch_device_queue_add_internal (device_queue,
1035 				      device,
1036 				      CH_CMD_GET_CALIBRATION,
1037 				      (guint8 *) &calibration_index,
1038 				      sizeof(guint16),
1039 				      (guint8 *) buffer,
1040 				      9*4 + 1 + CH_CALIBRATION_DESCRIPTION_LEN,
1041 				      g_free,
1042 				      ch_device_queue_buffer_to_get_calibration_cb,
1043 				      helper,
1044 				      g_free);
1045 }
1046 
1047 /**
1048  * ch_device_queue_set_calibration:
1049  * @device_queue:	A #ChDeviceQueue
1050  * @device:		A #GUsbDevice
1051  * @calibration_index:	The slot position
1052  * @calibration:	the 3x3 calibration matrix
1053  * @types:		The types the matrix supports
1054  * @description:	The description of the calibration
1055  *
1056  * Sets the calibration data.
1057  *
1058  * NOTE: This command is available on hardware version: 1 & 2
1059  *
1060  * Since: 0.1.29
1061  **/
1062 void
ch_device_queue_set_calibration(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 calibration_index,const CdMat3x3 * calibration,guint8 types,const gchar * description)1063 ch_device_queue_set_calibration (ChDeviceQueue *device_queue,
1064 				 GUsbDevice *device,
1065 				 guint16 calibration_index,
1066 				 const CdMat3x3 *calibration,
1067 				 guint8 types,
1068 				 const gchar *description)
1069 {
1070 	ChPackedFloat pf_tmp;
1071 	gdouble *calibration_tmp;
1072 	guint8 buffer[9*4 + 2 + 1 + CH_CALIBRATION_DESCRIPTION_LEN];
1073 	guint i;
1074 
1075 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1076 	g_return_if_fail (G_USB_IS_DEVICE (device));
1077 	g_return_if_fail (calibration_index < CH_CALIBRATION_MAX);
1078 	g_return_if_fail (calibration != NULL);
1079 	g_return_if_fail (description != NULL);
1080 
1081 	/* write index */
1082 	memcpy (buffer, &calibration_index, sizeof(guint16));
1083 
1084 	/* convert from float to signed value */
1085 	for (i = 0; i < 9; i++) {
1086 		calibration_tmp = cd_mat33_get_data (calibration);
1087 		ch_double_to_packed_float (calibration_tmp[i], &pf_tmp);
1088 		memcpy (&buffer[i*4 + 2], &pf_tmp, sizeof (pf_tmp));
1089 	}
1090 
1091 	/* write types */
1092 	buffer[9*4 + 2] = types;
1093 
1094 	/* write description */
1095 	strncpy ((gchar *) buffer + 9*4 + 2 + 1,
1096 		 description,
1097 		 CH_CALIBRATION_DESCRIPTION_LEN);
1098 
1099 	ch_device_queue_add (device_queue,
1100 			     device,
1101 			     CH_CMD_SET_CALIBRATION,
1102 			     (guint8 *) buffer,
1103 			     sizeof(buffer),
1104 			     NULL,
1105 			     0);
1106 }
1107 
1108 /**
1109  * ch_device_queue_set_calibration_ccmx:
1110  *
1111  * Since: 0.1.29
1112  **/
1113 gboolean
ch_device_queue_set_calibration_ccmx(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 calibration_index,CdIt8 * ccmx,GError ** error)1114 ch_device_queue_set_calibration_ccmx (ChDeviceQueue *device_queue,
1115 				      GUsbDevice *device,
1116 				      guint16 calibration_index,
1117 				      CdIt8 *ccmx,
1118 				      GError **error)
1119 {
1120 	const CdMat3x3 *calibration;
1121 	const gchar *description;
1122 	gdouble *calibration_tmp;
1123 	guint8 types = 0;
1124 	guint i;
1125 
1126 	g_return_val_if_fail (CD_IS_IT8 (ccmx), FALSE);
1127 	g_return_val_if_fail (CH_IS_DEVICE_QUEUE (device_queue), FALSE);
1128 	g_return_val_if_fail (G_USB_IS_DEVICE (device), FALSE);
1129 
1130 	/* ensure correct kind */
1131 	if (cd_it8_get_kind (ccmx) != CD_IT8_KIND_CCMX) {
1132 		g_set_error (error, 1, 0, "is not a CCMX file");
1133 		return FALSE;
1134 	}
1135 
1136 	/* get the supported display types */
1137 	if (cd_it8_has_option (ccmx, "TYPE_FACTORY")) {
1138 		types = CH_CALIBRATION_TYPE_ALL;
1139 	} else {
1140 		if (cd_it8_has_option (ccmx, "TYPE_LCD"))
1141 			types += CH_CALIBRATION_TYPE_LCD;
1142 		if (cd_it8_has_option (ccmx, "TYPE_LED"))
1143 			types += CH_CALIBRATION_TYPE_LED;
1144 		if (cd_it8_has_option (ccmx, "TYPE_CRT"))
1145 			types += CH_CALIBRATION_TYPE_CRT;
1146 		if (cd_it8_has_option (ccmx, "TYPE_PROJECTOR"))
1147 			types += CH_CALIBRATION_TYPE_PROJECTOR;
1148 	}
1149 
1150 	/* no types set in CCMX file */
1151 	if (types == 0) {
1152 		g_set_error_literal (error, 1, 0, "No TYPE_x in ccmx file");
1153 		return FALSE;
1154 	}
1155 
1156 	/* get the description from the ccmx file */
1157 	description = cd_it8_get_title (ccmx);
1158 	if (description == NULL) {
1159 		g_set_error_literal (error, 1, 0,
1160 				     "CCMX file does not have DISPLAY");
1161 		return FALSE;
1162 	}
1163 
1164 	/* get the values and check for sanity */
1165 	calibration = cd_it8_get_matrix (ccmx);
1166 	calibration_tmp = cd_mat33_get_data (calibration);
1167 	for (i = 0; i < 9; i++) {
1168 		if (calibration_tmp[i] < -100.0f ||
1169 		    calibration_tmp[i] > 100.0f) {
1170 			g_set_error (error, 1, 0,
1171 				     "Matrix value %u out of range %f",
1172 				     i, calibration_tmp[i]);
1173 			return FALSE;
1174 		}
1175 	}
1176 
1177 	/* set to HW */
1178 	ch_device_queue_set_calibration (device_queue,
1179 					 device,
1180 					 calibration_index,
1181 					 calibration,
1182 					 types,
1183 					 description);
1184 	return TRUE;
1185 }
1186 
1187 /**
1188  * ch_device_queue_write_firmware:
1189  * @device_queue:	A #ChDeviceQueue
1190  * @device:		A #GUsbDevice
1191  * @data:		Firmware binary data
1192  * @len:		Size of @data
1193  *
1194  * Writes new firmware to the device.
1195  *
1196  * NOTE: This command is available on hardware version: 1 & 2
1197  *
1198  * Since: 0.1.29
1199  **/
1200 void
ch_device_queue_write_firmware(ChDeviceQueue * device_queue,GUsbDevice * device,const guint8 * data,gsize len)1201 ch_device_queue_write_firmware (ChDeviceQueue	*device_queue,
1202 				GUsbDevice	*device,
1203 				const guint8	*data,
1204 				gsize		 len)
1205 {
1206 	gsize chunk_len;
1207 	guint idx;
1208 	guint16 runcode_addr;
1209 
1210 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1211 	g_return_if_fail (G_USB_IS_DEVICE (device));
1212 	g_return_if_fail (data != NULL);
1213 
1214 	/* erase flash */
1215 	runcode_addr = ch_device_get_runcode_address (device);
1216 	g_debug ("Erasing at %04x size %" G_GSIZE_FORMAT,
1217 		 runcode_addr, len);
1218 	ch_device_queue_erase_flash (device_queue,
1219 				     device,
1220 				     runcode_addr,
1221 				     len);
1222 
1223 	/* just write in 32 byte chunks, as we're sure that the firmware
1224 	 * image has been prepared to end on a 64 byte chunk with
1225 	 * colorhug-inhx32-to-bin >= 0.1.5 */
1226 	idx = 0;
1227 	chunk_len = CH_FLASH_TRANSFER_BLOCK_SIZE;
1228 	do {
1229 		if (idx + chunk_len > len)
1230 			chunk_len = len - idx;
1231 		g_debug ("Writing at %04x size %" G_GSIZE_FORMAT,
1232 			 runcode_addr + idx,
1233 			 chunk_len);
1234 		ch_device_queue_write_flash (device_queue,
1235 					     device,
1236 					     runcode_addr + idx,
1237 					     (guint8 *) data + idx,
1238 					     chunk_len);
1239 		idx += chunk_len;
1240 	} while (idx < len);
1241 }
1242 
1243 /**
1244  * ch_device_queue_verify_firmware:
1245  * @device_queue:	A #ChDeviceQueue
1246  * @device:		A #GUsbDevice
1247  * @data:		Firmware binary data
1248  * @len:		Size of @data
1249  *
1250  * Verifies firmware on the device.
1251  *
1252  * NOTE: This command is available on hardware version: 1 & 2
1253  *
1254  * Since: 0.1.29
1255  **/
1256 void
ch_device_queue_verify_firmware(ChDeviceQueue * device_queue,GUsbDevice * device,const guint8 * data,gsize len)1257 ch_device_queue_verify_firmware (ChDeviceQueue	*device_queue,
1258 				 GUsbDevice	*device,
1259 				 const guint8	*data,
1260 				 gsize		 len)
1261 {
1262 	gsize chunk_len;
1263 	guint idx;
1264 	guint16 runcode_addr;
1265 
1266 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1267 	g_return_if_fail (G_USB_IS_DEVICE (device));
1268 	g_return_if_fail (data != NULL);
1269 
1270 	/* read in 60 byte chunks */
1271 	idx = 0;
1272 	chunk_len = 60;
1273 	runcode_addr = ch_device_get_runcode_address (device);
1274 	do {
1275 		if (idx + chunk_len > len)
1276 			chunk_len = len - idx;
1277 		g_debug ("Verifying at %04x size %" G_GSIZE_FORMAT,
1278 			 runcode_addr + idx,
1279 			 chunk_len);
1280 		ch_device_queue_verify_flash (device_queue,
1281 					      device,
1282 					      runcode_addr + idx,
1283 					      data + idx,
1284 					      chunk_len);
1285 		idx += chunk_len;
1286 	} while (idx < len);
1287 }
1288 
1289 /**
1290  * ch_device_queue_read_firmware:
1291  * @device_queue:	A #ChDeviceQueue
1292  * @device:		A #GUsbDevice
1293  * @data:		Firmware binary data
1294  * @len:		Size of @data
1295  *
1296  * Reads firmware on the device.
1297  *
1298  * NOTE: This command is available on hardware version: 1 & 2
1299  *
1300  * Since: 1.2.11
1301  **/
1302 void
ch_device_queue_read_firmware(ChDeviceQueue * device_queue,GUsbDevice * device,guint8 ** data,gsize * len)1303 ch_device_queue_read_firmware (ChDeviceQueue	*device_queue,
1304 			       GUsbDevice	*device,
1305 			       guint8		**data,
1306 			       gsize		*len)
1307 {
1308 	gsize chunk_len = 60;
1309 	guint idx = 0;
1310 	guint16 runcode_addr;
1311 	guint8 *data_tmp;
1312 	gsize len_tmp;
1313 
1314 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1315 	g_return_if_fail (G_USB_IS_DEVICE (device));
1316 	g_return_if_fail (data != NULL);
1317 
1318 	/* assume firmware is padded */
1319 	len_tmp = ch_device_get_runcode_address (device);
1320 	data_tmp = g_malloc0 (len_tmp);
1321 
1322 	/* read in 60 byte chunks */
1323 	runcode_addr = ch_device_get_runcode_address (device);
1324 	do {
1325 		if (idx + chunk_len > len_tmp)
1326 			chunk_len = len_tmp - idx;
1327 		g_debug ("Reading at %04x size %" G_GSIZE_FORMAT,
1328 			 runcode_addr + idx,
1329 			 chunk_len);
1330 		ch_device_queue_read_flash (device_queue,
1331 					    device,
1332 					    runcode_addr + idx,
1333 					    data_tmp + idx,
1334 					    chunk_len);
1335 		idx += chunk_len;
1336 	} while (idx < len_tmp);
1337 
1338 	/* return */
1339 	*data = data_tmp;
1340 	if (len != NULL)
1341 		*len = len_tmp;
1342 }
1343 
1344 /**
1345  * ch_device_queue_clear_calibration:
1346  * @device_queue:	A #ChDeviceQueue
1347  * @device:		A #GUsbDevice
1348  * @calibration_index:	Slot
1349  *
1350  * Clears a calibration slot.
1351  *
1352  * NOTE: This command is available on hardware version: 1 & 2
1353  *
1354  * Since: 0.1.29
1355  **/
1356 void
ch_device_queue_clear_calibration(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 calibration_index)1357 ch_device_queue_clear_calibration (ChDeviceQueue *device_queue,
1358 				   GUsbDevice *device,
1359 				   guint16 calibration_index)
1360 {
1361 	guint8 buffer[9*4 + 2 + 1 + CH_CALIBRATION_DESCRIPTION_LEN];
1362 
1363 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1364 	g_return_if_fail (G_USB_IS_DEVICE (device));
1365 	g_return_if_fail (calibration_index < CH_CALIBRATION_MAX);
1366 
1367 	/* write index */
1368 	memcpy (buffer, &calibration_index, sizeof(guint16));
1369 
1370 	/* clear data */
1371 	memset (buffer + 2, 0xff, sizeof (buffer) - 2);
1372 
1373 	ch_device_queue_add (device_queue,
1374 			     device,
1375 			     CH_CMD_SET_CALIBRATION,
1376 			     (guint8 *) buffer,
1377 			     sizeof(buffer),
1378 			     NULL,
1379 			     0);
1380 }
1381 
1382 /**
1383  * ch_device_queue_buffer_to_double_cb:
1384  **/
1385 static gboolean
ch_device_queue_buffer_to_double_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)1386 ch_device_queue_buffer_to_double_cb (guint8 *output_buffer,
1387 				     gsize output_buffer_size,
1388 				     gpointer user_data,
1389 				     GError **error)
1390 {
1391 	ChPackedFloat pf_tmp;
1392 	gdouble tmp;
1393 
1394 	/* check buffer size */
1395 	if (output_buffer_size != sizeof (ChPackedFloat)) {
1396 		g_set_error (error, 1, 0,
1397 			     "Wrong output buffer size, expected %" G_GSIZE_FORMAT ", got %" G_GSIZE_FORMAT,
1398 			     sizeof (ChPackedFloat), output_buffer_size);
1399 		return FALSE;
1400 	}
1401 
1402 	/* convert back into floating point */
1403 	memcpy (&pf_tmp, output_buffer, sizeof (ChPackedFloat));
1404 	ch_packed_float_to_double (&pf_tmp, &tmp);
1405 	memcpy (user_data, &tmp, sizeof (tmp));
1406 	return TRUE;
1407 }
1408 
1409 /**
1410  * ch_device_queue_get_pre_scale:
1411  * @device_queue:	A #ChDeviceQueue
1412  * @device:		A #GUsbDevice
1413  * @pre_scale:		Pre-scale value
1414  *
1415  * Gets the pre scale value.
1416  *
1417  * NOTE: This command is available on hardware version: 1 & 2
1418  *
1419  * Since: 0.1.29
1420  **/
1421 void
ch_device_queue_get_pre_scale(ChDeviceQueue * device_queue,GUsbDevice * device,gdouble * pre_scale)1422 ch_device_queue_get_pre_scale (ChDeviceQueue *device_queue,
1423 			       GUsbDevice *device,
1424 			       gdouble *pre_scale)
1425 {
1426 	guint8 *buffer;
1427 
1428 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1429 	g_return_if_fail (G_USB_IS_DEVICE (device));
1430 	g_return_if_fail (pre_scale != NULL);
1431 
1432 	*pre_scale = 0.0f;
1433 	buffer = g_new0 (guint8, sizeof (ChPackedFloat));
1434 	ch_device_queue_add_internal (device_queue,
1435 				     device,
1436 				     CH_CMD_GET_PRE_SCALE,
1437 				     NULL,
1438 				     0,
1439 				     buffer,
1440 				     sizeof(ChPackedFloat),
1441 				     g_free,
1442 				     ch_device_queue_buffer_to_double_cb,
1443 				     pre_scale,
1444 				     NULL);
1445 }
1446 
1447 /**
1448  * ch_device_queue_set_pre_scale:
1449  * @device_queue:	A #ChDeviceQueue
1450  * @device:		A #GUsbDevice
1451  * @pre_scale:		Pre-scale value
1452  *
1453  * Sets the pre-scale value.
1454  *
1455  * NOTE: This command is available on hardware version: 1 & 2
1456  *
1457  * Since: 0.1.29
1458  **/
1459 void
ch_device_queue_set_pre_scale(ChDeviceQueue * device_queue,GUsbDevice * device,gdouble pre_scale)1460 ch_device_queue_set_pre_scale (ChDeviceQueue *device_queue,
1461 			       GUsbDevice *device,
1462 			       gdouble pre_scale)
1463 {
1464 	ChPackedFloat buffer;
1465 
1466 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1467 	g_return_if_fail (G_USB_IS_DEVICE (device));
1468 
1469 	/* convert from float to signed value */
1470 	ch_double_to_packed_float (pre_scale, &buffer);
1471 
1472 	ch_device_queue_add (device_queue,
1473 			     device,
1474 			     CH_CMD_SET_PRE_SCALE,
1475 			     (guint8 *) &buffer,
1476 			     sizeof(buffer),
1477 			     NULL,
1478 			     0);
1479 }
1480 
1481 /**
1482  * ch_device_queue_get_temperature:
1483  * @device_queue:	A #ChDeviceQueue
1484  * @device:		A #GUsbDevice
1485  * @temperature:	Temperature in Celcius
1486  *
1487  * Gets the device temperature.
1488  *
1489  * NOTE: This command is available on hardware version: 2
1490  *
1491  * Since: 0.1.29
1492  **/
1493 void
ch_device_queue_get_temperature(ChDeviceQueue * device_queue,GUsbDevice * device,gdouble * temperature)1494 ch_device_queue_get_temperature (ChDeviceQueue *device_queue,
1495 				 GUsbDevice *device,
1496 				 gdouble *temperature)
1497 {
1498 	guint8 *buffer;
1499 
1500 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1501 	g_return_if_fail (G_USB_IS_DEVICE (device));
1502 	g_return_if_fail (temperature != NULL);
1503 
1504 	*temperature = 0.0f;
1505 	buffer = g_new0 (guint8, sizeof (ChPackedFloat));
1506 	ch_device_queue_add_internal (device_queue,
1507 				     device,
1508 				     CH_CMD_GET_TEMPERATURE,
1509 				     NULL,
1510 				     0,
1511 				     buffer,
1512 				     sizeof(ChPackedFloat),
1513 				     g_free,
1514 				     ch_device_queue_buffer_to_double_cb,
1515 				     temperature,
1516 				     NULL);
1517 }
1518 
1519 /**
1520  * ch_device_queue_get_dac_value:
1521  * @device_queue:	A #ChDeviceQueue
1522  * @device:		A #GUsbDevice
1523  * @dac_value:		value between 0.0 and 0.99
1524  *
1525  * Gets the DAC value.
1526  *
1527  * NOTE: This command is available on hardware version: 2
1528  *
1529  * Since: 1.1.6
1530  **/
1531 void
ch_device_queue_get_dac_value(ChDeviceQueue * device_queue,GUsbDevice * device,gdouble * dac_value)1532 ch_device_queue_get_dac_value (ChDeviceQueue *device_queue,
1533 			       GUsbDevice *device,
1534 			       gdouble *dac_value)
1535 {
1536 	guint8 *buffer;
1537 
1538 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1539 	g_return_if_fail (G_USB_IS_DEVICE (device));
1540 	g_return_if_fail (dac_value != NULL);
1541 
1542 	*dac_value = 0.0f;
1543 	buffer = g_new0 (guint8, sizeof (ChPackedFloat));
1544 	ch_device_queue_add_internal (device_queue,
1545 				     device,
1546 				     CH_CMD_GET_DAC_VALUE,
1547 				     NULL,
1548 				     0,
1549 				     buffer,
1550 				     sizeof(ChPackedFloat),
1551 				     g_free,
1552 				     ch_device_queue_buffer_to_double_cb,
1553 				     dac_value,
1554 				     NULL);
1555 }
1556 
1557 /**
1558  * ch_device_queue_set_dac_value:
1559  * @device_queue:	A #ChDeviceQueue
1560  * @device:		A #GUsbDevice
1561  * @dac_value:		The DAC value
1562  *
1563  * Sets the post scale value.
1564  *
1565  * NOTE: This command is available on hardware version: 1 & 2
1566  *
1567  * Since: 1.1.6
1568  **/
1569 void
ch_device_queue_set_dac_value(ChDeviceQueue * device_queue,GUsbDevice * device,gdouble dac_value)1570 ch_device_queue_set_dac_value (ChDeviceQueue *device_queue,
1571 				GUsbDevice *device,
1572 				gdouble dac_value)
1573 {
1574 	ChPackedFloat buffer;
1575 
1576 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1577 	g_return_if_fail (G_USB_IS_DEVICE (device));
1578 
1579 	/* convert from float to signed value */
1580 	ch_double_to_packed_float (dac_value, &buffer);
1581 
1582 	ch_device_queue_add (device_queue,
1583 			     device,
1584 			     CH_CMD_SET_DAC_VALUE,
1585 			     (guint8 *) &buffer,
1586 			     sizeof(buffer),
1587 			     NULL,
1588 			     0);
1589 }
1590 
1591 /**
1592  * ch_device_queue_get_adc_vref_pos:
1593  * @device_queue:	A #ChDeviceQueue
1594  * @device:		A #GUsbDevice
1595  * @vref:		The voltage reference, ranging from 0.0 to 3.3V.
1596  *
1597  * Gets the ADC Vref+ calibration value.
1598  *
1599  * NOTE: This command is available on hardware version: 2
1600  *
1601  * Since: 0.1.31
1602  **/
1603 void
ch_device_queue_get_adc_vref_pos(ChDeviceQueue * device_queue,GUsbDevice * device,gdouble * vref)1604 ch_device_queue_get_adc_vref_pos (ChDeviceQueue *device_queue,
1605 				  GUsbDevice *device,
1606 				  gdouble *vref)
1607 {
1608 	guint8 *buffer;
1609 
1610 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1611 	g_return_if_fail (G_USB_IS_DEVICE (device));
1612 	g_return_if_fail (vref != NULL);
1613 
1614 	*vref = 0.0f;
1615 	buffer = g_new0 (guint8, sizeof (ChPackedFloat));
1616 	ch_device_queue_add_internal (device_queue,
1617 				     device,
1618 				     CH_CMD_GET_ADC_CALIBRATION_POS,
1619 				     NULL,
1620 				     0,
1621 				     buffer,
1622 				     sizeof(ChPackedFloat),
1623 				     g_free,
1624 				     ch_device_queue_buffer_to_double_cb,
1625 				     vref,
1626 				     NULL);
1627 }
1628 
1629 /**
1630  * ch_device_queue_get_adc_vref_neg:
1631  * @device_queue:	A #ChDeviceQueue
1632  * @device:		A #GUsbDevice
1633  * @vref:		The voltage reference, ranging from 0.0 to 3.3V.
1634  *
1635  * Gets the ADC Vref- calibration value.
1636  *
1637  * NOTE: This command is available on hardware version: 2
1638  *
1639  * Since: 0.1.31
1640  **/
1641 void
ch_device_queue_get_adc_vref_neg(ChDeviceQueue * device_queue,GUsbDevice * device,gdouble * vref)1642 ch_device_queue_get_adc_vref_neg (ChDeviceQueue *device_queue,
1643 				  GUsbDevice *device,
1644 				  gdouble *vref)
1645 {
1646 	guint8 *buffer;
1647 
1648 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1649 	g_return_if_fail (G_USB_IS_DEVICE (device));
1650 	g_return_if_fail (vref != NULL);
1651 
1652 	*vref = 0.0f;
1653 	buffer = g_new0 (guint8, sizeof (ChPackedFloat));
1654 	ch_device_queue_add_internal (device_queue,
1655 				     device,
1656 				     CH_CMD_GET_ADC_CALIBRATION_NEG,
1657 				     NULL,
1658 				     0,
1659 				     buffer,
1660 				     sizeof(ChPackedFloat),
1661 				     g_free,
1662 				     ch_device_queue_buffer_to_double_cb,
1663 				     vref,
1664 				     NULL);
1665 }
1666 
1667 /**
1668  * ch_device_queue_take_reading_spectral:
1669  * @device_queue:	A #ChDeviceQueue
1670  * @device:		A #GUsbDevice
1671  * @sram_addr:		The SRAM location where the data is held
1672  *
1673  * Takes a raw spectral reading.
1674  *
1675  * NOTE: This command is available on hardware version: 2
1676  *
1677  * Since: 0.1.31
1678  **/
1679 void
ch_device_queue_take_reading_spectral(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 * sram_addr)1680 ch_device_queue_take_reading_spectral (ChDeviceQueue *device_queue,
1681 				       GUsbDevice *device,
1682 				       guint16 *sram_addr)
1683 {
1684 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1685 	g_return_if_fail (G_USB_IS_DEVICE (device));
1686 	g_return_if_fail (sram_addr != NULL);
1687 
1688 	*sram_addr = 0x0000;
1689 	ch_device_queue_add (device_queue,
1690 			     device,
1691 			     CH_CMD_TAKE_READING_SPECTRAL,
1692 			     NULL,
1693 			     0,
1694 			     (guint8 *) sram_addr,
1695 			     sizeof (guint16));
1696 }
1697 
1698 /**
1699  * ch_device_queue_get_ccd_calibration:
1700  * @device_queue:	A #ChDeviceQueue
1701  * @device:		A #GUsbDevice
1702  * @indexes:		An array of red, green, blue indexes
1703  *
1704  * Gets the CCD spectral calibration indexes. These are "pointers" to specific
1705  * spectral peaks returned by the CCD.
1706  *
1707  * NOTE: This command is available on hardware version: 2
1708  *
1709  * Since: 0.1.31
1710  **/
1711 void
ch_device_queue_get_ccd_calibration(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 * indexes)1712 ch_device_queue_get_ccd_calibration (ChDeviceQueue *device_queue,
1713 				     GUsbDevice *device,
1714 				     guint16 *indexes)
1715 {
1716 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1717 	g_return_if_fail (G_USB_IS_DEVICE (device));
1718 	g_return_if_fail (indexes != NULL);
1719 
1720 	/* three uint16_t values */
1721 	ch_device_queue_add (device_queue,
1722 			     device,
1723 			     CH_CMD_GET_CCD_CALIBRATION,
1724 			     NULL,
1725 			     0,
1726 			     (guint8 *) indexes,
1727 			     3 * sizeof (guint16));
1728 }
1729 
1730 /**
1731  * ch_device_queue_set_ccd_calibration:
1732  * @device_queue:	A #ChDeviceQueue
1733  * @device:		A #GUsbDevice
1734  * @indexes:		An array of red, green, blue indexes
1735  *
1736  * Sets the CCD spectral calibration indexes. These are "pointers" to specific
1737  * spectral peaks returned by the CCD.
1738  *
1739  * NOTE: This command is available on hardware version: 2
1740  *
1741  * Since: 0.1.31
1742  **/
1743 void
ch_device_queue_set_ccd_calibration(ChDeviceQueue * device_queue,GUsbDevice * device,const guint16 * indexes)1744 ch_device_queue_set_ccd_calibration (ChDeviceQueue *device_queue,
1745 				     GUsbDevice *device,
1746 				     const guint16 *indexes)
1747 {
1748 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1749 	g_return_if_fail (G_USB_IS_DEVICE (device));
1750 	g_return_if_fail (indexes != NULL);
1751 	g_return_if_fail (indexes[0] < CH_CCD_SPECTRAL_RESOLUTION);
1752 	g_return_if_fail (indexes[1] < CH_CCD_SPECTRAL_RESOLUTION);
1753 	g_return_if_fail (indexes[2] < CH_CCD_SPECTRAL_RESOLUTION);
1754 
1755 	/* three uint16_t values */
1756 	ch_device_queue_add (device_queue,
1757 			     device,
1758 			     CH_CMD_SET_CCD_CALIBRATION,
1759 			     (const guint8 *) indexes,
1760 			     3 * sizeof (guint16),
1761 			     NULL,
1762 			     0);
1763 }
1764 
1765 /**
1766  * ch_device_queue_get_post_scale:
1767  * @device_queue:	A #ChDeviceQueue
1768  * @device:		A #GUsbDevice
1769  * @post_scale:		The post-scale value
1770  *
1771  * Gets the post scale value.
1772  *
1773  * NOTE: This command is available on hardware version: 1 & 2
1774  *
1775  * Since: 0.1.29
1776  **/
1777 void
ch_device_queue_get_post_scale(ChDeviceQueue * device_queue,GUsbDevice * device,gdouble * post_scale)1778 ch_device_queue_get_post_scale (ChDeviceQueue *device_queue,
1779 				GUsbDevice *device,
1780 				gdouble *post_scale)
1781 {
1782 	guint8 *buffer;
1783 
1784 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1785 	g_return_if_fail (G_USB_IS_DEVICE (device));
1786 	g_return_if_fail (post_scale != NULL);
1787 
1788 	*post_scale = 0.0f;
1789 	buffer = g_new0 (guint8, sizeof (ChPackedFloat));
1790 	ch_device_queue_add_internal (device_queue,
1791 				      device,
1792 				      CH_CMD_GET_POST_SCALE,
1793 				      NULL,
1794 				      0,
1795 				      buffer,
1796 				      sizeof(ChPackedFloat),
1797 				      g_free,
1798 				      ch_device_queue_buffer_to_double_cb,
1799 				      post_scale,
1800 				      NULL);
1801 }
1802 
1803 /**
1804  * ch_device_queue_set_post_scale:
1805  * @device_queue:	A #ChDeviceQueue
1806  * @device:		A #GUsbDevice
1807  * @post_scale:		The post-scale value
1808  *
1809  * Sets the post scale value.
1810  *
1811  * NOTE: This command is available on hardware version: 1 & 2
1812  *
1813  * Since: 0.1.29
1814  **/
1815 void
ch_device_queue_set_post_scale(ChDeviceQueue * device_queue,GUsbDevice * device,gdouble post_scale)1816 ch_device_queue_set_post_scale (ChDeviceQueue *device_queue,
1817 				GUsbDevice *device,
1818 				gdouble post_scale)
1819 {
1820 	ChPackedFloat buffer;
1821 
1822 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1823 	g_return_if_fail (G_USB_IS_DEVICE (device));
1824 
1825 	/* convert from float to signed value */
1826 	ch_double_to_packed_float (post_scale, &buffer);
1827 
1828 	ch_device_queue_add (device_queue,
1829 			     device,
1830 			     CH_CMD_SET_POST_SCALE,
1831 			     (guint8 *) &buffer,
1832 			     sizeof(buffer),
1833 			     NULL,
1834 			     0);
1835 }
1836 
1837 /**
1838  * ch_device_queue_get_serial_number:
1839  * @device_queue:	A #ChDeviceQueue
1840  * @device:		A #GUsbDevice
1841  * @serial_number:	The device serial number
1842  *
1843  * Gets the device serial number.
1844  *
1845  * NOTE: This command is available on hardware version: 1 & 2
1846  *
1847  * Since: 0.1.29
1848  **/
1849 void
ch_device_queue_get_serial_number(ChDeviceQueue * device_queue,GUsbDevice * device,guint32 * serial_number)1850 ch_device_queue_get_serial_number (ChDeviceQueue *device_queue,
1851 				   GUsbDevice *device,
1852 				   guint32 *serial_number)
1853 {
1854 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1855 	g_return_if_fail (G_USB_IS_DEVICE (device));
1856 	g_return_if_fail (serial_number != NULL);
1857 
1858 	*serial_number = 0;
1859 	ch_device_queue_add_internal (device_queue,
1860 				      device,
1861 				      CH_CMD_GET_SERIAL_NUMBER,
1862 				      NULL,
1863 				      0,
1864 				      (guint8 *) serial_number,
1865 				      sizeof(guint32),
1866 				      NULL,
1867 				      ch_device_queue_buffer_uint32_from_le_cb,
1868 				      NULL,
1869 				      NULL);
1870 }
1871 
1872 /**
1873  * ch_device_queue_set_serial_number:
1874  * @device_queue:	A #ChDeviceQueue
1875  * @device:		A #GUsbDevice
1876  * @serial_number:	The device serial number
1877  *
1878  * Sets the device serial number.
1879  *
1880  * NOTE: This command is available on hardware version: 1 & 2
1881  *
1882  * Since: 0.1.29
1883  **/
1884 void
ch_device_queue_set_serial_number(ChDeviceQueue * device_queue,GUsbDevice * device,guint32 serial_number)1885 ch_device_queue_set_serial_number (ChDeviceQueue *device_queue,
1886 				   GUsbDevice *device,
1887 				   guint32 serial_number)
1888 {
1889 	guint32 serial_le;
1890 
1891 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1892 	g_return_if_fail (G_USB_IS_DEVICE (device));
1893 	g_return_if_fail (serial_number > 0);
1894 
1895 	serial_le = GUINT32_TO_LE (serial_number);
1896 
1897 	ch_device_queue_add (device_queue,
1898 			     device,
1899 			     CH_CMD_SET_SERIAL_NUMBER,
1900 			     (const guint8 *) &serial_le,
1901 			     sizeof(serial_le),
1902 			     NULL,
1903 			     0);
1904 }
1905 
1906 /**
1907  * ch_device_queue_get_leds:
1908  * @device_queue:	A #ChDeviceQueue
1909  * @device:		A #GUsbDevice
1910  * @leds:		The LED bitfield
1911  *
1912  * Gets the LED status.
1913  *
1914  * NOTE: This command is available on hardware version: 1 & 2
1915  *
1916  * Since: 0.1.29
1917  **/
1918 void
ch_device_queue_get_leds(ChDeviceQueue * device_queue,GUsbDevice * device,guint8 * leds)1919 ch_device_queue_get_leds (ChDeviceQueue *device_queue,
1920 			  GUsbDevice *device,
1921 			  guint8 *leds)
1922 {
1923 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1924 	g_return_if_fail (G_USB_IS_DEVICE (device));
1925 	g_return_if_fail (leds != NULL);
1926 
1927 	*leds = 0;
1928 	ch_device_queue_add (device_queue,
1929 			     device,
1930 			     CH_CMD_GET_LEDS,
1931 			     NULL,
1932 			     0,
1933 			     leds,
1934 			     1);
1935 }
1936 
1937 /**
1938  * ch_device_queue_set_leds:
1939  * @device_queue:	A #ChDeviceQueue
1940  * @device:		A #GUsbDevice
1941  * @leds:		The LEDs bitfield
1942  * @repeat:		Sets the number of times to repeat the pattern
1943  * @on_time:		Set the on time
1944  * @off_time:		Set the off time
1945  *
1946  * Sets the LED status.
1947  *
1948  * NOTE: This command is available on hardware version: 1 & 2
1949  *
1950  * Since: 0.1.29
1951  **/
1952 void
ch_device_queue_set_leds(ChDeviceQueue * device_queue,GUsbDevice * device,guint8 leds,guint8 repeat,guint8 on_time,guint8 off_time)1953 ch_device_queue_set_leds (ChDeviceQueue *device_queue,
1954 			  GUsbDevice *device,
1955 			  guint8 leds,
1956 			  guint8 repeat,
1957 			  guint8 on_time,
1958 			  guint8 off_time)
1959 {
1960 	guint8 buffer[4];
1961 
1962 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1963 	g_return_if_fail (G_USB_IS_DEVICE (device));
1964 	g_return_if_fail (leds < 0x08);
1965 
1966 	buffer[0] = leds;
1967 	buffer[1] = repeat;
1968 	buffer[2] = on_time;
1969 	buffer[3] = off_time;
1970 	ch_device_queue_add (device_queue,
1971 			     device,
1972 			     CH_CMD_SET_LEDS,
1973 			     (const guint8 *) buffer,
1974 			     sizeof (buffer),
1975 			     NULL,
1976 			     0);
1977 }
1978 
1979 /**
1980  * ch_device_queue_get_pcb_errata:
1981  * @device_queue:	A #ChDeviceQueue
1982  * @device:		A #GUsbDevice
1983  * @pcb_errata:		The PCB errata, e.g. %CH_PCB_ERRATA_SWAPPED_LEDS
1984  *
1985  * Gets the PCB errata level.
1986  *
1987  * NOTE: This command is available on hardware version: 1 & 2
1988  *
1989  * Since: 0.1.29
1990  **/
1991 void
ch_device_queue_get_pcb_errata(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 * pcb_errata)1992 ch_device_queue_get_pcb_errata (ChDeviceQueue *device_queue,
1993 				GUsbDevice *device,
1994 				guint16 *pcb_errata)
1995 {
1996 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
1997 	g_return_if_fail (G_USB_IS_DEVICE (device));
1998 	g_return_if_fail (pcb_errata != NULL);
1999 
2000 	*pcb_errata = CH_PCB_ERRATA_NONE;
2001 	ch_device_queue_add (device_queue,
2002 			     device,
2003 			     CH_CMD_GET_PCB_ERRATA,
2004 			     NULL,
2005 			     0,
2006 			     (guint8 *) pcb_errata,
2007 			     sizeof (guint16));
2008 }
2009 
2010 /**
2011  * ch_device_queue_set_pcb_errata:
2012  * @device_queue:	A #ChDeviceQueue
2013  * @device:		A #GUsbDevice
2014  * @pcb_errata:		The PCB errata, e.g. %CH_PCB_ERRATA_SWAPPED_LEDS
2015  *
2016  * Sets the PCB board errata.
2017  *
2018  * NOTE: This command is available on hardware version: 1 & 2
2019  *
2020  * Since: 0.1.29
2021  **/
2022 void
ch_device_queue_set_pcb_errata(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 pcb_errata)2023 ch_device_queue_set_pcb_errata (ChDeviceQueue *device_queue,
2024 				GUsbDevice *device,
2025 				guint16 pcb_errata)
2026 {
2027 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2028 	g_return_if_fail (G_USB_IS_DEVICE (device));
2029 
2030 	ch_device_queue_add (device_queue,
2031 			     device,
2032 			     CH_CMD_SET_PCB_ERRATA,
2033 			     (const guint8 *) &pcb_errata,
2034 			     sizeof (guint16),
2035 			     NULL,
2036 			     0);
2037 }
2038 
2039 /**
2040  * ch_device_queue_get_remote_hash:
2041  * @device_queue:	A #ChDeviceQueue
2042  * @device:		A #GUsbDevice
2043  * @remote_hash:	A #ChSha1
2044  *
2045  * Gets the remote hash stored on the device.
2046  *
2047  * NOTE: This command is available on hardware version: 1 & 2
2048  *
2049  * Since: 0.1.29
2050  **/
2051 void
ch_device_queue_get_remote_hash(ChDeviceQueue * device_queue,GUsbDevice * device,ChSha1 * remote_hash)2052 ch_device_queue_get_remote_hash (ChDeviceQueue *device_queue,
2053 				 GUsbDevice *device,
2054 				 ChSha1 *remote_hash)
2055 {
2056 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2057 	g_return_if_fail (G_USB_IS_DEVICE (device));
2058 	g_return_if_fail (remote_hash != NULL);
2059 
2060 	ch_device_queue_add (device_queue,
2061 			     device,
2062 			     CH_CMD_GET_REMOTE_HASH,
2063 			     NULL,
2064 			     0,
2065 			     (guint8 *) remote_hash,
2066 			     sizeof (ChSha1));
2067 }
2068 
2069 /**
2070  * ch_device_queue_set_remote_hash:
2071  * @device_queue:	A #ChDeviceQueue
2072  * @device:		A #GUsbDevice
2073  * @remote_hash:	A #ChSha1
2074  *
2075  * Sets the remote hash on the device.
2076  *
2077  * NOTE: This command is available on hardware version: 1 & 2
2078  *
2079  * Since: 0.1.29
2080  **/
2081 void
ch_device_queue_set_remote_hash(ChDeviceQueue * device_queue,GUsbDevice * device,ChSha1 * remote_hash)2082 ch_device_queue_set_remote_hash (ChDeviceQueue *device_queue,
2083 				 GUsbDevice *device,
2084 				 ChSha1 *remote_hash)
2085 {
2086 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2087 	g_return_if_fail (G_USB_IS_DEVICE (device));
2088 
2089 	ch_device_queue_add (device_queue,
2090 			     device,
2091 			     CH_CMD_SET_REMOTE_HASH,
2092 			     (const guint8 *) remote_hash,
2093 			     sizeof (ChSha1),
2094 			     NULL,
2095 			     0);
2096 }
2097 
2098 /**
2099  * ch_device_queue_write_eeprom:
2100  * @device_queue:	A #ChDeviceQueue
2101  * @device:		A #GUsbDevice
2102  * @magic:		The magic sekret string
2103  *
2104  * Writes values to the firmware to be set at device startup.
2105  *
2106  * NOTE: This command is available on hardware version: 1 & 2
2107  *
2108  * Since: 0.1.29
2109  **/
2110 void
ch_device_queue_write_eeprom(ChDeviceQueue * device_queue,GUsbDevice * device,const gchar * magic)2111 ch_device_queue_write_eeprom (ChDeviceQueue *device_queue,
2112 			      GUsbDevice *device,
2113 			      const gchar *magic)
2114 {
2115 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2116 	g_return_if_fail (G_USB_IS_DEVICE (device));
2117 	g_return_if_fail (magic != NULL);
2118 
2119 	ch_device_queue_add (device_queue,
2120 			     device,
2121 			     CH_CMD_WRITE_EEPROM,
2122 			     (const guint8 *) magic,
2123 			     strlen(magic),
2124 			     NULL,
2125 			     0);
2126 }
2127 
2128 /**
2129  * ch_device_queue_buffer_dark_offsets_cb:
2130  **/
2131 static gboolean
ch_device_queue_buffer_dark_offsets_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)2132 ch_device_queue_buffer_dark_offsets_cb (guint8 *output_buffer,
2133 					gsize output_buffer_size,
2134 					gpointer user_data,
2135 					GError **error)
2136 {
2137 	CdColorRGB *value = (CdColorRGB *) user_data;
2138 	guint16 tmp;
2139 
2140 	/* check buffer size */
2141 	if (output_buffer_size != sizeof (guint16) * 3) {
2142 		g_set_error (error, 1, 0,
2143 			     "Wrong output buffer size, expected %" G_GSIZE_FORMAT ", got %" G_GSIZE_FORMAT,
2144 			     sizeof (guint16) * 3, output_buffer_size);
2145 		return FALSE;
2146 	}
2147 
2148 	/* convert back into floating point */
2149 	tmp = cd_buffer_read_uint16_le (output_buffer + 0);
2150 	value->R = (gdouble) tmp / (gdouble) 0xffff;
2151 	tmp = cd_buffer_read_uint16_le (output_buffer + 2);
2152 	value->G = (gdouble) tmp / (gdouble) 0xffff;
2153 	tmp = cd_buffer_read_uint16_le (output_buffer + 4);
2154 	value->B = (gdouble) tmp / (gdouble) 0xffff;
2155 	return TRUE;
2156 }
2157 
2158 /**
2159  * ch_device_queue_get_dark_offsets:
2160  * @device_queue:	A #ChDeviceQueue
2161  * @device:		A #GUsbDevice
2162  * @value:		A #CdColorRGB
2163  *
2164  * Gets the device dark offsets.
2165  *
2166  * NOTE: This command is available on hardware version: 1 & 2
2167  *
2168  * Since: 0.1.29
2169  **/
2170 void
ch_device_queue_get_dark_offsets(ChDeviceQueue * device_queue,GUsbDevice * device,CdColorRGB * value)2171 ch_device_queue_get_dark_offsets (ChDeviceQueue *device_queue,
2172 				  GUsbDevice *device,
2173 				  CdColorRGB *value)
2174 {
2175 	guint8 *buffer;
2176 
2177 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2178 	g_return_if_fail (G_USB_IS_DEVICE (device));
2179 	g_return_if_fail (value != NULL);
2180 
2181 	buffer = g_new0 (guint8, sizeof(guint16) * 3);
2182 	ch_device_queue_add_internal (device_queue,
2183 				      device,
2184 				      CH_CMD_GET_DARK_OFFSETS,
2185 				      NULL,
2186 				      0,
2187 				      buffer,
2188 				      sizeof(guint16) * 3,
2189 				      g_free,
2190 				      ch_device_queue_buffer_dark_offsets_cb,
2191 				      value,
2192 				      NULL);
2193 }
2194 
2195 /**
2196  * ch_device_queue_set_dark_offsets:
2197  * @device_queue:	A #ChDeviceQueue
2198  * @device:		A #GUsbDevice
2199  * @value:		A #CdColorRGB
2200  *
2201  * Sets the device dark offsets.
2202  *
2203  * NOTE: This command is available on hardware version: 1 & 2
2204  *
2205  * Since: 0.1.29
2206  **/
2207 void
ch_device_queue_set_dark_offsets(ChDeviceQueue * device_queue,GUsbDevice * device,CdColorRGB * value)2208 ch_device_queue_set_dark_offsets (ChDeviceQueue *device_queue,
2209 				  GUsbDevice *device,
2210 				  CdColorRGB *value)
2211 {
2212 	guint16 buffer[3];
2213 
2214 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2215 	g_return_if_fail (G_USB_IS_DEVICE (device));
2216 
2217 	buffer[0] = value->R * (gdouble) 0xffff;
2218 	buffer[1] = value->G * (gdouble) 0xffff;
2219 	buffer[2] = value->B * (gdouble) 0xffff;
2220 	ch_device_queue_add (device_queue,
2221 			     device,
2222 			     CH_CMD_SET_DARK_OFFSETS,
2223 			     (const guint8 *) buffer,
2224 			     sizeof(buffer),
2225 			     NULL,
2226 			     0);
2227 }
2228 
2229 /**
2230  * ch_device_queue_take_reading_raw:
2231  * @device_queue:	A #ChDeviceQueue
2232  * @device:		A #GUsbDevice
2233  * @take_reading:	A raw reading value
2234  *
2235  * Take a raw reading from the sensor.
2236  *
2237  * NOTE: This command is available on hardware version: 1 & 2
2238  *
2239  * Since: 0.1.29
2240  **/
2241 void
ch_device_queue_take_reading_raw(ChDeviceQueue * device_queue,GUsbDevice * device,guint32 * take_reading)2242 ch_device_queue_take_reading_raw (ChDeviceQueue *device_queue,
2243 				  GUsbDevice *device,
2244 				  guint32 *take_reading)
2245 {
2246 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2247 	g_return_if_fail (G_USB_IS_DEVICE (device));
2248 	g_return_if_fail (take_reading != NULL);
2249 
2250 	ch_device_queue_add_internal (device_queue,
2251 				      device,
2252 				      CH_CMD_TAKE_READING_RAW,
2253 				      NULL,
2254 				      0,
2255 				      (guint8 *) take_reading,
2256 				      sizeof(guint32),
2257 				      NULL,
2258 				      ch_device_queue_buffer_uint32_from_le_cb,
2259 				      NULL,
2260 				      NULL);
2261 }
2262 
2263 /**
2264  * ch_device_queue_buffer_triple_rgb_cb:
2265  **/
2266 static gboolean
ch_device_queue_buffer_triple_rgb_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)2267 ch_device_queue_buffer_triple_rgb_cb (guint8 *output_buffer,
2268 				      gsize output_buffer_size,
2269 				      gpointer user_data,
2270 				      GError **error)
2271 {
2272 	CdColorRGB *value = (CdColorRGB *) user_data;
2273 	ChPackedFloat tmp;
2274 
2275 	/* check buffer size */
2276 	if (output_buffer_size != sizeof (ChPackedFloat) * 3) {
2277 		g_set_error (error, 1, 0,
2278 			     "Wrong output buffer size, expected %" G_GSIZE_FORMAT ", got %" G_GSIZE_FORMAT,
2279 			     sizeof (ChPackedFloat) * 3, output_buffer_size);
2280 		return FALSE;
2281 	}
2282 
2283 	/* convert back into floating point */
2284 	memcpy (&tmp, output_buffer + 0, sizeof (ChPackedFloat));
2285 	ch_packed_float_to_double (&tmp, &value->R);
2286 	memcpy (&tmp, output_buffer + 4, sizeof (ChPackedFloat));
2287 	ch_packed_float_to_double (&tmp, &value->G);
2288 	memcpy (&tmp, output_buffer + 8, sizeof (ChPackedFloat));
2289 	ch_packed_float_to_double (&tmp, &value->B);
2290 	return TRUE;
2291 }
2292 
2293 /**
2294  * ch_device_queue_take_readings:
2295  * @device_queue:	A #ChDeviceQueue
2296  * @device:		A #GUsbDevice
2297  * @value:		The #CdColorRGB of the raw reading
2298  *
2299  * Take a RGB triplet of readings from the sensor without applying the
2300  * calibration matrix.
2301  *
2302  * NOTE: This command is available on hardware version: 1 & 2
2303  *
2304  * Since: 0.1.29
2305  **/
2306 void
ch_device_queue_take_readings(ChDeviceQueue * device_queue,GUsbDevice * device,CdColorRGB * value)2307 ch_device_queue_take_readings (ChDeviceQueue *device_queue,
2308 			       GUsbDevice *device,
2309 			       CdColorRGB *value)
2310 {
2311 	guint8 *buffer;
2312 
2313 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2314 	g_return_if_fail (G_USB_IS_DEVICE (device));
2315 	g_return_if_fail (value != NULL);
2316 
2317 	buffer = g_new0 (guint8, sizeof(ChPackedFloat) * 3);
2318 	ch_device_queue_add_internal (device_queue,
2319 				      device,
2320 				      CH_CMD_TAKE_READINGS,
2321 				      NULL,
2322 				      0,
2323 				      buffer,
2324 				      sizeof(ChPackedFloat) * 3,
2325 				      g_free,
2326 				      ch_device_queue_buffer_triple_rgb_cb,
2327 				      value,
2328 				      NULL);
2329 }
2330 
2331 /**
2332  * ch_device_queue_buffer_triple_xyz_cb:
2333  **/
2334 static gboolean
ch_device_queue_buffer_triple_xyz_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)2335 ch_device_queue_buffer_triple_xyz_cb (guint8 *output_buffer,
2336 				      gsize output_buffer_size,
2337 				      gpointer user_data,
2338 				      GError **error)
2339 {
2340 	CdColorXYZ *value = (CdColorXYZ *) user_data;
2341 	ChPackedFloat tmp;
2342 
2343 	/* check buffer size */
2344 	if (output_buffer_size != sizeof (ChPackedFloat) * 3) {
2345 		g_set_error (error, 1, 0,
2346 			     "Wrong output buffer size, expected %" G_GSIZE_FORMAT ", got %" G_GSIZE_FORMAT,
2347 			     sizeof (ChPackedFloat) * 3, output_buffer_size);
2348 		return FALSE;
2349 	}
2350 
2351 	/* convert back into floating point */
2352 	memcpy (&tmp, output_buffer + 0, sizeof (ChPackedFloat));
2353 	ch_packed_float_to_double (&tmp, &value->X);
2354 	memcpy (&tmp, output_buffer + 4, sizeof (ChPackedFloat));
2355 	ch_packed_float_to_double (&tmp, &value->Y);
2356 	memcpy (&tmp, output_buffer + 8, sizeof (ChPackedFloat));
2357 	ch_packed_float_to_double (&tmp, &value->Z);
2358 	return TRUE;
2359 }
2360 
2361 /**
2362  * ch_device_queue_take_readings_xyz:
2363  * @device_queue:	A #ChDeviceQueue
2364  * @device:		A #GUsbDevice
2365  * @value:		The #CdColorXYZ for a given calibration slot
2366  *
2367  * Take an XYZ fully cooked reading from the sensor.
2368  *
2369  * NOTE: This command is available on hardware version: 1 & 2
2370  *
2371  * Since: 0.1.29
2372  **/
2373 void
ch_device_queue_take_readings_xyz(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 calibration_index,CdColorXYZ * value)2374 ch_device_queue_take_readings_xyz (ChDeviceQueue *device_queue,
2375 				   GUsbDevice *device,
2376 				   guint16 calibration_index,
2377 				   CdColorXYZ *value)
2378 {
2379 	guint8 *buffer;
2380 
2381 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2382 	g_return_if_fail (G_USB_IS_DEVICE (device));
2383 	g_return_if_fail (value != NULL);
2384 
2385 	buffer = g_new0 (guint8, sizeof(ChPackedFloat) * 3);
2386 	ch_device_queue_add_internal (device_queue,
2387 				     device,
2388 				     CH_CMD_TAKE_READING_XYZ,
2389 				     (guint8 *) &calibration_index,
2390 				     sizeof(guint16),
2391 				     buffer,
2392 				     sizeof(ChPackedFloat) * 3,
2393 				     g_free,
2394 				     ch_device_queue_buffer_triple_xyz_cb,
2395 				     value,
2396 				     NULL);
2397 }
2398 
2399 /**
2400  * ch_device_queue_reset:
2401  * @device_queue:	A #ChDeviceQueue
2402  * @device:		A #GUsbDevice
2403  *
2404  * Resets the device back to bootloader mode.
2405  *
2406  * NOTE: This command is available on hardware version: 1 & 2
2407  *
2408  * Since: 0.1.29
2409  **/
2410 void
ch_device_queue_reset(ChDeviceQueue * device_queue,GUsbDevice * device)2411 ch_device_queue_reset (ChDeviceQueue *device_queue,
2412 		       GUsbDevice *device)
2413 {
2414 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2415 	g_return_if_fail (G_USB_IS_DEVICE (device));
2416 
2417 	ch_device_queue_add (device_queue,
2418 			     device,
2419 			     CH_CMD_RESET,
2420 			     NULL,
2421 			     0,
2422 			     NULL,
2423 			     0);
2424 }
2425 
2426 /**
2427  * ch_device_queue_calculate_checksum:
2428  **/
2429 static guint8
ch_device_queue_calculate_checksum(const guint8 * data,gsize len)2430 ch_device_queue_calculate_checksum (const guint8 *data,
2431 				    gsize len)
2432 {
2433 	guint8 checksum = 0xff;
2434 	guint i;
2435 	for (i = 0; i < len; i++)
2436 		checksum ^= data[i];
2437 	return checksum;
2438 }
2439 
2440 /**
2441  * ch_device_queue_write_flash:
2442  * @device_queue:	A #ChDeviceQueue
2443  * @device:		A #GUsbDevice
2444  * @address:		The device EEPROM address
2445  * @data:		Binary data
2446  * @len:		The length of @data
2447  *
2448  * Write flash code to the device.
2449  *
2450  * NOTE: This command is available on hardware version: 1 & 2
2451  *
2452  * Since: 0.1.29
2453  **/
2454 void
ch_device_queue_write_flash(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 address,const guint8 * data,gsize len)2455 ch_device_queue_write_flash (ChDeviceQueue *device_queue,
2456 			     GUsbDevice *device,
2457 			     guint16 address,
2458 			     const guint8 *data,
2459 			     gsize len)
2460 {
2461 	guint16 addr_le;
2462 	guint8 buffer_tx[64];
2463 
2464 	/* set address, length, checksum, data */
2465 	addr_le = GUINT16_TO_LE (address);
2466 	memcpy (buffer_tx + 0, &addr_le, 2);
2467 	buffer_tx[2] = len;
2468 	buffer_tx[3] = ch_device_queue_calculate_checksum (data, len);
2469 	memcpy (buffer_tx + 4, data, len);
2470 
2471 	ch_device_queue_add (device_queue,
2472 			     device,
2473 			     CH_CMD_WRITE_FLASH,
2474 			     buffer_tx,
2475 			     len + 4,
2476 			     NULL,
2477 			     0);
2478 }
2479 
2480 /* tiny helper */
2481 typedef struct {
2482 	guint16		 address;
2483 	guint8		*data;
2484 	gsize		 len;
2485 } ChDeviceQueueReadFlashHelper;
2486 
2487 /**
2488  * ch_device_queue_buffer_read_flash_cb:
2489  **/
2490 static gboolean
ch_device_queue_buffer_read_flash_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)2491 ch_device_queue_buffer_read_flash_cb (guint8 *output_buffer,
2492 				      gsize output_buffer_size,
2493 				      gpointer user_data,
2494 				      GError **error)
2495 {
2496 	ChDeviceQueueReadFlashHelper *helper = (ChDeviceQueueReadFlashHelper *) user_data;
2497 	guint8 expected_checksum;
2498 
2499 	/* check buffer size */
2500 	if (output_buffer_size != helper->len + 1) {
2501 		g_set_error (error, 1, 0,
2502 			     "Wrong output buffer size, expected %" G_GSIZE_FORMAT ", got %" G_GSIZE_FORMAT,
2503 			     helper->len + 1, output_buffer_size);
2504 		return FALSE;
2505 	}
2506 
2507 	/* verify checksum */
2508 	expected_checksum = ch_device_queue_calculate_checksum (output_buffer + 1,
2509 								helper->len);
2510 	if (output_buffer[0] != expected_checksum) {
2511 		g_set_error (error, 1, 0,
2512 			     "Checksum @0x%04x invalid",
2513 			     helper->address);
2514 		return FALSE;
2515 	}
2516 
2517 	/* copy data to final location */
2518 	memcpy (helper->data, output_buffer + 1, helper->len);
2519 	return TRUE;
2520 }
2521 
2522 /**
2523  * ch_device_queue_read_flash:
2524  * @device_queue:	A #ChDeviceQueue
2525  * @device:		A #GUsbDevice
2526  * @address:		The device EEPROM address
2527  * @data:		Binary data
2528  * @len:		The length of @data
2529  *
2530  * Read flash code from the device.
2531  *
2532  * NOTE: This command is available on hardware version: 1 & 2
2533  *
2534  * Since: 0.1.29
2535  **/
2536 void
ch_device_queue_read_flash(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 address,guint8 * data,gsize len)2537 ch_device_queue_read_flash (ChDeviceQueue *device_queue,
2538 			    GUsbDevice *device,
2539 			    guint16 address,
2540 			    guint8 *data,
2541 			    gsize len)
2542 {
2543 	ChDeviceQueueReadFlashHelper *helper;
2544 	guint16 addr_le;
2545 	guint8 *buffer;
2546 	guint8 buffer_tx[3];
2547 
2548 	/* set address, length, checksum, data */
2549 	addr_le = GUINT16_TO_LE (address);
2550 	memcpy (buffer_tx + 0, &addr_le, 2);
2551 	buffer_tx[2] = len;
2552 
2553 	/* create a helper structure as the checksum needs an extra
2554 	 * byte for the checksum */
2555 	helper = g_new0 (ChDeviceQueueReadFlashHelper, 1);
2556 	helper->data = data;
2557 	helper->len = len;
2558 	helper->address = address;
2559 
2560 	buffer = g_new0 (guint8, len + 1);
2561 	ch_device_queue_add_internal (device_queue,
2562 				      device,
2563 				      CH_CMD_READ_FLASH,
2564 				      buffer_tx,
2565 				      sizeof(buffer_tx),
2566 				      buffer,
2567 				      len + 1,
2568 				      g_free,
2569 				      ch_device_queue_buffer_read_flash_cb,
2570 				      helper,
2571 				      g_free);
2572 }
2573 
2574 /**
2575  * ch_device_queue_buffer_verify_flash_cb:
2576  **/
2577 static gboolean
ch_device_queue_buffer_verify_flash_cb(guint8 * output_buffer,gsize output_buffer_size,gpointer user_data,GError ** error)2578 ch_device_queue_buffer_verify_flash_cb (guint8 *output_buffer,
2579 					gsize output_buffer_size,
2580 					gpointer user_data,
2581 					GError **error)
2582 {
2583 	ChDeviceQueueReadFlashHelper *helper = (ChDeviceQueueReadFlashHelper *) user_data;
2584 	guint16 i;
2585 	guint8 expected_checksum;
2586 
2587 	/* check buffer size */
2588 	if (output_buffer_size != helper->len + 1) {
2589 		g_set_error (error, 1, 0,
2590 			     "Wrong output buffer size, expected %" G_GSIZE_FORMAT ", got %" G_GSIZE_FORMAT,
2591 			     helper->len + 1, output_buffer_size);
2592 		return FALSE;
2593 	}
2594 
2595 	/* verify checksum */
2596 	expected_checksum = ch_device_queue_calculate_checksum (output_buffer + 1,
2597 								helper->len);
2598 	if (output_buffer[0] != expected_checksum) {
2599 		g_set_error (error, 1, 0,
2600 			     "Checksum @0x%04x invalid",
2601 			     helper->address);
2602 		return FALSE;
2603 	}
2604 
2605 	/* verify data */
2606 	if (memcmp (helper->data, output_buffer + 1, helper->len) != 0) {
2607 		for (i = 0; i < helper->len; i++) {
2608 			if (helper->data[i] != output_buffer[i + 1])
2609 				break;
2610 		}
2611 		g_set_error (error, 1, 0,
2612 			     "Failed to verify at @0x%04x",
2613 			     (guint) (helper->address + i));
2614 		return FALSE;
2615 	}
2616 	return TRUE;
2617 }
2618 
2619 static void
ch_device_queue_verify_flash_helper_destroy(gpointer data)2620 ch_device_queue_verify_flash_helper_destroy (gpointer data)
2621 {
2622 	ChDeviceQueueReadFlashHelper *helper = (ChDeviceQueueReadFlashHelper *) data;
2623 	g_free (helper->data);
2624 	g_free (helper);
2625 }
2626 
2627 /**
2628  * ch_device_queue_verify_flash:
2629  * @device_queue:	A #ChDeviceQueue
2630  * @device:		A #GUsbDevice
2631  * @address:		The device EEPROM address
2632  * @data:		Binary data
2633  * @len:		The length of @data
2634  *
2635  * Verify flash code from the device.
2636  *
2637  * NOTE: This command is available on hardware version: 1 & 2
2638  *
2639  * Since: 0.1.29
2640  **/
2641 void
ch_device_queue_verify_flash(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 address,const guint8 * data,gsize len)2642 ch_device_queue_verify_flash (ChDeviceQueue *device_queue,
2643 			      GUsbDevice *device,
2644 			      guint16 address,
2645 			      const guint8 *data,
2646 			      gsize len)
2647 {
2648 	ChDeviceQueueReadFlashHelper *helper;
2649 	guint16 addr_le;
2650 	guint8 *buffer;
2651 	guint8 buffer_tx[3];
2652 
2653 	/* set address, length, checksum, data */
2654 	addr_le = GUINT16_TO_LE (address);
2655 	memcpy (buffer_tx + 0, &addr_le, 2);
2656 	buffer_tx[2] = len;
2657 
2658 	/* create a helper structure as the checksum needs an extra
2659 	 * byte for the checksum */
2660 	helper = g_new0 (ChDeviceQueueReadFlashHelper, 1);
2661 	helper->data = g_memdup (data, len + 1);
2662 	helper->len = len;
2663 	helper->address = address;
2664 
2665 	buffer = g_new0 (guint8, len + 1);
2666 	ch_device_queue_add_internal (device_queue,
2667 				      device,
2668 				      CH_CMD_READ_FLASH,
2669 				      buffer_tx,
2670 				      sizeof(buffer_tx),
2671 				      buffer,
2672 				      len + 1,
2673 				      g_free,
2674 				      ch_device_queue_buffer_verify_flash_cb,
2675 				      helper,
2676 				      ch_device_queue_verify_flash_helper_destroy);
2677 }
2678 
2679 /**
2680  * ch_device_queue_erase_flash:
2681  * @device_queue:	A #ChDeviceQueue
2682  * @device:		A #GUsbDevice
2683  * @address:		The device EEPROM address
2684  * @len:		The length of @data
2685  *
2686  * Erase program code on the device.
2687  *
2688  * NOTE: This command is available on hardware version: 1 & 2
2689  *
2690  * Since: 0.1.29
2691  **/
2692 void
ch_device_queue_erase_flash(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 address,gsize len)2693 ch_device_queue_erase_flash (ChDeviceQueue *device_queue,
2694 			     GUsbDevice *device,
2695 			     guint16 address,
2696 			     gsize len)
2697 {
2698 	guint8 buffer_tx[4];
2699 	guint16 addr_le;
2700 	guint16 len_le;
2701 
2702 	/* set address, length, checksum, data */
2703 	addr_le = GUINT16_TO_LE (address);
2704 	memcpy (buffer_tx + 0, &addr_le, 2);
2705 	len_le = GUINT16_TO_LE (len);
2706 	memcpy (buffer_tx + 2, &len_le, 2);
2707 
2708 	ch_device_queue_add (device_queue,
2709 			     device,
2710 			     CH_CMD_ERASE_FLASH,
2711 			     buffer_tx,
2712 			     sizeof(buffer_tx),
2713 			     NULL,
2714 			     0);
2715 }
2716 
2717 /**
2718  * ch_device_queue_set_flash_success:
2719  * @device_queue:	A #ChDeviceQueue
2720  * @device:		A #GUsbDevice
2721  * @value:		Success value
2722  *
2723  * Sets the firmware flash sucess value.
2724  * Be careful using this function as misuse can result in a 'bricked'
2725  * ColorHug device.
2726  *
2727  * NOTE: This command is available on hardware version: 1 & 2
2728  *
2729  * Since: 0.1.29
2730  **/
2731 void
ch_device_queue_set_flash_success(ChDeviceQueue * device_queue,GUsbDevice * device,guint8 value)2732 ch_device_queue_set_flash_success (ChDeviceQueue *device_queue,
2733 				   GUsbDevice *device,
2734 				   guint8 value)
2735 {
2736 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2737 	g_return_if_fail (G_USB_IS_DEVICE (device));
2738 
2739 	/* set flash success true */
2740 	ch_device_queue_add (device_queue,
2741 			     device,
2742 			     CH_CMD_SET_FLASH_SUCCESS,
2743 			     (guint8 *) &value, 1,
2744 			     NULL, 0);
2745 }
2746 
2747 /**
2748  * ch_device_queue_boot_flash:
2749  * @device_queue:	A #ChDeviceQueue
2750  * @device:		A #GUsbDevice
2751  *
2752  * Boots the device from bootloader to firmware mode.
2753  *
2754  * NOTE: This command is available on hardware version: 1 & 2
2755  *
2756  * Since: 0.1.29
2757  **/
2758 void
ch_device_queue_boot_flash(ChDeviceQueue * device_queue,GUsbDevice * device)2759 ch_device_queue_boot_flash (ChDeviceQueue *device_queue,
2760 			    GUsbDevice *device)
2761 {
2762 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2763 	g_return_if_fail (G_USB_IS_DEVICE (device));
2764 
2765 	/* boot into new code */
2766 	ch_device_queue_add (device_queue,
2767 			     device,
2768 			     CH_CMD_BOOT_FLASH,
2769 			     NULL, 0,
2770 			     NULL, 0);
2771 }
2772 
2773 /**
2774  * ch_device_queue_self_test:
2775  * @device_queue:	A #ChDeviceQueue
2776  * @device:		A #GUsbDevice
2777  *
2778  * Performs some self tests on the device.
2779  *
2780  * NOTE: This command is available on hardware version: 1 & 2
2781  *
2782  * Since: 0.1.29
2783  **/
2784 void
ch_device_queue_self_test(ChDeviceQueue * device_queue,GUsbDevice * device)2785 ch_device_queue_self_test (ChDeviceQueue *device_queue,
2786 			    GUsbDevice *device)
2787 {
2788 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2789 	g_return_if_fail (G_USB_IS_DEVICE (device));
2790 
2791 	/* do a really simple self test */
2792 	ch_device_queue_add (device_queue,
2793 			     device,
2794 			     CH_CMD_SELF_TEST,
2795 			     NULL, 0,
2796 			     NULL, 0);
2797 }
2798 
2799 /**
2800  * ch_device_queue_get_hardware_version:
2801  * @device_queue:	A #ChDeviceQueue
2802  * @device:		A #GUsbDevice
2803  * @hw_version:		The hardware version
2804  *
2805  * Gets the hardware version.
2806  *
2807  * NOTE: This command is available on hardware version: 1 & 2
2808  *
2809  * Since: 0.1.29
2810  **/
2811 void
ch_device_queue_get_hardware_version(ChDeviceQueue * device_queue,GUsbDevice * device,guint8 * hw_version)2812 ch_device_queue_get_hardware_version (ChDeviceQueue *device_queue,
2813 				      GUsbDevice *device,
2814 				      guint8 *hw_version)
2815 {
2816 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2817 	g_return_if_fail (G_USB_IS_DEVICE (device));
2818 	g_return_if_fail (hw_version != NULL);
2819 
2820 	ch_device_queue_add (device_queue,
2821 			     device,
2822 			     CH_CMD_GET_HARDWARE_VERSION,
2823 			     NULL,
2824 			     0,
2825 			     hw_version,
2826 			     1);
2827 }
2828 
2829 /**
2830  * ch_device_queue_get_owner_name:
2831  * @device_queue:	A #ChDeviceQueue
2832  * @device:		A #GUsbDevice
2833  * @name:		The owner name
2834  *
2835  * Gets the owner name.
2836  *
2837  * NOTE: This command is available on hardware version: 1 & 2
2838  *
2839  * Since: 0.1.29
2840  **/
2841 void
ch_device_queue_get_owner_name(ChDeviceQueue * device_queue,GUsbDevice * device,gchar * name)2842 ch_device_queue_get_owner_name (ChDeviceQueue *device_queue,
2843 				GUsbDevice *device,
2844 				gchar *name)
2845 {
2846 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2847 	g_return_if_fail (G_USB_IS_DEVICE (device));
2848 	g_return_if_fail (name != NULL);
2849 
2850 	ch_device_queue_add (device_queue,
2851 			     device,
2852 			     CH_CMD_GET_OWNER_NAME,
2853 			     NULL,
2854 			     0,
2855 			     (guint8 *) name,
2856 			     sizeof(gchar) * CH_OWNER_LENGTH_MAX);
2857 	name[CH_OWNER_LENGTH_MAX-1] = 0;
2858 }
2859 
2860 /**
2861  * ch_device_queue_set_owner_name:
2862  * @device_queue:	A #ChDeviceQueue
2863  * @device:		A #GUsbDevice
2864  * @name:		The owner name
2865  *
2866  * Sets the owner name.
2867  *
2868  * NOTE: This command is available on hardware version: 1 & 2
2869  *
2870  * Since: 0.1.29
2871  **/
2872 void
ch_device_queue_set_owner_name(ChDeviceQueue * device_queue,GUsbDevice * device,const gchar * name)2873 ch_device_queue_set_owner_name (ChDeviceQueue *device_queue,
2874 				GUsbDevice *device,
2875 				const gchar *name)
2876 {
2877 	gchar buf[CH_OWNER_LENGTH_MAX];
2878 
2879 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2880 	g_return_if_fail (G_USB_IS_DEVICE (device));
2881 	g_return_if_fail (name != NULL);
2882 
2883 	memset(buf, 0, CH_OWNER_LENGTH_MAX);
2884 	g_strlcpy(buf, name, CH_OWNER_LENGTH_MAX);
2885 
2886 	ch_device_queue_add (device_queue,
2887 			     device,
2888 			     CH_CMD_SET_OWNER_NAME,
2889 			     (const guint8 *) buf,
2890 			     sizeof(gchar) * CH_OWNER_LENGTH_MAX,
2891 			     NULL,
2892 			     0);
2893 }
2894 
2895 /**
2896  * ch_device_queue_get_owner_email:
2897  * @device_queue:	A #ChDeviceQueue
2898  * @device:		A #GUsbDevice
2899  * @email:		An email address
2900  *
2901  * Gets the owner email address.
2902  *
2903  * NOTE: This command is available on hardware version: 1 & 2
2904  *
2905  * Since: 0.1.29
2906  **/
2907 void
ch_device_queue_get_owner_email(ChDeviceQueue * device_queue,GUsbDevice * device,gchar * email)2908 ch_device_queue_get_owner_email (ChDeviceQueue *device_queue,
2909 				 GUsbDevice *device,
2910 				 gchar *email)
2911 {
2912 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2913 	g_return_if_fail (G_USB_IS_DEVICE (device));
2914 	g_return_if_fail (email != NULL);
2915 
2916 	ch_device_queue_add (device_queue,
2917 			     device,
2918 			     CH_CMD_GET_OWNER_EMAIL,
2919 			     NULL,
2920 			     0,
2921 			     (guint8 *) email,
2922 			     sizeof(gchar) * CH_OWNER_LENGTH_MAX);
2923 	email[CH_OWNER_LENGTH_MAX-1] = 0;
2924 }
2925 
2926 /**
2927  * ch_device_queue_set_owner_email:
2928  * @device_queue:	A #ChDeviceQueue
2929  * @device:		A #GUsbDevice
2930  * @email:		An email address
2931  *
2932  * Sets the owner email address.
2933  *
2934  * NOTE: This command is available on hardware version: 1 & 2
2935  *
2936  * Since: 0.1.29
2937  **/
2938 void
ch_device_queue_set_owner_email(ChDeviceQueue * device_queue,GUsbDevice * device,const gchar * email)2939 ch_device_queue_set_owner_email (ChDeviceQueue *device_queue,
2940 				 GUsbDevice *device,
2941 				 const gchar *email)
2942 {
2943 	gchar buf[CH_OWNER_LENGTH_MAX];
2944 
2945 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2946 	g_return_if_fail (G_USB_IS_DEVICE (device));
2947 	g_return_if_fail (email != NULL);
2948 
2949 	memset (buf, 0, CH_OWNER_LENGTH_MAX);
2950 	g_strlcpy (buf, email, CH_OWNER_LENGTH_MAX);
2951 
2952 	ch_device_queue_add (device_queue,
2953 			     device,
2954 			     CH_CMD_SET_OWNER_EMAIL,
2955 			     (const guint8 *) buf,
2956 			     sizeof(gchar) * CH_OWNER_LENGTH_MAX,
2957 			     NULL,
2958 			     0);
2959 }
2960 
2961 /**
2962  * ch_device_queue_take_reading_array:
2963  * @device_queue:	A #ChDeviceQueue
2964  * @device:		A #GUsbDevice
2965  * @reading_array:	An array of raw readings
2966  *
2967  * Get an array of raw readings in quick succession.
2968  *
2969  * NOTE: This command is available on hardware version: 1 & 2
2970  *
2971  * Since: 0.1.29
2972  **/
2973 void
ch_device_queue_take_reading_array(ChDeviceQueue * device_queue,GUsbDevice * device,guint8 * reading_array)2974 ch_device_queue_take_reading_array (ChDeviceQueue *device_queue,
2975 				    GUsbDevice *device,
2976 				    guint8 *reading_array)
2977 {
2978 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
2979 	g_return_if_fail (G_USB_IS_DEVICE (device));
2980 	g_return_if_fail (reading_array != NULL);
2981 
2982 	ch_device_queue_add (device_queue,
2983 			     device,
2984 			     CH_CMD_TAKE_READING_ARRAY,
2985 			     NULL,
2986 			     0,
2987 			     reading_array,
2988 			     30);
2989 }
2990 
2991 /**
2992  * ch_device_queue_get_measure_mode:
2993  * @device_queue:	A #ChDeviceQueue
2994  * @device:		A #GUsbDevice
2995  * @measure_mode:	The #ChMeasureMode, e.g. %CH_MEASURE_MODE_DURATION
2996  *
2997  * Gets the measurement mode.
2998  *
2999  * NOTE: This command is available on hardware version: 1 & 2
3000  *
3001  * Since: 0.1.29
3002  **/
3003 void
ch_device_queue_get_measure_mode(ChDeviceQueue * device_queue,GUsbDevice * device,ChMeasureMode * measure_mode)3004 ch_device_queue_get_measure_mode (ChDeviceQueue *device_queue,
3005 				  GUsbDevice *device,
3006 				  ChMeasureMode *measure_mode)
3007 {
3008 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
3009 	g_return_if_fail (G_USB_IS_DEVICE (device));
3010 	g_return_if_fail (measure_mode != NULL);
3011 
3012 	ch_device_queue_add (device_queue,
3013 			     device,
3014 			     CH_CMD_GET_MEASURE_MODE,
3015 			     NULL,
3016 			     0,
3017 			     (guint8 *) measure_mode,
3018 			     1);
3019 }
3020 
3021 /**
3022  * ch_device_queue_set_measure_mode:
3023  * @device_queue:	A #ChDeviceQueue
3024  * @device:		A #GUsbDevice
3025  * @measure_mode:	The #ChMeasureMode, e.g. %CH_MEASURE_MODE_DURATION
3026  *
3027  * Sets the measurement mode.
3028  *
3029  * NOTE: This command is available on hardware version: 1 & 2
3030  *
3031  * Since: 0.1.29
3032  **/
3033 void
ch_device_queue_set_measure_mode(ChDeviceQueue * device_queue,GUsbDevice * device,ChMeasureMode measure_mode)3034 ch_device_queue_set_measure_mode (ChDeviceQueue *device_queue,
3035 				  GUsbDevice *device,
3036 				  ChMeasureMode measure_mode)
3037 {
3038 	guint8 tmp = measure_mode;
3039 
3040 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
3041 	g_return_if_fail (G_USB_IS_DEVICE (device));
3042 
3043 	ch_device_queue_add (device_queue,
3044 			     device,
3045 			     CH_CMD_SET_MEASURE_MODE,
3046 			     &tmp,
3047 			     1,
3048 			     NULL,
3049 			     0);
3050 }
3051 
3052 /**
3053  * ch_device_queue_write_sram_internal:
3054  **/
3055 static void
ch_device_queue_write_sram_internal(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 address,const guint8 * data,gsize len)3056 ch_device_queue_write_sram_internal (ChDeviceQueue *device_queue,
3057 				     GUsbDevice *device,
3058 				     guint16 address,
3059 				     const guint8 *data,
3060 				     gsize len)
3061 {
3062 	guint16 addr_le;
3063 	guint8 buffer_tx[CH_USB_HID_EP_SIZE];
3064 
3065 	/* set address, length, checksum, data */
3066 	addr_le = GUINT16_TO_LE (address);
3067 	memcpy (buffer_tx + 0, &addr_le, 2);
3068 	buffer_tx[2] = len;
3069 	memcpy (buffer_tx + 3, data, len);
3070 
3071 	ch_device_queue_add (device_queue,
3072 			     device,
3073 			     CH_CMD_WRITE_SRAM,
3074 			     buffer_tx,
3075 			     len + 3,
3076 			     NULL,
3077 			     0);
3078 }
3079 
3080 /**
3081  * ch_device_queue_write_sram:
3082  * @device_queue:	A #ChDeviceQueue
3083  * @device:		A #GUsbDevice
3084  * @address:		The device memory address
3085  * @data:		The binary data
3086  * @len:		Size of @data
3087  *
3088  * Writes binary data to the SRAM.
3089  *
3090  * NOTE: This command is available on hardware version: 2
3091  *
3092  * Since: 0.1.29
3093  **/
3094 void
ch_device_queue_write_sram(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 address,const guint8 * data,gsize len)3095 ch_device_queue_write_sram (ChDeviceQueue *device_queue,
3096 			    GUsbDevice *device,
3097 			    guint16 address,
3098 			    const guint8 *data,
3099 			    gsize len)
3100 {
3101 	gsize chunk_len = 60;
3102 	guint idx = 0;
3103 
3104 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
3105 	g_return_if_fail (G_USB_IS_DEVICE (device));
3106 	g_return_if_fail (data != NULL);
3107 	g_return_if_fail (len > 0);
3108 
3109 	/* write in 60 byte chunks */
3110 	do {
3111 		if (idx + chunk_len > len)
3112 			chunk_len = len - idx;
3113 		g_debug ("Writing SRAM at %04x size %" G_GSIZE_FORMAT,
3114 			 idx, chunk_len);
3115 		ch_device_queue_write_sram_internal (device_queue,
3116 						     device,
3117 						     idx,
3118 						     data + idx,
3119 						     chunk_len);
3120 		idx += chunk_len;
3121 	} while (idx < len);
3122 }
3123 
3124 /**
3125  * ch_device_queue_read_sram_internal:
3126  **/
3127 static void
ch_device_queue_read_sram_internal(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 address,guint8 * data,gsize len)3128 ch_device_queue_read_sram_internal (ChDeviceQueue *device_queue,
3129 				    GUsbDevice *device,
3130 				    guint16 address,
3131 				    guint8 *data,
3132 				    gsize len)
3133 {
3134 	guint16 addr_le;
3135 	guint8 buffer_tx[3];
3136 
3137 	/* set address, length, data */
3138 	addr_le = GUINT16_TO_LE (address);
3139 	memcpy (buffer_tx + 0, &addr_le, 2);
3140 	buffer_tx[2] = len;
3141 
3142 	ch_device_queue_add (device_queue,
3143 			     device,
3144 			     CH_CMD_READ_SRAM,
3145 			     buffer_tx,
3146 			     sizeof(buffer_tx),
3147 			     data,
3148 			     len);
3149 }
3150 
3151 /**
3152  * ch_device_queue_read_sram:
3153  * @device_queue:	A #ChDeviceQueue
3154  * @device:		A #GUsbDevice
3155  * @address:		The device memory address
3156  * @data:		The binary data
3157  * @len:		Size of @data
3158  *
3159  * Reads binary data from the SRAM.
3160  *
3161  * NOTE: This command is available on hardware version: 2
3162  *
3163  * Since: 0.1.29
3164  **/
3165 void
ch_device_queue_read_sram(ChDeviceQueue * device_queue,GUsbDevice * device,guint16 address,guint8 * data,gsize len)3166 ch_device_queue_read_sram (ChDeviceQueue *device_queue,
3167 			   GUsbDevice *device,
3168 			   guint16 address,
3169 			   guint8 *data,
3170 			   gsize len)
3171 {
3172 	gsize chunk_len = 60;
3173 	guint idx = 0;
3174 
3175 	g_return_if_fail (CH_IS_DEVICE_QUEUE (device_queue));
3176 	g_return_if_fail (G_USB_IS_DEVICE (device));
3177 	g_return_if_fail (data != NULL);
3178 	g_return_if_fail (len > 0);
3179 
3180 	/* write in 60 byte chunks */
3181 	do {
3182 		if (idx + chunk_len > len)
3183 			chunk_len = len - idx;
3184 		g_debug ("Reading SRAM at %04x size %" G_GSIZE_FORMAT,
3185 			 idx, chunk_len);
3186 		ch_device_queue_read_sram_internal (device_queue,
3187 						    device,
3188 						    idx,
3189 						    data + idx,
3190 						    chunk_len);
3191 		idx += chunk_len;
3192 	} while (idx < len);
3193 }
3194 
3195 /**********************************************************************/
3196 
3197 /**
3198  * ch_device_queue_class_init:
3199  **/
3200 static void
ch_device_queue_class_init(ChDeviceQueueClass * klass)3201 ch_device_queue_class_init (ChDeviceQueueClass *klass)
3202 {
3203 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
3204 	object_class->finalize = ch_device_queue_finalize;
3205 
3206 	/**
3207 	 * ChDeviceQueueClass::device-failed:
3208 	 * @device_queue: the #ChDeviceQueue instance that emitted the signal
3209 	 * @device: the device that failed
3210 	 * @error_message: the error that caused the failure
3211 	 *
3212 	 * The ::device-failed signal is emitted when a device has failed.
3213 	 **/
3214 	signals[SIGNAL_DEVICE_FAILED] =
3215 		g_signal_new ("device-failed",
3216 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
3217 			      G_STRUCT_OFFSET (ChDeviceQueueClass, device_failed),
3218 			      NULL, NULL, g_cclosure_marshal_generic,
3219 			      G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_STRING);
3220 
3221 	/**
3222 	 * ChDeviceQueueClass::progress-changed:
3223 	 * @device_queue: the #ChDeviceQueue instance that emitted the signal
3224 	 * @percentage: the percentage complete the action is
3225 	 * @error_message: the error that caused the failure
3226 	 *
3227 	 * The ::progress-changed signal is emitted when a the commands
3228 	 * are being submitted.
3229 	 **/
3230 	signals[SIGNAL_PROGRESS_CHANGED] =
3231 		g_signal_new ("progress-changed",
3232 			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
3233 			      G_STRUCT_OFFSET (ChDeviceQueueClass, progress_changed),
3234 			      NULL, NULL, g_cclosure_marshal_generic,
3235 			      G_TYPE_NONE, 1, G_TYPE_UINT);
3236 }
3237 
3238 /**
3239  * ch_device_queue_init:
3240  **/
3241 static void
ch_device_queue_init(ChDeviceQueue * device_queue)3242 ch_device_queue_init (ChDeviceQueue *device_queue)
3243 {
3244 	ChDeviceQueuePrivate *priv = GET_PRIVATE (device_queue);
3245 	priv->data_array = g_ptr_array_new_with_free_func ((GDestroyNotify) ch_device_queue_data_free);
3246 	priv->devices_in_use = g_hash_table_new_full (g_str_hash,
3247 								    g_str_equal,
3248 								    g_free,
3249 								    NULL);
3250 }
3251 
3252 /**
3253  * ch_device_queue_finalize:
3254  **/
3255 static void
ch_device_queue_finalize(GObject * object)3256 ch_device_queue_finalize (GObject *object)
3257 {
3258 	ChDeviceQueue *device_queue = CH_DEVICE_QUEUE (object);
3259 	ChDeviceQueuePrivate *priv = GET_PRIVATE (device_queue);
3260 
3261 	g_ptr_array_unref (priv->data_array);
3262 	g_hash_table_unref (priv->devices_in_use);
3263 
3264 	G_OBJECT_CLASS (ch_device_queue_parent_class)->finalize (object);
3265 }
3266 
3267 /**
3268  * ch_device_queue_new:
3269  *
3270  * Since: 0.1.29
3271  **/
3272 ChDeviceQueue *
ch_device_queue_new(void)3273 ch_device_queue_new (void)
3274 {
3275 	ChDeviceQueue *device_queue;
3276 	device_queue = g_object_new (CH_TYPE_DEVICE_QUEUE, NULL);
3277 	return CH_DEVICE_QUEUE (device_queue);
3278 }
3279