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 void error(const char *fmt, ...)
27 error = g_error_new_valist(
28 g_quark_from_string("subsurface"),
29 DIVE_ERROR_PARSE, fmt, args);
35 static parser_status_t create_parser(device_data_t *devdata, parser_t **parser)
37 switch (devdata->type) {
38 case DEVICE_TYPE_SUUNTO_SOLUTION:
39 return suunto_solution_parser_create(parser);
41 case DEVICE_TYPE_SUUNTO_EON:
42 return suunto_eon_parser_create(parser, 0);
44 case DEVICE_TYPE_SUUNTO_VYPER:
45 if (devdata->devinfo.model == 0x01)
46 return suunto_eon_parser_create(parser, 1);
47 return suunto_vyper_parser_create(parser);
49 case DEVICE_TYPE_SUUNTO_VYPER2:
50 case DEVICE_TYPE_SUUNTO_D9:
51 return suunto_d9_parser_create(parser, devdata->devinfo.model);
53 case DEVICE_TYPE_UWATEC_ALADIN:
54 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
55 return uwatec_memomouse_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
57 case DEVICE_TYPE_UWATEC_SMART:
58 return uwatec_smart_parser_create(parser, devdata->devinfo.model, devdata->clock.devtime, devdata->clock.systime);
60 case DEVICE_TYPE_REEFNET_SENSUS:
61 return reefnet_sensus_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
63 case DEVICE_TYPE_REEFNET_SENSUSPRO:
64 return reefnet_sensuspro_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
66 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
67 return reefnet_sensusultra_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
69 case DEVICE_TYPE_OCEANIC_VTPRO:
70 return oceanic_vtpro_parser_create(parser);
72 case DEVICE_TYPE_OCEANIC_VEO250:
73 return oceanic_veo250_parser_create(parser, devdata->devinfo.model);
75 case DEVICE_TYPE_OCEANIC_ATOM2:
76 return oceanic_atom2_parser_create(parser, devdata->devinfo.model);
78 case DEVICE_TYPE_MARES_DARWIN:
79 return mares_darwin_parser_create(parser, devdata->devinfo.model);
81 case DEVICE_TYPE_MARES_NEMO:
82 case DEVICE_TYPE_MARES_PUCK:
83 return mares_nemo_parser_create(parser, devdata->devinfo.model);
85 case DEVICE_TYPE_MARES_ICONHD:
86 return mares_iconhd_parser_create(parser, devdata->devinfo.model);
88 case DEVICE_TYPE_HW_OSTC:
89 return hw_ostc_parser_create(parser NOT_FROG);
91 #ifdef LIBDIVECOMPUTER_SUPPORTS_FROG
92 case DEVICE_TYPE_HW_FROG:
93 return hw_ostc_parser_create(parser, 1);
96 case DEVICE_TYPE_CRESSI_EDY:
97 case DEVICE_TYPE_ZEAGLE_N2ITION3:
98 return cressi_edy_parser_create(parser, devdata->devinfo.model);
100 case DEVICE_TYPE_ATOMICS_COBALT:
101 return atomics_cobalt_parser_create(parser);
104 return PARSER_STATUS_ERROR;
108 static int parse_gasmixes(struct dive *dive, parser_t *parser, int ngases)
112 for (i = 0; i < ngases; i++) {
114 gasmix_t gasmix = {0};
117 rc = parser_get_field(parser, FIELD_TYPE_GASMIX, i, &gasmix);
118 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED)
121 if (i >= MAX_CYLINDERS)
124 o2 = gasmix.oxygen * 1000 + 0.5;
125 he = gasmix.helium * 1000 + 0.5;
127 /* Ignore bogus data - libdivecomputer does some crazy stuff */
128 if (o2 <= AIR_PERMILLE || o2 >= 1000)
130 if (he < 0 || he >= 800 || o2+he >= 1000)
133 dive->cylinder[i].gasmix.o2.permille = o2;
134 dive->cylinder[i].gasmix.he.permille = he;
136 return PARSER_STATUS_SUCCESS;
139 static void handle_event(struct dive *dive, struct sample *sample, parser_sample_value_t value)
142 static const char *events[] = {
143 "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
144 "violation", "bookmark", "surface", "safety stop", "gaschange",
145 "safety stop (voluntary)", "safety stop (mandatory)", "deepstop",
146 "ceiling (safety stop)", "unknown", "divetime", "maxdepth",
147 "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning"
149 const int nr_events = sizeof(events) / sizeof(const char *);
153 * Just ignore surface events. They are pointless. What "surface"
154 * means depends on the dive computer (and possibly even settings
155 * in the dive computer). It does *not* necessarily mean "depth 0",
156 * so don't even turn it into that.
158 if (value.event.type == SAMPLE_EVENT_SURFACE)
162 * Other evens might be more interesting, but for now we just print them out.
164 type = value.event.type;
165 name = "invalid event number";
166 if (type < nr_events)
169 time = value.event.time;
171 time += sample->time.seconds;
173 add_event(dive, time, type, value.event.flags, value.event.value, name);
177 sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata)
180 struct dive **divep = userdata;
181 struct dive *dive = *divep;
182 struct sample *sample;
185 * We fill in the "previous" sample - except for SAMPLE_TYPE_TIME,
186 * which creates a new one.
188 sample = dive->samples ? dive->sample+dive->samples-1 : NULL;
191 case SAMPLE_TYPE_TIME:
192 sample = prepare_sample(divep);
193 sample->time.seconds = value.time;
194 finish_sample(*divep);
196 case SAMPLE_TYPE_DEPTH:
197 sample->depth.mm = value.depth * 1000 + 0.5;
199 case SAMPLE_TYPE_PRESSURE:
200 sample->cylinderindex = value.pressure.tank;
201 sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5;
203 case SAMPLE_TYPE_TEMPERATURE:
204 sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5;
206 case SAMPLE_TYPE_EVENT:
207 handle_event(dive, sample, value);
209 case SAMPLE_TYPE_RBT:
210 printf(" <rbt>%u</rbt>\n", value.rbt);
212 case SAMPLE_TYPE_HEARTBEAT:
213 printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat);
215 case SAMPLE_TYPE_BEARING:
216 printf(" <bearing>%u</bearing>\n", value.bearing);
218 case SAMPLE_TYPE_VENDOR:
219 printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
220 for (i = 0; i < value.vendor.size; ++i)
221 printf("%02X", ((unsigned char *) value.vendor.data)[i]);
222 printf("</vendor>\n");
230 static int parse_samples(struct dive **divep, parser_t *parser)
232 // Parse the sample data.
233 printf("Parsing the sample data.\n");
234 return parser_samples_foreach(parser, sample_cb, divep);
238 * Check if this dive already existed before the import
240 static int find_dive(struct dive *dive, device_data_t *devdata)
244 for (i = 0; i < dive_table.preexisting; i++) {
245 struct dive *old = dive_table.dives[i];
247 if (dive->when != old->when)
254 static int dive_cb(const unsigned char *data, unsigned int size,
255 const unsigned char *fingerprint, unsigned int fsize,
259 parser_t *parser = NULL;
260 device_data_t *devdata = userdata;
261 dc_datetime_t dt = {0};
265 rc = create_parser(devdata, &parser);
266 if (rc != PARSER_STATUS_SUCCESS) {
267 fprintf(stderr, "Unable to create parser for %s", devdata->name);
271 rc = parser_set_data(parser, data, size);
272 if (rc != PARSER_STATUS_SUCCESS) {
273 fprintf(stderr, "Error registering the data.");
274 parser_destroy(parser);
279 rc = parser_get_datetime(parser, &dt);
280 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
281 fprintf(stderr, "Error parsing the datetime.");
282 parser_destroy (parser);
286 tm.tm_year = dt.year;
287 tm.tm_mon = dt.month-1;
289 tm.tm_hour = dt.hour;
290 tm.tm_min = dt.minute;
291 tm.tm_sec = dt.second;
292 dive->when = utc_mktime(&tm);
294 // Parse the divetime.
295 printf("Parsing the divetime.\n");
296 unsigned int divetime = 0;
297 rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
298 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
299 fprintf(stderr, "Error parsing the divetime.");
300 parser_destroy(parser);
303 dive->duration.seconds = divetime;
305 // Parse the maxdepth.
306 printf("Parsing the maxdepth.\n");
307 double maxdepth = 0.0;
308 rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
309 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
310 fprintf(stderr, "Error parsing the maxdepth.");
311 parser_destroy(parser);
314 dive->maxdepth.mm = maxdepth * 1000 + 0.5;
316 // Parse the gas mixes.
317 printf("Parsing the gas mixes.\n");
318 unsigned int ngases = 0;
319 rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
320 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
321 fprintf(stderr, "Error parsing the gas mix count.");
322 parser_destroy(parser);
326 rc = parse_gasmixes(dive, parser, ngases);
327 if (rc != PARSER_STATUS_SUCCESS) {
328 fprintf(stderr, "Error parsing the gas mix.");
329 parser_destroy(parser);
333 // Initialize the sample data.
334 rc = parse_samples(&dive, parser);
335 if (rc != PARSER_STATUS_SUCCESS) {
336 fprintf(stderr, "Error parsing the samples.");
337 parser_destroy(parser);
341 parser_destroy(parser);
343 /* If we already saw this dive, abort. */
344 if (find_dive(dive, devdata))
352 static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
354 return device_foreach(device, dive_cb, devicedata);
357 static device_status_t device_open(const char *devname,
362 case DEVICE_TYPE_SUUNTO_SOLUTION:
363 return suunto_solution_device_open(device, devname);
365 case DEVICE_TYPE_SUUNTO_EON:
366 return suunto_eon_device_open(device, devname);
368 case DEVICE_TYPE_SUUNTO_VYPER:
369 return suunto_vyper_device_open(device, devname);
371 case DEVICE_TYPE_SUUNTO_VYPER2:
372 return suunto_vyper2_device_open(device, devname);
374 case DEVICE_TYPE_SUUNTO_D9:
375 return suunto_d9_device_open(device, devname);
377 case DEVICE_TYPE_UWATEC_ALADIN:
378 return uwatec_aladin_device_open(device, devname);
380 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
381 return uwatec_memomouse_device_open(device, devname);
383 case DEVICE_TYPE_UWATEC_SMART:
384 return uwatec_smart_device_open(device);
386 case DEVICE_TYPE_REEFNET_SENSUS:
387 return reefnet_sensus_device_open(device, devname);
389 case DEVICE_TYPE_REEFNET_SENSUSPRO:
390 return reefnet_sensuspro_device_open(device, devname);
392 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
393 return reefnet_sensusultra_device_open(device, devname);
395 case DEVICE_TYPE_OCEANIC_VTPRO:
396 return oceanic_vtpro_device_open(device, devname);
398 case DEVICE_TYPE_OCEANIC_VEO250:
399 return oceanic_veo250_device_open(device, devname);
401 case DEVICE_TYPE_OCEANIC_ATOM2:
402 return oceanic_atom2_device_open(device, devname);
404 case DEVICE_TYPE_MARES_DARWIN:
405 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?
407 case DEVICE_TYPE_MARES_NEMO:
408 return mares_nemo_device_open(device, devname);
410 case DEVICE_TYPE_MARES_PUCK:
411 return mares_puck_device_open(device, devname);
413 case DEVICE_TYPE_MARES_ICONHD:
414 return mares_iconhd_device_open(device, devname);
416 case DEVICE_TYPE_HW_OSTC:
417 return hw_ostc_device_open(device, devname);
419 case DEVICE_TYPE_CRESSI_EDY:
420 return cressi_edy_device_open(device, devname);
422 case DEVICE_TYPE_ZEAGLE_N2ITION3:
423 return zeagle_n2ition3_device_open(device, devname);
425 case DEVICE_TYPE_ATOMICS_COBALT:
426 return atomics_cobalt_device_open(device);
429 return DEVICE_STATUS_ERROR;
433 static void event_cb(device_t *device, device_event_t event, const void *data, void *userdata)
435 const device_progress_t *progress = data;
436 const device_devinfo_t *devinfo = data;
437 const device_clock_t *clock = data;
438 device_data_t *devdata = userdata;
441 case DEVICE_EVENT_WAITING:
442 printf("Event: waiting for user action\n");
444 case DEVICE_EVENT_PROGRESS:
445 update_progressbar(&devdata->progress,
446 (double) progress->current / (double) progress->maximum);
448 case DEVICE_EVENT_DEVINFO:
449 devdata->devinfo = *devinfo;
450 printf("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n",
451 devinfo->model, devinfo->model,
452 devinfo->firmware, devinfo->firmware,
453 devinfo->serial, devinfo->serial);
455 case DEVICE_EVENT_CLOCK:
456 devdata->clock = *clock;
457 printf("Event: systime=%"PRId64", devtime=%u\n",
458 (uint64_t)clock->systime, clock->devtime);
465 static int import_thread_done = 0, import_thread_cancelled;
468 cancel_cb(void *userdata)
470 return import_thread_cancelled;
473 static const char *do_libdivecomputer_import(device_data_t *data)
475 device_t *device = NULL;
478 rc = device_open(data->devname, data->type, &device);
479 if (rc != DEVICE_STATUS_SUCCESS)
480 return "Unable to open %s (%s)";
482 // Register the event handler.
483 int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
484 rc = device_set_events(device, events, event_cb, data);
485 if (rc != DEVICE_STATUS_SUCCESS) {
486 device_close(device);
487 return "Error registering the event handler.";
490 // Register the cancellation handler.
491 rc = device_set_cancel(device, cancel_cb, data);
492 if (rc != DEVICE_STATUS_SUCCESS) {
493 device_close(device);
494 return "Error registering the cancellation handler.";
497 rc = import_device_data(device, data);
498 if (rc != DEVICE_STATUS_SUCCESS) {
499 device_close(device);
500 return "Dive data import error";
503 device_close(device);
507 static void *pthread_wrapper(void *_data)
509 device_data_t *data = _data;
510 const char *err_string = do_libdivecomputer_import(data);
511 import_thread_done = 1;
512 return (void *)err_string;
515 void do_import(device_data_t *data)
520 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
521 import_thread_done = 0;
522 pthread_create(&pthread, NULL, pthread_wrapper, data);
523 while (!import_thread_done) {
524 import_thread_cancelled = process_ui_events();
527 if (pthread_join(pthread, &retval) < 0)
528 retval = "Odd pthread error return";
530 error(retval, data->name, data->devname);
534 * Taken from 'example.c' in libdivecomputer.
536 * I really wish there was some way to just have
537 * libdivecomputer tell us what devices it supports,
538 * rather than have the application have to know..
540 struct device_list device_list[] = {
541 { "Suunto Solution", DEVICE_TYPE_SUUNTO_SOLUTION },
542 { "Suunto Eon", DEVICE_TYPE_SUUNTO_EON },
543 { "Suunto Vyper", DEVICE_TYPE_SUUNTO_VYPER },
544 { "Suunto Vyper Air", DEVICE_TYPE_SUUNTO_VYPER2 },
545 { "Suunto D9", DEVICE_TYPE_SUUNTO_D9 },
546 { "Uwatec Aladin", DEVICE_TYPE_UWATEC_ALADIN },
547 { "Uwatec Memo Mouse", DEVICE_TYPE_UWATEC_MEMOMOUSE },
548 { "Uwatec Smart", DEVICE_TYPE_UWATEC_SMART },
549 { "ReefNet Sensus", DEVICE_TYPE_REEFNET_SENSUS },
550 { "ReefNet Sensus Pro", DEVICE_TYPE_REEFNET_SENSUSPRO },
551 { "ReefNet Sensus Ultra",DEVICE_TYPE_REEFNET_SENSUSULTRA },
552 { "Oceanic VT Pro", DEVICE_TYPE_OCEANIC_VTPRO },
553 { "Oceanic Veo250", DEVICE_TYPE_OCEANIC_VEO250 },
554 { "Oceanic Atom 2", DEVICE_TYPE_OCEANIC_ATOM2 },
555 { "Mares Darwin, M1, M2, Airlab", DEVICE_TYPE_MARES_DARWIN },
556 { "Mares Nemo, Excel, Apneist", DEVICE_TYPE_MARES_NEMO },
557 { "Mares Puck, Nemo Air, Nemo Wide", DEVICE_TYPE_MARES_PUCK },
558 { "Mares Icon HD", DEVICE_TYPE_MARES_ICONHD },
559 { "OSTC", DEVICE_TYPE_HW_OSTC },
560 #ifdef LIBDIVECOMPUTER_SUPPORTS_FROG
561 { "OSTC Frog", DEVICE_TYPE_HW_FROG },
563 { "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
564 { "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
565 { "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },