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 inline int year(int year)
273 static int dive_cb(const unsigned char *data, unsigned int size,
274 const unsigned char *fingerprint, unsigned int fsize,
278 parser_t *parser = NULL;
279 device_data_t *devdata = userdata;
280 dc_datetime_t dt = {0};
284 rc = create_parser(devdata, &parser);
285 if (rc != PARSER_STATUS_SUCCESS) {
286 dev_info(devdata, "Unable to create parser for %s", devdata->name);
290 rc = parser_set_data(parser, data, size);
291 if (rc != PARSER_STATUS_SUCCESS) {
292 dev_info(devdata, "Error registering the data");
293 parser_destroy(parser);
297 import_dive_number++;
299 rc = parser_get_datetime(parser, &dt);
300 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
301 dev_info(devdata, "Error parsing the datetime");
302 parser_destroy (parser);
306 tm.tm_year = dt.year;
307 tm.tm_mon = dt.month-1;
309 tm.tm_hour = dt.hour;
310 tm.tm_min = dt.minute;
311 tm.tm_sec = dt.second;
312 dive->when = utc_mktime(&tm);
314 // Parse the divetime.
315 dev_info(devdata, "Dive %d: %s %d %04d", import_dive_number,
316 monthname(tm.tm_mon), tm.tm_mday, year(tm.tm_year));
317 unsigned int divetime = 0;
318 rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
319 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
320 dev_info(devdata, "Error parsing the divetime");
321 parser_destroy(parser);
324 dive->duration.seconds = divetime;
326 // Parse the maxdepth.
327 double maxdepth = 0.0;
328 rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
329 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
330 dev_info(devdata, "Error parsing the maxdepth");
331 parser_destroy(parser);
334 dive->maxdepth.mm = maxdepth * 1000 + 0.5;
336 // Parse the gas mixes.
337 unsigned int ngases = 0;
338 rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
339 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
340 dev_info(devdata, "Error parsing the gas mix count");
341 parser_destroy(parser);
345 rc = parse_gasmixes(devdata, dive, parser, ngases);
346 if (rc != PARSER_STATUS_SUCCESS) {
347 dev_info(devdata, "Error parsing the gas mix");
348 parser_destroy(parser);
352 // Initialize the sample data.
353 rc = parse_samples(devdata, &dive, parser);
354 if (rc != PARSER_STATUS_SUCCESS) {
355 dev_info(devdata, "Error parsing the samples");
356 parser_destroy(parser);
360 parser_destroy(parser);
362 /* If we already saw this dive, abort. */
363 if (find_dive(dive, devdata))
371 static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
373 return device_foreach(device, dive_cb, devicedata);
376 static device_status_t device_open(const char *devname,
381 case DEVICE_TYPE_SUUNTO_SOLUTION:
382 return suunto_solution_device_open(device, devname);
384 case DEVICE_TYPE_SUUNTO_EON:
385 return suunto_eon_device_open(device, devname);
387 case DEVICE_TYPE_SUUNTO_VYPER:
388 return suunto_vyper_device_open(device, devname);
390 case DEVICE_TYPE_SUUNTO_VYPER2:
391 return suunto_vyper2_device_open(device, devname);
393 case DEVICE_TYPE_SUUNTO_D9:
394 return suunto_d9_device_open(device, devname);
396 case DEVICE_TYPE_UWATEC_ALADIN:
397 return uwatec_aladin_device_open(device, devname);
399 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
400 return uwatec_memomouse_device_open(device, devname);
402 case DEVICE_TYPE_UWATEC_SMART:
403 return uwatec_smart_device_open(device);
405 case DEVICE_TYPE_REEFNET_SENSUS:
406 return reefnet_sensus_device_open(device, devname);
408 case DEVICE_TYPE_REEFNET_SENSUSPRO:
409 return reefnet_sensuspro_device_open(device, devname);
411 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
412 return reefnet_sensusultra_device_open(device, devname);
414 case DEVICE_TYPE_OCEANIC_VTPRO:
415 return oceanic_vtpro_device_open(device, devname);
417 case DEVICE_TYPE_OCEANIC_VEO250:
418 return oceanic_veo250_device_open(device, devname);
420 case DEVICE_TYPE_OCEANIC_ATOM2:
421 return oceanic_atom2_device_open(device, devname);
423 case DEVICE_TYPE_MARES_DARWIN:
424 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?
426 case DEVICE_TYPE_MARES_NEMO:
427 return mares_nemo_device_open(device, devname);
429 case DEVICE_TYPE_MARES_PUCK:
430 return mares_puck_device_open(device, devname);
432 case DEVICE_TYPE_MARES_ICONHD:
433 return mares_iconhd_device_open(device, devname);
435 case DEVICE_TYPE_HW_OSTC:
436 return hw_ostc_device_open(device, devname);
438 case DEVICE_TYPE_CRESSI_EDY:
439 return cressi_edy_device_open(device, devname);
441 case DEVICE_TYPE_ZEAGLE_N2ITION3:
442 return zeagle_n2ition3_device_open(device, devname);
444 case DEVICE_TYPE_ATOMICS_COBALT:
445 return atomics_cobalt_device_open(device);
448 return DEVICE_STATUS_ERROR;
453 static void event_cb(device_t *device, device_event_t event, const void *data, void *userdata)
455 const device_progress_t *progress = data;
456 const device_devinfo_t *devinfo = data;
457 const device_clock_t *clock = data;
458 device_data_t *devdata = userdata;
461 case DEVICE_EVENT_WAITING:
462 dev_info(devdata, "Event: waiting for user action");
464 case DEVICE_EVENT_PROGRESS:
465 update_progressbar(&devdata->progress,
466 (double) progress->current / (double) progress->maximum);
468 case DEVICE_EVENT_DEVINFO:
469 devdata->devinfo = *devinfo;
470 dev_info(devdata, "model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)",
471 devinfo->model, devinfo->model,
472 devinfo->firmware, devinfo->firmware,
473 devinfo->serial, devinfo->serial);
475 case DEVICE_EVENT_CLOCK:
476 devdata->clock = *clock;
477 dev_info(devdata, "Event: systime=%"PRId64", devtime=%u\n",
478 (uint64_t)clock->systime, clock->devtime);
485 static int import_thread_done = 0, import_thread_cancelled;
488 cancel_cb(void *userdata)
490 return import_thread_cancelled;
493 static const char *do_libdivecomputer_import(device_data_t *data)
495 device_t *device = NULL;
498 import_dive_number = 0;
499 rc = device_open(data->devname, data->type, &device);
500 if (rc != DEVICE_STATUS_SUCCESS)
501 return "Unable to open %s (%s)";
503 // Register the event handler.
504 int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
505 rc = device_set_events(device, events, event_cb, data);
506 if (rc != DEVICE_STATUS_SUCCESS) {
507 device_close(device);
508 return "Error registering the event handler.";
511 // Register the cancellation handler.
512 rc = device_set_cancel(device, cancel_cb, data);
513 if (rc != DEVICE_STATUS_SUCCESS) {
514 device_close(device);
515 return "Error registering the cancellation handler.";
518 rc = import_device_data(device, data);
519 if (rc != DEVICE_STATUS_SUCCESS) {
520 device_close(device);
521 return "Dive data import error";
524 device_close(device);
528 static void *pthread_wrapper(void *_data)
530 device_data_t *data = _data;
531 const char *err_string = do_libdivecomputer_import(data);
532 import_thread_done = 1;
533 return (void *)err_string;
536 GError *do_import(device_data_t *data)
541 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
542 import_thread_done = 0;
543 pthread_create(&pthread, NULL, pthread_wrapper, data);
544 while (!import_thread_done) {
545 import_thread_cancelled = process_ui_events();
548 if (pthread_join(pthread, &retval) < 0)
549 retval = "Odd pthread error return";
551 return error(retval, data->name, data->devname);
556 * Taken from 'example.c' in libdivecomputer.
558 * I really wish there was some way to just have
559 * libdivecomputer tell us what devices it supports,
560 * rather than have the application have to know..
562 struct device_list device_list[] = {
563 { "Suunto Solution", DEVICE_TYPE_SUUNTO_SOLUTION },
564 { "Suunto Eon", DEVICE_TYPE_SUUNTO_EON },
565 { "Suunto Vyper", DEVICE_TYPE_SUUNTO_VYPER },
566 { "Suunto Vyper Air", DEVICE_TYPE_SUUNTO_VYPER2 },
567 { "Suunto D9", DEVICE_TYPE_SUUNTO_D9 },
568 { "Uwatec Aladin", DEVICE_TYPE_UWATEC_ALADIN },
569 { "Uwatec Memo Mouse", DEVICE_TYPE_UWATEC_MEMOMOUSE },
570 { "Uwatec Smart", DEVICE_TYPE_UWATEC_SMART },
571 { "ReefNet Sensus", DEVICE_TYPE_REEFNET_SENSUS },
572 { "ReefNet Sensus Pro", DEVICE_TYPE_REEFNET_SENSUSPRO },
573 { "ReefNet Sensus Ultra",DEVICE_TYPE_REEFNET_SENSUSULTRA },
574 { "Oceanic VT Pro", DEVICE_TYPE_OCEANIC_VTPRO },
575 { "Oceanic Veo250", DEVICE_TYPE_OCEANIC_VEO250 },
576 { "Oceanic Atom 2", DEVICE_TYPE_OCEANIC_ATOM2 },
577 { "Mares Darwin, M1, M2, Airlab", DEVICE_TYPE_MARES_DARWIN },
578 { "Mares Nemo, Excel, Apneist", DEVICE_TYPE_MARES_NEMO },
579 { "Mares Puck, Nemo Air, Nemo Wide", DEVICE_TYPE_MARES_PUCK },
580 { "Mares Icon HD", DEVICE_TYPE_MARES_ICONHD },
581 { "OSTC", DEVICE_TYPE_HW_OSTC },
582 #ifdef LIBDIVECOMPUTER_SUPPORTS_FROG
583 { "OSTC Frog", DEVICE_TYPE_HW_FROG },
585 { "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
586 { "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
587 { "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },