7 #include "display-gtk.h"
9 #include "libdivecomputer.h"
11 static void error(const char *fmt, ...)
17 error = g_error_new_valist(
18 g_quark_from_string("subsurface"),
19 DIVE_ERROR_PARSE, fmt, args);
25 static parser_status_t create_parser(device_data_t *devdata, parser_t **parser)
27 switch (devdata->type) {
28 case DEVICE_TYPE_SUUNTO_SOLUTION:
29 return suunto_solution_parser_create(parser);
31 case DEVICE_TYPE_SUUNTO_EON:
32 return suunto_eon_parser_create(parser, 0);
34 case DEVICE_TYPE_SUUNTO_VYPER:
35 if (devdata->devinfo.model == 0x01)
36 return suunto_eon_parser_create(parser, 1);
37 return suunto_vyper_parser_create(parser);
39 case DEVICE_TYPE_SUUNTO_VYPER2:
40 case DEVICE_TYPE_SUUNTO_D9:
41 return suunto_d9_parser_create(parser, devdata->devinfo.model);
43 case DEVICE_TYPE_UWATEC_ALADIN:
44 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
45 return uwatec_memomouse_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
47 case DEVICE_TYPE_UWATEC_SMART:
48 return uwatec_smart_parser_create(parser, devdata->devinfo.model, devdata->clock.devtime, devdata->clock.systime);
50 case DEVICE_TYPE_REEFNET_SENSUS:
51 return reefnet_sensus_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
53 case DEVICE_TYPE_REEFNET_SENSUSPRO:
54 return reefnet_sensuspro_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
56 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
57 return reefnet_sensusultra_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
59 case DEVICE_TYPE_OCEANIC_VTPRO:
60 return oceanic_vtpro_parser_create(parser);
62 case DEVICE_TYPE_OCEANIC_VEO250:
63 return oceanic_veo250_parser_create(parser, devdata->devinfo.model);
65 case DEVICE_TYPE_OCEANIC_ATOM2:
66 return oceanic_atom2_parser_create(parser, devdata->devinfo.model);
68 case DEVICE_TYPE_MARES_NEMO:
69 case DEVICE_TYPE_MARES_PUCK:
70 return mares_nemo_parser_create(parser, devdata->devinfo.model);
72 case DEVICE_TYPE_MARES_ICONHD:
73 return mares_iconhd_parser_create(parser);
75 case DEVICE_TYPE_HW_OSTC:
76 return hw_ostc_parser_create(parser);
78 case DEVICE_TYPE_CRESSI_EDY:
79 case DEVICE_TYPE_ZEAGLE_N2ITION3:
80 return cressi_edy_parser_create(parser, devdata->devinfo.model);
82 case DEVICE_TYPE_ATOMICS_COBALT:
83 return atomics_cobalt_parser_create(parser);
86 return PARSER_STATUS_ERROR;
90 static int parse_gasmixes(struct dive *dive, parser_t *parser, int ngases)
94 for (i = 0; i < ngases; i++) {
96 gasmix_t gasmix = {0};
99 rc = parser_get_field(parser, FIELD_TYPE_GASMIX, i, &gasmix);
100 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED)
103 if (i >= MAX_CYLINDERS)
106 o2 = gasmix.oxygen * 1000 + 0.5;
107 he = gasmix.helium * 1000 + 0.5;
109 /* Ignore bogus data - libdivecomputer does some crazy stuff */
110 if (o2 < 210 || o2 >= 1000)
112 if (he < 0 || he >= 800 || o2+he >= 1000)
115 dive->cylinder[i].gasmix.o2.permille = o2;
116 dive->cylinder[i].gasmix.he.permille = he;
118 return PARSER_STATUS_SUCCESS;
121 static void handle_event(struct dive *dive, struct sample *sample, parser_sample_value_t value)
124 static const char *events[] = {
125 "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
126 "violation", "bookmark", "surface", "safety stop", "gaschange",
127 "safety stop (voluntary)", "safety stop (mandatory)", "deepstop",
128 "ceiling (safety stop)", "unknown", "divetime", "maxdepth",
129 "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning"
131 const int nr_events = sizeof(events) / sizeof(const char *);
135 * Just ignore surface events. They are pointless. What "surface"
136 * means depends on the dive computer (and possibly even settings
137 * in the dive computer). It does *not* necessarily mean "depth 0",
138 * so don't even turn it into that.
140 if (value.event.type == SAMPLE_EVENT_SURFACE)
144 * Other evens might be more interesting, but for now we just print them out.
146 type = value.event.type;
147 name = "invalid event number";
148 if (type < nr_events)
151 time = value.event.time;
153 time += sample->time.seconds;
155 add_event(dive, time, type, value.event.flags, value.event.value, name);
159 sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata)
162 struct dive **divep = userdata;
163 struct dive *dive = *divep;
164 struct sample *sample;
167 * We fill in the "previous" sample - except for SAMPLE_TYPE_TIME,
168 * which creates a new one.
170 sample = dive->samples ? dive->sample+dive->samples-1 : NULL;
173 case SAMPLE_TYPE_TIME:
174 sample = prepare_sample(divep);
175 sample->time.seconds = value.time;
176 finish_sample(*divep, sample);
178 case SAMPLE_TYPE_DEPTH:
179 sample->depth.mm = value.depth * 1000 + 0.5;
181 case SAMPLE_TYPE_PRESSURE:
182 sample->cylinderindex = value.pressure.tank;
183 sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5;
185 case SAMPLE_TYPE_TEMPERATURE:
186 sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5;
188 case SAMPLE_TYPE_EVENT:
189 handle_event(dive, sample, value);
191 case SAMPLE_TYPE_RBT:
192 printf(" <rbt>%u</rbt>\n", value.rbt);
194 case SAMPLE_TYPE_HEARTBEAT:
195 printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat);
197 case SAMPLE_TYPE_BEARING:
198 printf(" <bearing>%u</bearing>\n", value.bearing);
200 case SAMPLE_TYPE_VENDOR:
201 printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
202 for (i = 0; i < value.vendor.size; ++i)
203 printf("%02X", ((unsigned char *) value.vendor.data)[i]);
204 printf("</vendor>\n");
212 static int parse_samples(struct dive **divep, parser_t *parser)
214 // Parse the sample data.
215 printf("Parsing the sample data.\n");
216 return parser_samples_foreach(parser, sample_cb, divep);
219 static int dive_cb(const unsigned char *data, unsigned int size,
220 const unsigned char *fingerprint, unsigned int fsize,
224 parser_t *parser = NULL;
225 device_data_t *devdata = userdata;
226 dc_datetime_t dt = {0};
230 rc = create_parser(devdata, &parser);
231 if (rc != PARSER_STATUS_SUCCESS) {
232 fprintf(stderr, "Unable to create parser for %s", devdata->name);
236 rc = parser_set_data(parser, data, size);
237 if (rc != PARSER_STATUS_SUCCESS) {
238 fprintf(stderr, "Error registering the data.");
239 parser_destroy(parser);
244 rc = parser_get_datetime(parser, &dt);
245 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
246 fprintf(stderr, "Error parsing the datetime.");
247 parser_destroy (parser);
251 tm.tm_year = dt.year;
252 tm.tm_mon = dt.month-1;
254 tm.tm_hour = dt.hour;
255 tm.tm_min = dt.minute;
256 tm.tm_sec = dt.second;
257 dive->when = utc_mktime(&tm);
259 // Parse the divetime.
260 printf("Parsing the divetime.\n");
261 unsigned int divetime = 0;
262 rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
263 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
264 fprintf(stderr, "Error parsing the divetime.");
265 parser_destroy(parser);
268 dive->duration.seconds = divetime;
270 // Parse the maxdepth.
271 printf("Parsing the maxdepth.\n");
272 double maxdepth = 0.0;
273 rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
274 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
275 fprintf(stderr, "Error parsing the maxdepth.");
276 parser_destroy(parser);
279 dive->maxdepth.mm = maxdepth * 1000 + 0.5;
281 // Parse the gas mixes.
282 printf("Parsing the gas mixes.\n");
283 unsigned int ngases = 0;
284 rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
285 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
286 fprintf(stderr, "Error parsing the gas mix count.");
287 parser_destroy(parser);
291 rc = parse_gasmixes(dive, parser, ngases);
292 if (rc != PARSER_STATUS_SUCCESS) {
293 fprintf(stderr, "Error parsing the gas mix.");
294 parser_destroy(parser);
298 // Initialize the sample data.
299 rc = parse_samples(&dive, parser);
300 if (rc != PARSER_STATUS_SUCCESS) {
301 fprintf(stderr, "Error parsing the samples.");
302 parser_destroy(parser);
307 parser_destroy(parser);
312 static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
314 return device_foreach(device, dive_cb, devicedata);
317 static device_status_t device_open(const char *devname,
322 case DEVICE_TYPE_SUUNTO_SOLUTION:
323 return suunto_solution_device_open(device, devname);
325 case DEVICE_TYPE_SUUNTO_EON:
326 return suunto_eon_device_open(device, devname);
328 case DEVICE_TYPE_SUUNTO_VYPER:
329 return suunto_vyper_device_open(device, devname);
331 case DEVICE_TYPE_SUUNTO_VYPER2:
332 return suunto_vyper2_device_open(device, devname);
334 case DEVICE_TYPE_SUUNTO_D9:
335 return suunto_d9_device_open(device, devname);
337 case DEVICE_TYPE_UWATEC_ALADIN:
338 return uwatec_aladin_device_open(device, devname);
340 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
341 return uwatec_memomouse_device_open(device, devname);
343 case DEVICE_TYPE_UWATEC_SMART:
344 return uwatec_smart_device_open(device);
346 case DEVICE_TYPE_REEFNET_SENSUS:
347 return reefnet_sensus_device_open(device, devname);
349 case DEVICE_TYPE_REEFNET_SENSUSPRO:
350 return reefnet_sensuspro_device_open(device, devname);
352 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
353 return reefnet_sensusultra_device_open(device, devname);
355 case DEVICE_TYPE_OCEANIC_VTPRO:
356 return oceanic_vtpro_device_open(device, devname);
358 case DEVICE_TYPE_OCEANIC_VEO250:
359 return oceanic_veo250_device_open(device, devname);
361 case DEVICE_TYPE_OCEANIC_ATOM2:
362 return oceanic_atom2_device_open(device, devname);
364 case DEVICE_TYPE_MARES_NEMO:
365 return mares_nemo_device_open(device, devname);
367 case DEVICE_TYPE_MARES_PUCK:
368 return mares_puck_device_open(device, devname);
370 case DEVICE_TYPE_MARES_ICONHD:
371 return mares_iconhd_device_open(device, devname);
373 case DEVICE_TYPE_HW_OSTC:
374 return hw_ostc_device_open(device, devname);
376 case DEVICE_TYPE_CRESSI_EDY:
377 return cressi_edy_device_open(device, devname);
379 case DEVICE_TYPE_ZEAGLE_N2ITION3:
380 return zeagle_n2ition3_device_open(device, devname);
382 case DEVICE_TYPE_ATOMICS_COBALT:
383 return atomics_cobalt_device_open(device);
386 return DEVICE_STATUS_ERROR;
390 static void event_cb(device_t *device, device_event_t event, const void *data, void *userdata)
392 const device_progress_t *progress = (device_progress_t *) data;
393 const device_devinfo_t *devinfo = (device_devinfo_t *) data;
394 const device_clock_t *clock = (device_clock_t *) data;
395 device_data_t *devdata = (device_data_t *) userdata;
398 case DEVICE_EVENT_WAITING:
399 printf("Event: waiting for user action\n");
401 case DEVICE_EVENT_PROGRESS:
402 update_progressbar(&devdata->progress,
403 (double) progress->current / (double) progress->maximum);
405 case DEVICE_EVENT_DEVINFO:
406 devdata->devinfo = *devinfo;
407 printf("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n",
408 devinfo->model, devinfo->model,
409 devinfo->firmware, devinfo->firmware,
410 devinfo->serial, devinfo->serial);
412 case DEVICE_EVENT_CLOCK:
413 devdata->clock = *clock;
414 printf("Event: systime=%lld, devtime=%u\n",
415 clock->systime, clock->devtime);
422 static int import_thread_done = 0, import_thread_cancelled;
425 cancel_cb(void *userdata)
427 return import_thread_cancelled;
430 static const char *do_libdivecomputer_import(device_data_t *data)
432 device_t *device = NULL;
435 rc = device_open(data->devname, data->type, &device);
436 if (rc != DEVICE_STATUS_SUCCESS)
437 return "Unable to open %s (%s)";
439 // Register the event handler.
440 int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
441 rc = device_set_events(device, events, event_cb, data);
442 if (rc != DEVICE_STATUS_SUCCESS) {
443 device_close(device);
444 return "Error registering the event handler.";
447 // Register the cancellation handler.
448 rc = device_set_cancel(device, cancel_cb, data);
449 if (rc != DEVICE_STATUS_SUCCESS) {
450 device_close(device);
451 return "Error registering the cancellation handler.";
454 rc = import_device_data(device, data);
455 if (rc != DEVICE_STATUS_SUCCESS) {
456 device_close(device);
457 return "Dive data import error";
460 device_close(device);
464 static void *pthread_wrapper(void *_data)
466 device_data_t *data = _data;
467 const char *err_string = do_libdivecomputer_import(data);
468 import_thread_done = 1;
469 return (void *)err_string;
472 void do_import(device_data_t *data)
477 if (data->type == DEVICE_TYPE_UEMIS)
478 return uemis_import();
480 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
481 import_thread_done = 0;
482 pthread_create(&pthread, NULL, pthread_wrapper, data);
483 while (!import_thread_done) {
484 import_thread_cancelled = process_ui_events();
487 if (pthread_join(pthread, &retval) < 0)
488 retval = "Odd pthread error return";
490 error(retval, data->name, data->devname);
494 * Taken from 'example.c' in libdivecomputer.
496 * I really wish there was some way to just have
497 * libdivecomputer tell us what devices it supports,
498 * rather than have the application have to know..
500 struct device_list device_list[] = {
501 { "Suunto Solution", DEVICE_TYPE_SUUNTO_SOLUTION },
502 { "Suunto Eon", DEVICE_TYPE_SUUNTO_EON },
503 { "Suunto Vyper", DEVICE_TYPE_SUUNTO_VYPER },
504 { "Suunto Vyper Air", DEVICE_TYPE_SUUNTO_VYPER2 },
505 { "Suunto D9", DEVICE_TYPE_SUUNTO_D9 },
506 { "Uwatec Aladin", DEVICE_TYPE_UWATEC_ALADIN },
507 { "Uwatec Memo Mouse", DEVICE_TYPE_UWATEC_MEMOMOUSE },
508 { "Uwatec Smart", DEVICE_TYPE_UWATEC_SMART },
509 { "ReefNet Sensus", DEVICE_TYPE_REEFNET_SENSUS },
510 { "ReefNet Sensus Pro", DEVICE_TYPE_REEFNET_SENSUSPRO },
511 { "ReefNet Sensus Ultra",DEVICE_TYPE_REEFNET_SENSUSULTRA },
512 { "Oceanic VT Pro", DEVICE_TYPE_OCEANIC_VTPRO },
513 { "Oceanic Veo250", DEVICE_TYPE_OCEANIC_VEO250 },
514 { "Oceanic Atom 2", DEVICE_TYPE_OCEANIC_ATOM2 },
515 { "Mares Nemo", DEVICE_TYPE_MARES_NEMO },
516 { "Mares Puck", DEVICE_TYPE_MARES_PUCK },
517 { "Mares Icon HD", DEVICE_TYPE_MARES_ICONHD },
518 { "OSTC", DEVICE_TYPE_HW_OSTC },
519 { "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
520 { "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
521 { "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },
522 { "Uemis Zurich SDA", DEVICE_TYPE_UEMIS },