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 **divep, struct sample *sample, parser_sample_value_t value)
123 static const char *events[] = {
124 "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
125 "violation", "bookmark", "surface", "safety stop", "gaschange",
126 "safety stop (voluntary)", "safety stop (mandatory)", "deepstop",
127 "ceiling (safety stop)", "unknown", "divetime", "maxdepth",
128 "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning"};
130 printf(" <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\n",
131 value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]);
136 sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata)
139 struct dive **divep = userdata;
140 struct dive *dive = *divep;
141 struct sample *sample;
144 * We fill in the "previous" sample - except for SAMPLE_TYPE_TIME,
145 * which creates a new one.
147 sample = dive->samples ? dive->sample+dive->samples-1 : NULL;
150 case SAMPLE_TYPE_TIME:
151 sample = prepare_sample(divep);
152 sample->time.seconds = value.time;
153 finish_sample(*divep, sample);
155 case SAMPLE_TYPE_DEPTH:
156 sample->depth.mm = value.depth * 1000 + 0.5;
158 case SAMPLE_TYPE_PRESSURE:
159 sample->cylinderindex = value.pressure.tank;
160 sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5;
162 case SAMPLE_TYPE_TEMPERATURE:
163 sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5;
165 case SAMPLE_TYPE_EVENT:
166 handle_event(divep, sample, value);
168 case SAMPLE_TYPE_RBT:
169 printf(" <rbt>%u</rbt>\n", value.rbt);
171 case SAMPLE_TYPE_HEARTBEAT:
172 printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat);
174 case SAMPLE_TYPE_BEARING:
175 printf(" <bearing>%u</bearing>\n", value.bearing);
177 case SAMPLE_TYPE_VENDOR:
178 printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
179 for (i = 0; i < value.vendor.size; ++i)
180 printf("%02X", ((unsigned char *) value.vendor.data)[i]);
181 printf("</vendor>\n");
189 static int parse_samples(struct dive **divep, parser_t *parser)
191 // Parse the sample data.
192 printf("Parsing the sample data.\n");
193 return parser_samples_foreach(parser, sample_cb, divep);
196 static int dive_cb(const unsigned char *data, unsigned int size,
197 const unsigned char *fingerprint, unsigned int fsize,
201 parser_t *parser = NULL;
202 device_data_t *devdata = userdata;
203 dc_datetime_t dt = {0};
207 rc = create_parser(devdata, &parser);
208 if (rc != PARSER_STATUS_SUCCESS) {
209 fprintf(stderr, "Unable to create parser for %s", devdata->name);
213 rc = parser_set_data(parser, data, size);
214 if (rc != PARSER_STATUS_SUCCESS) {
215 fprintf(stderr, "Error registering the data.");
216 parser_destroy(parser);
221 rc = parser_get_datetime(parser, &dt);
222 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
223 fprintf(stderr, "Error parsing the datetime.");
224 parser_destroy (parser);
228 tm.tm_year = dt.year;
229 tm.tm_mon = dt.month-1;
231 tm.tm_hour = dt.hour;
232 tm.tm_min = dt.minute;
233 tm.tm_sec = dt.second;
234 dive->when = utc_mktime(&tm);
236 // Parse the divetime.
237 printf("Parsing the divetime.\n");
238 unsigned int divetime = 0;
239 rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
240 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
241 fprintf(stderr, "Error parsing the divetime.");
242 parser_destroy(parser);
245 dive->duration.seconds = divetime;
247 // Parse the maxdepth.
248 printf("Parsing the maxdepth.\n");
249 double maxdepth = 0.0;
250 rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
251 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
252 fprintf(stderr, "Error parsing the maxdepth.");
253 parser_destroy(parser);
256 dive->maxdepth.mm = maxdepth * 1000 + 0.5;
258 // Parse the gas mixes.
259 printf("Parsing the gas mixes.\n");
260 unsigned int ngases = 0;
261 rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
262 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
263 fprintf(stderr, "Error parsing the gas mix count.");
264 parser_destroy(parser);
268 rc = parse_gasmixes(dive, parser, ngases);
269 if (rc != PARSER_STATUS_SUCCESS) {
270 fprintf(stderr, "Error parsing the gas mix.");
271 parser_destroy(parser);
275 // Initialize the sample data.
276 rc = parse_samples(&dive, parser);
277 if (rc != PARSER_STATUS_SUCCESS) {
278 fprintf(stderr, "Error parsing the samples.");
279 parser_destroy(parser);
284 parser_destroy(parser);
289 static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
291 return device_foreach(device, dive_cb, devicedata);
294 static device_status_t device_open(const char *devname,
299 case DEVICE_TYPE_SUUNTO_SOLUTION:
300 return suunto_solution_device_open(device, devname);
302 case DEVICE_TYPE_SUUNTO_EON:
303 return suunto_eon_device_open(device, devname);
305 case DEVICE_TYPE_SUUNTO_VYPER:
306 return suunto_vyper_device_open(device, devname);
308 case DEVICE_TYPE_SUUNTO_VYPER2:
309 return suunto_vyper2_device_open(device, devname);
311 case DEVICE_TYPE_SUUNTO_D9:
312 return suunto_d9_device_open(device, devname);
314 case DEVICE_TYPE_UWATEC_ALADIN:
315 return uwatec_aladin_device_open(device, devname);
317 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
318 return uwatec_memomouse_device_open(device, devname);
320 case DEVICE_TYPE_UWATEC_SMART:
321 return uwatec_smart_device_open(device);
323 case DEVICE_TYPE_REEFNET_SENSUS:
324 return reefnet_sensus_device_open(device, devname);
326 case DEVICE_TYPE_REEFNET_SENSUSPRO:
327 return reefnet_sensuspro_device_open(device, devname);
329 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
330 return reefnet_sensusultra_device_open(device, devname);
332 case DEVICE_TYPE_OCEANIC_VTPRO:
333 return oceanic_vtpro_device_open(device, devname);
335 case DEVICE_TYPE_OCEANIC_VEO250:
336 return oceanic_veo250_device_open(device, devname);
338 case DEVICE_TYPE_OCEANIC_ATOM2:
339 return oceanic_atom2_device_open(device, devname);
341 case DEVICE_TYPE_MARES_NEMO:
342 return mares_nemo_device_open(device, devname);
344 case DEVICE_TYPE_MARES_PUCK:
345 return mares_puck_device_open(device, devname);
347 case DEVICE_TYPE_MARES_ICONHD:
348 return mares_iconhd_device_open(device, devname);
350 case DEVICE_TYPE_HW_OSTC:
351 return hw_ostc_device_open(device, devname);
353 case DEVICE_TYPE_CRESSI_EDY:
354 return cressi_edy_device_open(device, devname);
356 case DEVICE_TYPE_ZEAGLE_N2ITION3:
357 return zeagle_n2ition3_device_open(device, devname);
359 case DEVICE_TYPE_ATOMICS_COBALT:
360 return atomics_cobalt_device_open(device);
363 return DEVICE_STATUS_ERROR;
367 static void event_cb(device_t *device, device_event_t event, const void *data, void *userdata)
369 const device_progress_t *progress = (device_progress_t *) data;
370 const device_devinfo_t *devinfo = (device_devinfo_t *) data;
371 const device_clock_t *clock = (device_clock_t *) data;
372 device_data_t *devdata = (device_data_t *) userdata;
375 case DEVICE_EVENT_WAITING:
376 printf("Event: waiting for user action\n");
378 case DEVICE_EVENT_PROGRESS:
379 update_progressbar(&devdata->progress,
380 (double) progress->current / (double) progress->maximum);
382 case DEVICE_EVENT_DEVINFO:
383 devdata->devinfo = *devinfo;
384 printf("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n",
385 devinfo->model, devinfo->model,
386 devinfo->firmware, devinfo->firmware,
387 devinfo->serial, devinfo->serial);
389 case DEVICE_EVENT_CLOCK:
390 devdata->clock = *clock;
391 printf("Event: systime=%lld, devtime=%u\n",
392 clock->systime, clock->devtime);
399 static int import_thread_done = 0, import_thread_cancelled;
402 cancel_cb(void *userdata)
404 return import_thread_cancelled;
407 static const char *do_libdivecomputer_import(device_data_t *data)
409 device_t *device = NULL;
412 rc = device_open(data->devname, data->type, &device);
413 if (rc != DEVICE_STATUS_SUCCESS)
414 return "Unable to open %s (%s)";
416 // Register the event handler.
417 int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
418 rc = device_set_events(device, events, event_cb, data);
419 if (rc != DEVICE_STATUS_SUCCESS) {
420 device_close(device);
421 return "Error registering the event handler.";
424 // Register the cancellation handler.
425 rc = device_set_cancel(device, cancel_cb, data);
426 if (rc != DEVICE_STATUS_SUCCESS) {
427 device_close(device);
428 return "Error registering the cancellation handler.";
431 rc = import_device_data(device, data);
432 if (rc != DEVICE_STATUS_SUCCESS) {
433 device_close(device);
434 return "Dive data import error";
437 device_close(device);
441 static void *pthread_wrapper(void *_data)
443 device_data_t *data = _data;
444 const char *err_string = do_libdivecomputer_import(data);
445 import_thread_done = 1;
446 return (void *)err_string;
449 void do_import(device_data_t *data)
454 if (data->type == DEVICE_TYPE_UEMIS)
455 return uemis_import();
457 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
458 import_thread_done = 0;
459 pthread_create(&pthread, NULL, pthread_wrapper, data);
460 while (!import_thread_done) {
461 import_thread_cancelled = process_ui_events();
464 if (pthread_join(pthread, &retval) < 0)
465 retval = "Odd pthread error return";
467 error(retval, data->name, data->devname);
471 * Taken from 'example.c' in libdivecomputer.
473 * I really wish there was some way to just have
474 * libdivecomputer tell us what devices it supports,
475 * rather than have the application have to know..
477 struct device_list device_list[] = {
478 { "Suunto Solution", DEVICE_TYPE_SUUNTO_SOLUTION },
479 { "Suunto Eon", DEVICE_TYPE_SUUNTO_EON },
480 { "Suunto Vyper", DEVICE_TYPE_SUUNTO_VYPER },
481 { "Suunto Vyper Air", DEVICE_TYPE_SUUNTO_VYPER2 },
482 { "Suunto D9", DEVICE_TYPE_SUUNTO_D9 },
483 { "Uwatec Aladin", DEVICE_TYPE_UWATEC_ALADIN },
484 { "Uwatec Memo Mouse", DEVICE_TYPE_UWATEC_MEMOMOUSE },
485 { "Uwatec Smart", DEVICE_TYPE_UWATEC_SMART },
486 { "ReefNet Sensus", DEVICE_TYPE_REEFNET_SENSUS },
487 { "ReefNet Sensus Pro", DEVICE_TYPE_REEFNET_SENSUSPRO },
488 { "ReefNet Sensus Ultra",DEVICE_TYPE_REEFNET_SENSUSULTRA },
489 { "Oceanic VT Pro", DEVICE_TYPE_OCEANIC_VTPRO },
490 { "Oceanic Veo250", DEVICE_TYPE_OCEANIC_VEO250 },
491 { "Oceanic Atom 2", DEVICE_TYPE_OCEANIC_ATOM2 },
492 { "Mares Nemo", DEVICE_TYPE_MARES_NEMO },
493 { "Mares Puck", DEVICE_TYPE_MARES_PUCK },
494 { "Mares Icon HD", DEVICE_TYPE_MARES_ICONHD },
495 { "OSTC", DEVICE_TYPE_HW_OSTC },
496 { "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
497 { "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
498 { "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },
499 { "Uemis Zurich SDA", DEVICE_TYPE_UEMIS },