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(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");
229 static int parse_samples(struct dive **divep, parser_t *parser)
231 // Parse the sample data.
232 printf("Parsing the sample data.\n");
233 return parser_samples_foreach(parser, sample_cb, divep);
237 * Check if this dive already existed before the import
239 static int find_dive(struct dive *dive, device_data_t *devdata)
243 for (i = 0; i < dive_table.preexisting; i++) {
244 struct dive *old = dive_table.dives[i];
246 if (dive->when != old->when)
253 static int dive_cb(const unsigned char *data, unsigned int size,
254 const unsigned char *fingerprint, unsigned int fsize,
258 parser_t *parser = NULL;
259 device_data_t *devdata = userdata;
260 dc_datetime_t dt = {0};
264 rc = create_parser(devdata, &parser);
265 if (rc != PARSER_STATUS_SUCCESS) {
266 fprintf(stderr, "Unable to create parser for %s", devdata->name);
270 rc = parser_set_data(parser, data, size);
271 if (rc != PARSER_STATUS_SUCCESS) {
272 fprintf(stderr, "Error registering the data.");
273 parser_destroy(parser);
278 rc = parser_get_datetime(parser, &dt);
279 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
280 fprintf(stderr, "Error parsing the datetime.");
281 parser_destroy (parser);
285 tm.tm_year = dt.year;
286 tm.tm_mon = dt.month-1;
288 tm.tm_hour = dt.hour;
289 tm.tm_min = dt.minute;
290 tm.tm_sec = dt.second;
291 dive->when = utc_mktime(&tm);
293 // Parse the divetime.
294 printf("Parsing the divetime.\n");
295 unsigned int divetime = 0;
296 rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
297 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
298 fprintf(stderr, "Error parsing the divetime.");
299 parser_destroy(parser);
302 dive->duration.seconds = divetime;
304 // Parse the maxdepth.
305 printf("Parsing the maxdepth.\n");
306 double maxdepth = 0.0;
307 rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
308 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
309 fprintf(stderr, "Error parsing the maxdepth.");
310 parser_destroy(parser);
313 dive->maxdepth.mm = maxdepth * 1000 + 0.5;
315 // Parse the gas mixes.
316 printf("Parsing the gas mixes.\n");
317 unsigned int ngases = 0;
318 rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
319 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
320 fprintf(stderr, "Error parsing the gas mix count.");
321 parser_destroy(parser);
325 rc = parse_gasmixes(dive, parser, ngases);
326 if (rc != PARSER_STATUS_SUCCESS) {
327 fprintf(stderr, "Error parsing the gas mix.");
328 parser_destroy(parser);
332 // Initialize the sample data.
333 rc = parse_samples(&dive, parser);
334 if (rc != PARSER_STATUS_SUCCESS) {
335 fprintf(stderr, "Error parsing the samples.");
336 parser_destroy(parser);
340 parser_destroy(parser);
342 /* If we already saw this dive, abort. */
343 if (find_dive(dive, devdata))
351 static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
353 return device_foreach(device, dive_cb, devicedata);
356 static device_status_t device_open(const char *devname,
361 case DEVICE_TYPE_SUUNTO_SOLUTION:
362 return suunto_solution_device_open(device, devname);
364 case DEVICE_TYPE_SUUNTO_EON:
365 return suunto_eon_device_open(device, devname);
367 case DEVICE_TYPE_SUUNTO_VYPER:
368 return suunto_vyper_device_open(device, devname);
370 case DEVICE_TYPE_SUUNTO_VYPER2:
371 return suunto_vyper2_device_open(device, devname);
373 case DEVICE_TYPE_SUUNTO_D9:
374 return suunto_d9_device_open(device, devname);
376 case DEVICE_TYPE_UWATEC_ALADIN:
377 return uwatec_aladin_device_open(device, devname);
379 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
380 return uwatec_memomouse_device_open(device, devname);
382 case DEVICE_TYPE_UWATEC_SMART:
383 return uwatec_smart_device_open(device);
385 case DEVICE_TYPE_REEFNET_SENSUS:
386 return reefnet_sensus_device_open(device, devname);
388 case DEVICE_TYPE_REEFNET_SENSUSPRO:
389 return reefnet_sensuspro_device_open(device, devname);
391 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
392 return reefnet_sensusultra_device_open(device, devname);
394 case DEVICE_TYPE_OCEANIC_VTPRO:
395 return oceanic_vtpro_device_open(device, devname);
397 case DEVICE_TYPE_OCEANIC_VEO250:
398 return oceanic_veo250_device_open(device, devname);
400 case DEVICE_TYPE_OCEANIC_ATOM2:
401 return oceanic_atom2_device_open(device, devname);
403 case DEVICE_TYPE_MARES_DARWIN:
404 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?
406 case DEVICE_TYPE_MARES_NEMO:
407 return mares_nemo_device_open(device, devname);
409 case DEVICE_TYPE_MARES_PUCK:
410 return mares_puck_device_open(device, devname);
412 case DEVICE_TYPE_MARES_ICONHD:
413 return mares_iconhd_device_open(device, devname);
415 case DEVICE_TYPE_HW_OSTC:
416 return hw_ostc_device_open(device, devname);
418 case DEVICE_TYPE_CRESSI_EDY:
419 return cressi_edy_device_open(device, devname);
421 case DEVICE_TYPE_ZEAGLE_N2ITION3:
422 return zeagle_n2ition3_device_open(device, devname);
424 case DEVICE_TYPE_ATOMICS_COBALT:
425 return atomics_cobalt_device_open(device);
428 return DEVICE_STATUS_ERROR;
432 static void event_cb(device_t *device, device_event_t event, const void *data, void *userdata)
434 const device_progress_t *progress = data;
435 const device_devinfo_t *devinfo = data;
436 const device_clock_t *clock = data;
437 device_data_t *devdata = userdata;
440 case DEVICE_EVENT_WAITING:
441 printf("Event: waiting for user action\n");
443 case DEVICE_EVENT_PROGRESS:
444 update_progressbar(&devdata->progress,
445 (double) progress->current / (double) progress->maximum);
447 case DEVICE_EVENT_DEVINFO:
448 devdata->devinfo = *devinfo;
449 printf("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n",
450 devinfo->model, devinfo->model,
451 devinfo->firmware, devinfo->firmware,
452 devinfo->serial, devinfo->serial);
454 case DEVICE_EVENT_CLOCK:
455 devdata->clock = *clock;
456 printf("Event: systime=%"PRId64", devtime=%u\n",
457 (uint64_t)clock->systime, clock->devtime);
464 static int import_thread_done = 0, import_thread_cancelled;
467 cancel_cb(void *userdata)
469 return import_thread_cancelled;
472 static const char *do_libdivecomputer_import(device_data_t *data)
474 device_t *device = NULL;
477 rc = device_open(data->devname, data->type, &device);
478 if (rc != DEVICE_STATUS_SUCCESS)
479 return "Unable to open %s (%s)";
481 // Register the event handler.
482 int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
483 rc = device_set_events(device, events, event_cb, data);
484 if (rc != DEVICE_STATUS_SUCCESS) {
485 device_close(device);
486 return "Error registering the event handler.";
489 // Register the cancellation handler.
490 rc = device_set_cancel(device, cancel_cb, data);
491 if (rc != DEVICE_STATUS_SUCCESS) {
492 device_close(device);
493 return "Error registering the cancellation handler.";
496 rc = import_device_data(device, data);
497 if (rc != DEVICE_STATUS_SUCCESS) {
498 device_close(device);
499 return "Dive data import error";
502 device_close(device);
506 static void *pthread_wrapper(void *_data)
508 device_data_t *data = _data;
509 const char *err_string = do_libdivecomputer_import(data);
510 import_thread_done = 1;
511 return (void *)err_string;
514 GError *do_import(device_data_t *data)
519 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
520 import_thread_done = 0;
521 pthread_create(&pthread, NULL, pthread_wrapper, data);
522 while (!import_thread_done) {
523 import_thread_cancelled = process_ui_events();
526 if (pthread_join(pthread, &retval) < 0)
527 retval = "Odd pthread error return";
529 return 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 },