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