20 static void error(const char *fmt, ...)
26 error = g_error_new_valist(
27 g_quark_from_string("divelog"),
28 DIVE_ERROR_PARSE, fmt, args);
34 typedef struct device_data_t {
37 device_devinfo_t devinfo;
41 static parser_status_t create_parser(device_data_t *devdata, parser_t **parser)
43 switch (devdata->type) {
44 case DEVICE_TYPE_SUUNTO_SOLUTION:
45 return suunto_solution_parser_create(parser);
47 case DEVICE_TYPE_SUUNTO_EON:
48 return suunto_eon_parser_create(parser, 0);
50 case DEVICE_TYPE_SUUNTO_VYPER:
51 if (devdata->devinfo.model == 0x01)
52 return suunto_eon_parser_create(parser, 1);
53 return suunto_vyper_parser_create(parser);
55 case DEVICE_TYPE_SUUNTO_VYPER2:
56 case DEVICE_TYPE_SUUNTO_D9:
57 return suunto_d9_parser_create(parser, devdata->devinfo.model);
59 case DEVICE_TYPE_UWATEC_ALADIN:
60 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
61 return uwatec_memomouse_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
63 case DEVICE_TYPE_UWATEC_SMART:
64 return uwatec_smart_parser_create(parser, devdata->devinfo.model, devdata->clock.devtime, devdata->clock.systime);
66 case DEVICE_TYPE_REEFNET_SENSUS:
67 return reefnet_sensus_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
69 case DEVICE_TYPE_REEFNET_SENSUSPRO:
70 return reefnet_sensuspro_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
72 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
73 return reefnet_sensusultra_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
75 case DEVICE_TYPE_OCEANIC_VTPRO:
76 return oceanic_vtpro_parser_create(parser);
78 case DEVICE_TYPE_OCEANIC_VEO250:
79 return oceanic_veo250_parser_create(parser, devdata->devinfo.model);
81 case DEVICE_TYPE_OCEANIC_ATOM2:
82 return oceanic_atom2_parser_create(parser, devdata->devinfo.model);
84 case DEVICE_TYPE_MARES_NEMO:
85 case DEVICE_TYPE_MARES_PUCK:
86 return mares_nemo_parser_create(parser, devdata->devinfo.model);
88 case DEVICE_TYPE_MARES_ICONHD:
89 return mares_iconhd_parser_create(parser);
91 case DEVICE_TYPE_HW_OSTC:
92 return hw_ostc_parser_create(parser);
94 case DEVICE_TYPE_CRESSI_EDY:
95 case DEVICE_TYPE_ZEAGLE_N2ITION3:
96 return cressi_edy_parser_create(parser, devdata->devinfo.model);
98 case DEVICE_TYPE_ATOMICS_COBALT:
99 return atomics_cobalt_parser_create(parser);
102 return PARSER_STATUS_ERROR;
106 static int parse_gasmixes(parser_t *parser, int ngases)
110 for (i = 0; i < ngases; i++) {
112 gasmix_t gasmix = {0};
114 rc = parser_get_field(parser, FIELD_TYPE_GASMIX, i, &gasmix);
115 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED)
123 gasmix.helium * 100.0,
124 gasmix.oxygen * 100.0,
125 gasmix.nitrogen * 100.0);
127 return PARSER_STATUS_SUCCESS;
131 sample_cb (parser_sample_type_t type, parser_sample_value_t value, void *userdata)
134 static const char *events[] = {
135 "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
136 "violation", "bookmark", "surface", "safety stop", "gaschange",
137 "safety stop (voluntary)", "safety stop (mandatory)", "deepstop",
138 "ceiling (safety stop)", "unknown", "divetime", "maxdepth",
139 "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning"};
142 case SAMPLE_TYPE_TIME:
143 printf("<sample>\n");
144 printf(" <time>%02u:%02u</time>\n", value.time / 60, value.time % 60);
146 case SAMPLE_TYPE_DEPTH:
147 printf(" <depth>%.2f</depth>\n", value.depth);
149 case SAMPLE_TYPE_PRESSURE:
150 printf(" <pressure tank=\"%u\">%.2f</pressure>\n", value.pressure.tank, value.pressure.value);
152 case SAMPLE_TYPE_TEMPERATURE:
153 printf(" <temperature>%.2f</temperature>\n", value.temperature);
155 case SAMPLE_TYPE_EVENT:
156 printf(" <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\n",
157 value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]);
159 case SAMPLE_TYPE_RBT:
160 printf(" <rbt>%u</rbt>\n", value.rbt);
162 case SAMPLE_TYPE_HEARTBEAT:
163 printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat);
165 case SAMPLE_TYPE_BEARING:
166 printf(" <bearing>%u</bearing>\n", value.bearing);
168 case SAMPLE_TYPE_VENDOR:
169 printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
170 for (i = 0; i < value.vendor.size; ++i)
171 printf("%02X", ((unsigned char *) value.vendor.data)[i]);
172 printf("</vendor>\n");
180 static int parse_samples(parser_t *parser)
182 // Parse the sample data.
183 printf("Parsing the sample data.\n");
184 return parser_samples_foreach(parser, sample_cb, NULL);
187 static int dive_cb(const unsigned char *data, unsigned int size,
188 const unsigned char *fingerprint, unsigned int fsize,
192 parser_t *parser = NULL;
193 device_data_t *devdata = userdata;
194 dc_datetime_t dt = {0};
196 rc = create_parser(devdata, &parser);
197 if (rc != PARSER_STATUS_SUCCESS) {
198 error("Unable to create parser for %s", devdata->name);
202 rc = parser_set_data(parser, data, size);
203 if (rc != PARSER_STATUS_SUCCESS) {
204 error("Error registering the data.");
205 parser_destroy(parser);
209 rc = parser_get_datetime(parser, &dt);
210 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
211 error("Error parsing the datetime.");
212 parser_destroy (parser);
216 printf("<datetime>%04i-%02i-%02i %02i:%02i:%02i</datetime>\n",
217 dt.year, dt.month, dt.day,
218 dt.hour, dt.minute, dt.second);
220 // Parse the divetime.
221 printf("Parsing the divetime.\n");
222 unsigned int divetime = 0;
223 rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
224 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
225 error("Error parsing the divetime.");
226 parser_destroy(parser);
230 printf("<divetime>%02u:%02u</divetime>\n",
231 divetime / 60, divetime % 60);
233 // Parse the maxdepth.
234 printf("Parsing the maxdepth.\n");
235 double maxdepth = 0.0;
236 rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
237 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
238 error("Error parsing the maxdepth.");
239 parser_destroy(parser);
243 printf("<maxdepth>%.2f</maxdepth>\n", maxdepth);
245 // Parse the gas mixes.
246 printf("Parsing the gas mixes.\n");
247 unsigned int ngases = 0;
248 rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
249 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
250 error("Error parsing the gas mix count.");
251 parser_destroy(parser);
255 rc = parse_gasmixes(parser, ngases);
256 if (rc != PARSER_STATUS_SUCCESS) {
257 error("Error parsing the gas mix.");
258 parser_destroy(parser);
262 // Initialize the sample data.
263 rc = parse_samples(parser);
264 if (rc != PARSER_STATUS_SUCCESS) {
265 error("Error parsing the samples.");
266 parser_destroy(parser);
270 parser_destroy(parser);
275 static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
277 return device_foreach(device, dive_cb, devicedata);
280 static device_status_t device_open(const char *devname,
285 case DEVICE_TYPE_SUUNTO_SOLUTION:
286 return suunto_solution_device_open(device, devname);
288 case DEVICE_TYPE_SUUNTO_EON:
289 return suunto_eon_device_open(device, devname);
291 case DEVICE_TYPE_SUUNTO_VYPER:
292 return suunto_vyper_device_open(device, devname);
294 case DEVICE_TYPE_SUUNTO_VYPER2:
295 return suunto_vyper2_device_open(device, devname);
297 case DEVICE_TYPE_SUUNTO_D9:
298 return suunto_d9_device_open(device, devname);
300 case DEVICE_TYPE_UWATEC_ALADIN:
301 return uwatec_aladin_device_open(device, devname);
303 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
304 return uwatec_memomouse_device_open(device, devname);
306 case DEVICE_TYPE_UWATEC_SMART:
307 return uwatec_smart_device_open(device);
309 case DEVICE_TYPE_REEFNET_SENSUS:
310 return reefnet_sensus_device_open(device, devname);
312 case DEVICE_TYPE_REEFNET_SENSUSPRO:
313 return reefnet_sensuspro_device_open(device, devname);
315 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
316 return reefnet_sensusultra_device_open(device, devname);
318 case DEVICE_TYPE_OCEANIC_VTPRO:
319 return oceanic_vtpro_device_open(device, devname);
321 case DEVICE_TYPE_OCEANIC_VEO250:
322 return oceanic_veo250_device_open(device, devname);
324 case DEVICE_TYPE_OCEANIC_ATOM2:
325 return oceanic_atom2_device_open(device, devname);
327 case DEVICE_TYPE_MARES_NEMO:
328 return mares_nemo_device_open(device, devname);
330 case DEVICE_TYPE_MARES_PUCK:
331 return mares_puck_device_open(device, devname);
333 case DEVICE_TYPE_MARES_ICONHD:
334 return mares_iconhd_device_open(device, devname);
336 case DEVICE_TYPE_HW_OSTC:
337 return hw_ostc_device_open(device, devname);
339 case DEVICE_TYPE_CRESSI_EDY:
340 return cressi_edy_device_open(device, devname);
342 case DEVICE_TYPE_ZEAGLE_N2ITION3:
343 return zeagle_n2ition3_device_open(device, devname);
345 case DEVICE_TYPE_ATOMICS_COBALT:
346 return atomics_cobalt_device_open(device);
349 return DEVICE_STATUS_ERROR;
354 event_cb (device_t *device, device_event_t event, const void *data, void *userdata)
356 const device_progress_t *progress = (device_progress_t *) data;
357 const device_devinfo_t *devinfo = (device_devinfo_t *) data;
358 const device_clock_t *clock = (device_clock_t *) data;
359 device_data_t *devdata = (device_data_t *) userdata;
362 case DEVICE_EVENT_WAITING:
363 printf("Event: waiting for user action\n");
365 case DEVICE_EVENT_PROGRESS:
366 printf("Event: progress %3.2f%% (%u/%u)\n",
367 100.0 * (double) progress->current / (double) progress->maximum,
368 progress->current, progress->maximum);
370 case DEVICE_EVENT_DEVINFO:
371 devdata->devinfo = *devinfo;
372 printf("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n",
373 devinfo->model, devinfo->model,
374 devinfo->firmware, devinfo->firmware,
375 devinfo->serial, devinfo->serial);
377 case DEVICE_EVENT_CLOCK:
378 devdata->clock = *clock;
379 printf("Event: systime=%lld, devtime=%u\n",
380 clock->systime, clock->devtime);
388 cancel_cb (void *userdata)
393 static void do_import(const char *computer, device_type_t type)
395 /* FIXME! Needs user input! */
396 const char *devname = "/dev/ttyUSB0";
397 device_t *device = NULL;
399 device_data_t devicedata = {
404 rc = device_open(devname, type, &device);
405 if (rc != DEVICE_STATUS_SUCCESS) {
406 error("Unable to open %s (%s)", computer, devname);
410 // Register the event handler.
411 int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
412 rc = device_set_events(device, events, event_cb, &devicedata);
413 if (rc != DEVICE_STATUS_SUCCESS) {
414 error("Error registering the event handler.");
415 device_close(device);
419 // Register the cancellation handler.
420 rc = device_set_cancel(device, cancel_cb, &devicedata);
421 if (rc != DEVICE_STATUS_SUCCESS) {
422 error("Error registering the cancellation handler.");
423 device_close(device);
427 rc = import_device_data(device, &devicedata);
428 if (rc != DEVICE_STATUS_SUCCESS) {
429 error("Dive data import error");
430 device_close(device);
434 device_close(device);
438 * Taken from 'example.c' in libdivecomputer.
440 * I really wish there was some way to just have
441 * libdivecomputer tell us what devices it supports,
442 * rather than have the application have to know..
448 { "Suunto Solution", DEVICE_TYPE_SUUNTO_SOLUTION },
449 { "Suunto Eon", DEVICE_TYPE_SUUNTO_EON },
450 { "Suunto Vyper", DEVICE_TYPE_SUUNTO_VYPER },
451 { "Suunto Vyper Air", DEVICE_TYPE_SUUNTO_VYPER2 },
452 { "Suunto D9", DEVICE_TYPE_SUUNTO_D9 },
453 { "Uwatec Aladin", DEVICE_TYPE_UWATEC_ALADIN },
454 { "Uwatec Memo Mouse", DEVICE_TYPE_UWATEC_MEMOMOUSE },
455 { "Uwatec Smart", DEVICE_TYPE_UWATEC_SMART },
456 { "ReefNet Sensus", DEVICE_TYPE_REEFNET_SENSUS },
457 { "ReefNet Sensus Pro", DEVICE_TYPE_REEFNET_SENSUSPRO },
458 { "ReefNet Sensus Ultra",DEVICE_TYPE_REEFNET_SENSUSULTRA },
459 { "Oceanic VT Pro", DEVICE_TYPE_OCEANIC_VTPRO },
460 { "Oceanic Veo250", DEVICE_TYPE_OCEANIC_VEO250 },
461 { "Oceanic Atom 2", DEVICE_TYPE_OCEANIC_ATOM2 },
462 { "Mares Nemo", DEVICE_TYPE_MARES_NEMO },
463 { "Mares Puck", DEVICE_TYPE_MARES_PUCK },
464 { "Mares Icon HD", DEVICE_TYPE_MARES_ICONHD },
465 { "OSTC", DEVICE_TYPE_HW_OSTC },
466 { "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
467 { "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
468 { "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },
472 static void fill_computer_list(GtkListStore *store)
475 struct device_list *list = device_list;
477 for (list = device_list ; list->name ; list++) {
478 gtk_list_store_append(store, &iter);
479 gtk_list_store_set(store, &iter,
486 static GtkComboBox *dive_computer_selector(GtkWidget *dialog)
488 GtkWidget *hbox, *combo_box;
490 GtkCellRenderer *renderer;
492 hbox = gtk_hbox_new(FALSE, 6);
493 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
495 model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
496 fill_computer_list(model);
498 combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model));
499 gtk_box_pack_start(GTK_BOX(hbox), combo_box, FALSE, TRUE, 3);
501 renderer = gtk_cell_renderer_text_new();
502 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), renderer, TRUE);
503 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), renderer, "text", 0, NULL);
505 return GTK_COMBO_BOX(combo_box);
508 void import_dialog(GtkWidget *w, gpointer data)
512 GtkComboBox *computer;
514 dialog = gtk_dialog_new_with_buttons("Import from dive computer",
515 GTK_WINDOW(main_window),
516 GTK_DIALOG_DESTROY_WITH_PARENT,
517 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
518 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
521 computer = dive_computer_selector(dialog);
523 gtk_widget_show_all(dialog);
524 result = gtk_dialog_run(GTK_DIALOG(dialog));
530 case GTK_RESPONSE_ACCEPT:
531 if (!gtk_combo_box_get_active_iter(computer, &iter))
533 model = gtk_combo_box_get_model(computer);
534 gtk_tree_model_get(model, &iter,
538 do_import(comp, type);
543 gtk_widget_destroy(dialog);