9 #include "display-gtk.h"
11 #include "libdivecomputer.h"
13 /* Christ. Libdivecomputer has the worst configuration system ever. */
16 #define LIBDIVECOMPUTER_SUPPORTS_FROG
21 static GError *error(const char *fmt, ...)
27 error = g_error_new_valist(
28 g_quark_from_string("subsurface"),
29 DIVE_ERROR_PARSE, fmt, args);
34 static parser_status_t create_parser(device_data_t *devdata, parser_t **parser)
36 switch (devdata->type) {
37 case DEVICE_TYPE_SUUNTO_SOLUTION:
38 return suunto_solution_parser_create(parser);
40 case DEVICE_TYPE_SUUNTO_EON:
41 return suunto_eon_parser_create(parser, 0);
43 case DEVICE_TYPE_SUUNTO_VYPER:
44 if (devdata->devinfo.model == 0x01)
45 return suunto_eon_parser_create(parser, 1);
46 return suunto_vyper_parser_create(parser);
48 case DEVICE_TYPE_SUUNTO_VYPER2:
49 case DEVICE_TYPE_SUUNTO_D9:
50 return suunto_d9_parser_create(parser, devdata->devinfo.model);
52 case DEVICE_TYPE_UWATEC_ALADIN:
53 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
54 return uwatec_memomouse_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
56 case DEVICE_TYPE_UWATEC_SMART:
57 return uwatec_smart_parser_create(parser, devdata->devinfo.model, devdata->clock.devtime, devdata->clock.systime);
59 case DEVICE_TYPE_REEFNET_SENSUS:
60 return reefnet_sensus_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
62 case DEVICE_TYPE_REEFNET_SENSUSPRO:
63 return reefnet_sensuspro_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
65 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
66 return reefnet_sensusultra_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
68 case DEVICE_TYPE_OCEANIC_VTPRO:
69 return oceanic_vtpro_parser_create(parser);
71 case DEVICE_TYPE_OCEANIC_VEO250:
72 return oceanic_veo250_parser_create(parser, devdata->devinfo.model);
74 case DEVICE_TYPE_OCEANIC_ATOM2:
75 return oceanic_atom2_parser_create(parser, devdata->devinfo.model);
77 case DEVICE_TYPE_MARES_DARWIN:
78 return mares_darwin_parser_create(parser, devdata->devinfo.model);
80 case DEVICE_TYPE_MARES_NEMO:
81 case DEVICE_TYPE_MARES_PUCK:
82 return mares_nemo_parser_create(parser, devdata->devinfo.model);
84 case DEVICE_TYPE_MARES_ICONHD:
85 return mares_iconhd_parser_create(parser, devdata->devinfo.model);
87 case DEVICE_TYPE_HW_OSTC:
88 return hw_ostc_parser_create(parser NOT_FROG);
90 #ifdef LIBDIVECOMPUTER_SUPPORTS_FROG
91 case DEVICE_TYPE_HW_FROG:
92 return hw_ostc_parser_create(parser, 1);
95 case DEVICE_TYPE_CRESSI_EDY:
96 case DEVICE_TYPE_ZEAGLE_N2ITION3:
97 return cressi_edy_parser_create(parser, devdata->devinfo.model);
99 case DEVICE_TYPE_ATOMICS_COBALT:
100 return atomics_cobalt_parser_create(parser);
103 return PARSER_STATUS_ERROR;
107 static int parse_gasmixes(device_data_t *devdata, struct dive *dive, parser_t *parser, int ngases)
111 for (i = 0; i < ngases; i++) {
113 gasmix_t gasmix = {0};
116 rc = parser_get_field(parser, FIELD_TYPE_GASMIX, i, &gasmix);
117 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED)
120 if (i >= MAX_CYLINDERS)
123 o2 = gasmix.oxygen * 1000 + 0.5;
124 he = gasmix.helium * 1000 + 0.5;
126 /* Ignore bogus data - libdivecomputer does some crazy stuff */
127 if (o2 <= AIR_PERMILLE || o2 >= 1000)
129 if (he < 0 || he >= 800 || o2+he >= 1000)
132 dive->cylinder[i].gasmix.o2.permille = o2;
133 dive->cylinder[i].gasmix.he.permille = he;
135 return PARSER_STATUS_SUCCESS;
138 static void handle_event(struct dive *dive, struct sample *sample, parser_sample_value_t value)
141 static const char *events[] = {
142 "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
143 "violation", "bookmark", "surface", "safety stop", "gaschange",
144 "safety stop (voluntary)", "safety stop (mandatory)", "deepstop",
145 "ceiling (safety stop)", "unknown", "divetime", "maxdepth",
146 "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning"
148 const int nr_events = sizeof(events) / sizeof(const char *);
152 * Just ignore surface events. They are pointless. What "surface"
153 * means depends on the dive computer (and possibly even settings
154 * in the dive computer). It does *not* necessarily mean "depth 0",
155 * so don't even turn it into that.
157 if (value.event.type == SAMPLE_EVENT_SURFACE)
161 * Other evens might be more interesting, but for now we just print them out.
163 type = value.event.type;
164 name = "invalid event number";
165 if (type < nr_events)
168 time = value.event.time;
170 time += sample->time.seconds;
172 add_event(dive, time, type, value.event.flags, value.event.value, name);
176 sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata)
179 struct dive **divep = userdata;
180 struct dive *dive = *divep;
181 struct sample *sample;
184 * We fill in the "previous" sample - except for SAMPLE_TYPE_TIME,
185 * which creates a new one.
187 sample = dive->samples ? dive->sample+dive->samples-1 : NULL;
190 case SAMPLE_TYPE_TIME:
191 sample = prepare_sample(divep);
192 sample->time.seconds = value.time;
193 finish_sample(*divep);
195 case SAMPLE_TYPE_DEPTH:
196 sample->depth.mm = value.depth * 1000 + 0.5;
198 case SAMPLE_TYPE_PRESSURE:
199 sample->cylinderindex = value.pressure.tank;
200 sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5;
202 case SAMPLE_TYPE_TEMPERATURE:
203 sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5;
205 case SAMPLE_TYPE_EVENT:
206 handle_event(dive, sample, value);
208 case SAMPLE_TYPE_RBT:
209 printf(" <rbt>%u</rbt>\n", value.rbt);
211 case SAMPLE_TYPE_HEARTBEAT:
212 printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat);
214 case SAMPLE_TYPE_BEARING:
215 printf(" <bearing>%u</bearing>\n", value.bearing);
217 case SAMPLE_TYPE_VENDOR:
218 printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
219 for (i = 0; i < value.vendor.size; ++i)
220 printf("%02X", ((unsigned char *) value.vendor.data)[i]);
221 printf("</vendor>\n");
228 static void dev_info(device_data_t *devdata, const char *fmt, ...)
234 vsnprintf(buffer, sizeof(buffer), fmt, ap);
236 update_progressbar_text(&devdata->progress, buffer);
239 static int import_dive_number = 0;
241 static int parse_samples(device_data_t *devdata, struct dive **divep, parser_t *parser)
243 // Parse the sample data.
244 return parser_samples_foreach(parser, sample_cb, divep);
248 * Check if this dive already existed before the import
250 static int find_dive(struct dive *dive, device_data_t *devdata)
254 for (i = 0; i < dive_table.preexisting; i++) {
255 struct dive *old = dive_table.dives[i];
257 if (dive->when != old->when)
264 static int dive_cb(const unsigned char *data, unsigned int size,
265 const unsigned char *fingerprint, unsigned int fsize,
269 parser_t *parser = NULL;
270 device_data_t *devdata = userdata;
271 dc_datetime_t dt = {0};
275 rc = create_parser(devdata, &parser);
276 if (rc != PARSER_STATUS_SUCCESS) {
277 dev_info(devdata, "Unable to create parser for %s", devdata->name);
281 rc = parser_set_data(parser, data, size);
282 if (rc != PARSER_STATUS_SUCCESS) {
283 dev_info(devdata, "Error registering the data");
284 parser_destroy(parser);
288 import_dive_number++;
290 rc = parser_get_datetime(parser, &dt);
291 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
292 dev_info(devdata, "Error parsing the datetime");
293 parser_destroy (parser);
297 tm.tm_year = dt.year;
298 tm.tm_mon = dt.month-1;
300 tm.tm_hour = dt.hour;
301 tm.tm_min = dt.minute;
302 tm.tm_sec = dt.second;
303 dive->when = utc_mktime(&tm);
305 // Parse the divetime.
306 dev_info(devdata, "Parsing dive %d", import_dive_number);
307 unsigned int divetime = 0;
308 rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
309 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
310 dev_info(devdata, "Error parsing the divetime");
311 parser_destroy(parser);
314 dive->duration.seconds = divetime;
316 // Parse the maxdepth.
317 double maxdepth = 0.0;
318 rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
319 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
320 dev_info(devdata, "Error parsing the maxdepth");
321 parser_destroy(parser);
324 dive->maxdepth.mm = maxdepth * 1000 + 0.5;
326 // Parse the gas mixes.
327 unsigned int ngases = 0;
328 rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
329 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
330 dev_info(devdata, "Error parsing the gas mix count");
331 parser_destroy(parser);
335 rc = parse_gasmixes(devdata, dive, parser, ngases);
336 if (rc != PARSER_STATUS_SUCCESS) {
337 dev_info(devdata, "Error parsing the gas mix");
338 parser_destroy(parser);
342 // Initialize the sample data.
343 rc = parse_samples(devdata, &dive, parser);
344 if (rc != PARSER_STATUS_SUCCESS) {
345 dev_info(devdata, "Error parsing the samples");
346 parser_destroy(parser);
350 parser_destroy(parser);
352 /* If we already saw this dive, abort. */
353 if (find_dive(dive, devdata))
361 static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
363 return device_foreach(device, dive_cb, devicedata);
366 static device_status_t device_open(const char *devname,
371 case DEVICE_TYPE_SUUNTO_SOLUTION:
372 return suunto_solution_device_open(device, devname);
374 case DEVICE_TYPE_SUUNTO_EON:
375 return suunto_eon_device_open(device, devname);
377 case DEVICE_TYPE_SUUNTO_VYPER:
378 return suunto_vyper_device_open(device, devname);
380 case DEVICE_TYPE_SUUNTO_VYPER2:
381 return suunto_vyper2_device_open(device, devname);
383 case DEVICE_TYPE_SUUNTO_D9:
384 return suunto_d9_device_open(device, devname);
386 case DEVICE_TYPE_UWATEC_ALADIN:
387 return uwatec_aladin_device_open(device, devname);
389 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
390 return uwatec_memomouse_device_open(device, devname);
392 case DEVICE_TYPE_UWATEC_SMART:
393 return uwatec_smart_device_open(device);
395 case DEVICE_TYPE_REEFNET_SENSUS:
396 return reefnet_sensus_device_open(device, devname);
398 case DEVICE_TYPE_REEFNET_SENSUSPRO:
399 return reefnet_sensuspro_device_open(device, devname);
401 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
402 return reefnet_sensusultra_device_open(device, devname);
404 case DEVICE_TYPE_OCEANIC_VTPRO:
405 return oceanic_vtpro_device_open(device, devname);
407 case DEVICE_TYPE_OCEANIC_VEO250:
408 return oceanic_veo250_device_open(device, devname);
410 case DEVICE_TYPE_OCEANIC_ATOM2:
411 return oceanic_atom2_device_open(device, devname);
413 case DEVICE_TYPE_MARES_DARWIN:
414 return mares_darwin_device_open(device, devname, 0); /// last parameter is model type (taken from example), 0 seems to be standard, 1 is DARWIN_AIR => Darwin Air wont work if this is fixed here?
416 case DEVICE_TYPE_MARES_NEMO:
417 return mares_nemo_device_open(device, devname);
419 case DEVICE_TYPE_MARES_PUCK:
420 return mares_puck_device_open(device, devname);
422 case DEVICE_TYPE_MARES_ICONHD:
423 return mares_iconhd_device_open(device, devname);
425 case DEVICE_TYPE_HW_OSTC:
426 return hw_ostc_device_open(device, devname);
428 case DEVICE_TYPE_CRESSI_EDY:
429 return cressi_edy_device_open(device, devname);
431 case DEVICE_TYPE_ZEAGLE_N2ITION3:
432 return zeagle_n2ition3_device_open(device, devname);
434 case DEVICE_TYPE_ATOMICS_COBALT:
435 return atomics_cobalt_device_open(device);
438 return DEVICE_STATUS_ERROR;
443 static void event_cb(device_t *device, device_event_t event, const void *data, void *userdata)
445 const device_progress_t *progress = data;
446 const device_devinfo_t *devinfo = data;
447 const device_clock_t *clock = data;
448 device_data_t *devdata = userdata;
451 case DEVICE_EVENT_WAITING:
452 dev_info(devdata, "Event: waiting for user action");
454 case DEVICE_EVENT_PROGRESS:
455 update_progressbar(&devdata->progress,
456 (double) progress->current / (double) progress->maximum);
458 case DEVICE_EVENT_DEVINFO:
459 devdata->devinfo = *devinfo;
460 dev_info(devdata, "model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)",
461 devinfo->model, devinfo->model,
462 devinfo->firmware, devinfo->firmware,
463 devinfo->serial, devinfo->serial);
465 case DEVICE_EVENT_CLOCK:
466 devdata->clock = *clock;
467 dev_info(devdata, "Event: systime=%"PRId64", devtime=%u\n",
468 (uint64_t)clock->systime, clock->devtime);
475 static int import_thread_done = 0, import_thread_cancelled;
478 cancel_cb(void *userdata)
480 return import_thread_cancelled;
483 static const char *do_libdivecomputer_import(device_data_t *data)
485 device_t *device = NULL;
488 import_dive_number = 0;
489 rc = device_open(data->devname, data->type, &device);
490 if (rc != DEVICE_STATUS_SUCCESS)
491 return "Unable to open %s (%s)";
493 // Register the event handler.
494 int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
495 rc = device_set_events(device, events, event_cb, data);
496 if (rc != DEVICE_STATUS_SUCCESS) {
497 device_close(device);
498 return "Error registering the event handler.";
501 // Register the cancellation handler.
502 rc = device_set_cancel(device, cancel_cb, data);
503 if (rc != DEVICE_STATUS_SUCCESS) {
504 device_close(device);
505 return "Error registering the cancellation handler.";
508 rc = import_device_data(device, data);
509 if (rc != DEVICE_STATUS_SUCCESS) {
510 device_close(device);
511 return "Dive data import error";
514 device_close(device);
518 static void *pthread_wrapper(void *_data)
520 device_data_t *data = _data;
521 const char *err_string = do_libdivecomputer_import(data);
522 import_thread_done = 1;
523 return (void *)err_string;
526 GError *do_import(device_data_t *data)
531 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
532 import_thread_done = 0;
533 pthread_create(&pthread, NULL, pthread_wrapper, data);
534 while (!import_thread_done) {
535 import_thread_cancelled = process_ui_events();
538 if (pthread_join(pthread, &retval) < 0)
539 retval = "Odd pthread error return";
541 return error(retval, data->name, data->devname);
546 * Taken from 'example.c' in libdivecomputer.
548 * I really wish there was some way to just have
549 * libdivecomputer tell us what devices it supports,
550 * rather than have the application have to know..
552 struct device_list device_list[] = {
553 { "Suunto Solution", DEVICE_TYPE_SUUNTO_SOLUTION },
554 { "Suunto Eon", DEVICE_TYPE_SUUNTO_EON },
555 { "Suunto Vyper", DEVICE_TYPE_SUUNTO_VYPER },
556 { "Suunto Vyper Air", DEVICE_TYPE_SUUNTO_VYPER2 },
557 { "Suunto D9", DEVICE_TYPE_SUUNTO_D9 },
558 { "Uwatec Aladin", DEVICE_TYPE_UWATEC_ALADIN },
559 { "Uwatec Memo Mouse", DEVICE_TYPE_UWATEC_MEMOMOUSE },
560 { "Uwatec Smart", DEVICE_TYPE_UWATEC_SMART },
561 { "ReefNet Sensus", DEVICE_TYPE_REEFNET_SENSUS },
562 { "ReefNet Sensus Pro", DEVICE_TYPE_REEFNET_SENSUSPRO },
563 { "ReefNet Sensus Ultra",DEVICE_TYPE_REEFNET_SENSUSULTRA },
564 { "Oceanic VT Pro", DEVICE_TYPE_OCEANIC_VTPRO },
565 { "Oceanic Veo250", DEVICE_TYPE_OCEANIC_VEO250 },
566 { "Oceanic Atom 2", DEVICE_TYPE_OCEANIC_ATOM2 },
567 { "Mares Darwin, M1, M2, Airlab", DEVICE_TYPE_MARES_DARWIN },
568 { "Mares Nemo, Excel, Apneist", DEVICE_TYPE_MARES_NEMO },
569 { "Mares Puck, Nemo Air, Nemo Wide", DEVICE_TYPE_MARES_PUCK },
570 { "Mares Icon HD", DEVICE_TYPE_MARES_ICONHD },
571 { "OSTC", DEVICE_TYPE_HW_OSTC },
572 #ifdef LIBDIVECOMPUTER_SUPPORTS_FROG
573 { "OSTC Frog", DEVICE_TYPE_HW_FROG },
575 { "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
576 { "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
577 { "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },