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)
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 printf(" <event type=\"%u\" time=\"%u:%02u\" flags=\"%u\" value=\"%u\" name=\"%s\" />\n",
156 type, time / 60, time % 60,
157 value.event.flags, value.event.value, name);
161 sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata)
164 struct dive **divep = userdata;
165 struct dive *dive = *divep;
166 struct sample *sample;
169 * We fill in the "previous" sample - except for SAMPLE_TYPE_TIME,
170 * which creates a new one.
172 sample = dive->samples ? dive->sample+dive->samples-1 : NULL;
175 case SAMPLE_TYPE_TIME:
176 sample = prepare_sample(divep);
177 sample->time.seconds = value.time;
178 finish_sample(*divep, sample);
180 case SAMPLE_TYPE_DEPTH:
181 sample->depth.mm = value.depth * 1000 + 0.5;
183 case SAMPLE_TYPE_PRESSURE:
184 sample->cylinderindex = value.pressure.tank;
185 sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5;
187 case SAMPLE_TYPE_TEMPERATURE:
188 sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5;
190 case SAMPLE_TYPE_EVENT:
191 handle_event(divep, sample, value);
193 case SAMPLE_TYPE_RBT:
194 printf(" <rbt>%u</rbt>\n", value.rbt);
196 case SAMPLE_TYPE_HEARTBEAT:
197 printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat);
199 case SAMPLE_TYPE_BEARING:
200 printf(" <bearing>%u</bearing>\n", value.bearing);
202 case SAMPLE_TYPE_VENDOR:
203 printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
204 for (i = 0; i < value.vendor.size; ++i)
205 printf("%02X", ((unsigned char *) value.vendor.data)[i]);
206 printf("</vendor>\n");
214 static int parse_samples(struct dive **divep, parser_t *parser)
216 // Parse the sample data.
217 printf("Parsing the sample data.\n");
218 return parser_samples_foreach(parser, sample_cb, divep);
221 static int dive_cb(const unsigned char *data, unsigned int size,
222 const unsigned char *fingerprint, unsigned int fsize,
226 parser_t *parser = NULL;
227 device_data_t *devdata = userdata;
228 dc_datetime_t dt = {0};
232 rc = create_parser(devdata, &parser);
233 if (rc != PARSER_STATUS_SUCCESS) {
234 fprintf(stderr, "Unable to create parser for %s", devdata->name);
238 rc = parser_set_data(parser, data, size);
239 if (rc != PARSER_STATUS_SUCCESS) {
240 fprintf(stderr, "Error registering the data.");
241 parser_destroy(parser);
246 rc = parser_get_datetime(parser, &dt);
247 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
248 fprintf(stderr, "Error parsing the datetime.");
249 parser_destroy (parser);
253 tm.tm_year = dt.year;
254 tm.tm_mon = dt.month-1;
256 tm.tm_hour = dt.hour;
257 tm.tm_min = dt.minute;
258 tm.tm_sec = dt.second;
259 dive->when = utc_mktime(&tm);
261 // Parse the divetime.
262 printf("Parsing the divetime.\n");
263 unsigned int divetime = 0;
264 rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
265 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
266 fprintf(stderr, "Error parsing the divetime.");
267 parser_destroy(parser);
270 dive->duration.seconds = divetime;
272 // Parse the maxdepth.
273 printf("Parsing the maxdepth.\n");
274 double maxdepth = 0.0;
275 rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
276 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
277 fprintf(stderr, "Error parsing the maxdepth.");
278 parser_destroy(parser);
281 dive->maxdepth.mm = maxdepth * 1000 + 0.5;
283 // Parse the gas mixes.
284 printf("Parsing the gas mixes.\n");
285 unsigned int ngases = 0;
286 rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
287 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
288 fprintf(stderr, "Error parsing the gas mix count.");
289 parser_destroy(parser);
293 rc = parse_gasmixes(dive, parser, ngases);
294 if (rc != PARSER_STATUS_SUCCESS) {
295 fprintf(stderr, "Error parsing the gas mix.");
296 parser_destroy(parser);
300 // Initialize the sample data.
301 rc = parse_samples(&dive, parser);
302 if (rc != PARSER_STATUS_SUCCESS) {
303 fprintf(stderr, "Error parsing the samples.");
304 parser_destroy(parser);
309 parser_destroy(parser);
314 static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
316 return device_foreach(device, dive_cb, devicedata);
319 static device_status_t device_open(const char *devname,
324 case DEVICE_TYPE_SUUNTO_SOLUTION:
325 return suunto_solution_device_open(device, devname);
327 case DEVICE_TYPE_SUUNTO_EON:
328 return suunto_eon_device_open(device, devname);
330 case DEVICE_TYPE_SUUNTO_VYPER:
331 return suunto_vyper_device_open(device, devname);
333 case DEVICE_TYPE_SUUNTO_VYPER2:
334 return suunto_vyper2_device_open(device, devname);
336 case DEVICE_TYPE_SUUNTO_D9:
337 return suunto_d9_device_open(device, devname);
339 case DEVICE_TYPE_UWATEC_ALADIN:
340 return uwatec_aladin_device_open(device, devname);
342 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
343 return uwatec_memomouse_device_open(device, devname);
345 case DEVICE_TYPE_UWATEC_SMART:
346 return uwatec_smart_device_open(device);
348 case DEVICE_TYPE_REEFNET_SENSUS:
349 return reefnet_sensus_device_open(device, devname);
351 case DEVICE_TYPE_REEFNET_SENSUSPRO:
352 return reefnet_sensuspro_device_open(device, devname);
354 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
355 return reefnet_sensusultra_device_open(device, devname);
357 case DEVICE_TYPE_OCEANIC_VTPRO:
358 return oceanic_vtpro_device_open(device, devname);
360 case DEVICE_TYPE_OCEANIC_VEO250:
361 return oceanic_veo250_device_open(device, devname);
363 case DEVICE_TYPE_OCEANIC_ATOM2:
364 return oceanic_atom2_device_open(device, devname);
366 case DEVICE_TYPE_MARES_NEMO:
367 return mares_nemo_device_open(device, devname);
369 case DEVICE_TYPE_MARES_PUCK:
370 return mares_puck_device_open(device, devname);
372 case DEVICE_TYPE_MARES_ICONHD:
373 return mares_iconhd_device_open(device, devname);
375 case DEVICE_TYPE_HW_OSTC:
376 return hw_ostc_device_open(device, devname);
378 case DEVICE_TYPE_CRESSI_EDY:
379 return cressi_edy_device_open(device, devname);
381 case DEVICE_TYPE_ZEAGLE_N2ITION3:
382 return zeagle_n2ition3_device_open(device, devname);
384 case DEVICE_TYPE_ATOMICS_COBALT:
385 return atomics_cobalt_device_open(device);
388 return DEVICE_STATUS_ERROR;
392 static void event_cb(device_t *device, device_event_t event, const void *data, void *userdata)
394 const device_progress_t *progress = (device_progress_t *) data;
395 const device_devinfo_t *devinfo = (device_devinfo_t *) data;
396 const device_clock_t *clock = (device_clock_t *) data;
397 device_data_t *devdata = (device_data_t *) userdata;
400 case DEVICE_EVENT_WAITING:
401 printf("Event: waiting for user action\n");
403 case DEVICE_EVENT_PROGRESS:
404 update_progressbar(&devdata->progress,
405 (double) progress->current / (double) progress->maximum);
407 case DEVICE_EVENT_DEVINFO:
408 devdata->devinfo = *devinfo;
409 printf("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n",
410 devinfo->model, devinfo->model,
411 devinfo->firmware, devinfo->firmware,
412 devinfo->serial, devinfo->serial);
414 case DEVICE_EVENT_CLOCK:
415 devdata->clock = *clock;
416 printf("Event: systime=%lld, devtime=%u\n",
417 clock->systime, clock->devtime);
424 static int import_thread_done = 0, import_thread_cancelled;
427 cancel_cb(void *userdata)
429 return import_thread_cancelled;
432 static const char *do_libdivecomputer_import(device_data_t *data)
434 device_t *device = NULL;
437 rc = device_open(data->devname, data->type, &device);
438 if (rc != DEVICE_STATUS_SUCCESS)
439 return "Unable to open %s (%s)";
441 // Register the event handler.
442 int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
443 rc = device_set_events(device, events, event_cb, data);
444 if (rc != DEVICE_STATUS_SUCCESS) {
445 device_close(device);
446 return "Error registering the event handler.";
449 // Register the cancellation handler.
450 rc = device_set_cancel(device, cancel_cb, data);
451 if (rc != DEVICE_STATUS_SUCCESS) {
452 device_close(device);
453 return "Error registering the cancellation handler.";
456 rc = import_device_data(device, data);
457 if (rc != DEVICE_STATUS_SUCCESS) {
458 device_close(device);
459 return "Dive data import error";
462 device_close(device);
466 static void *pthread_wrapper(void *_data)
468 device_data_t *data = _data;
469 const char *err_string = do_libdivecomputer_import(data);
470 import_thread_done = 1;
471 return (void *)err_string;
474 void do_import(device_data_t *data)
479 if (data->type == DEVICE_TYPE_UEMIS)
480 return uemis_import();
482 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
483 import_thread_done = 0;
484 pthread_create(&pthread, NULL, pthread_wrapper, data);
485 while (!import_thread_done) {
486 import_thread_cancelled = process_ui_events();
489 if (pthread_join(pthread, &retval) < 0)
490 retval = "Odd pthread error return";
492 error(retval, data->name, data->devname);
496 * Taken from 'example.c' in libdivecomputer.
498 * I really wish there was some way to just have
499 * libdivecomputer tell us what devices it supports,
500 * rather than have the application have to know..
502 struct device_list device_list[] = {
503 { "Suunto Solution", DEVICE_TYPE_SUUNTO_SOLUTION },
504 { "Suunto Eon", DEVICE_TYPE_SUUNTO_EON },
505 { "Suunto Vyper", DEVICE_TYPE_SUUNTO_VYPER },
506 { "Suunto Vyper Air", DEVICE_TYPE_SUUNTO_VYPER2 },
507 { "Suunto D9", DEVICE_TYPE_SUUNTO_D9 },
508 { "Uwatec Aladin", DEVICE_TYPE_UWATEC_ALADIN },
509 { "Uwatec Memo Mouse", DEVICE_TYPE_UWATEC_MEMOMOUSE },
510 { "Uwatec Smart", DEVICE_TYPE_UWATEC_SMART },
511 { "ReefNet Sensus", DEVICE_TYPE_REEFNET_SENSUS },
512 { "ReefNet Sensus Pro", DEVICE_TYPE_REEFNET_SENSUSPRO },
513 { "ReefNet Sensus Ultra",DEVICE_TYPE_REEFNET_SENSUSULTRA },
514 { "Oceanic VT Pro", DEVICE_TYPE_OCEANIC_VTPRO },
515 { "Oceanic Veo250", DEVICE_TYPE_OCEANIC_VEO250 },
516 { "Oceanic Atom 2", DEVICE_TYPE_OCEANIC_ATOM2 },
517 { "Mares Nemo", DEVICE_TYPE_MARES_NEMO },
518 { "Mares Puck", DEVICE_TYPE_MARES_PUCK },
519 { "Mares Icon HD", DEVICE_TYPE_MARES_ICONHD },
520 { "OSTC", DEVICE_TYPE_HW_OSTC },
521 { "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
522 { "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
523 { "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },
524 { "Uemis Zurich SDA", DEVICE_TYPE_UEMIS },