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;
122 sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata)
125 static const char *events[] = {
126 "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
127 "violation", "bookmark", "surface", "safety stop", "gaschange",
128 "safety stop (voluntary)", "safety stop (mandatory)", "deepstop",
129 "ceiling (safety stop)", "unknown", "divetime", "maxdepth",
130 "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning"};
131 struct dive **divep = userdata;
132 struct dive *dive = *divep;
133 struct sample *sample;
136 * We fill in the "previous" sample - except for SAMPLE_TYPE_TIME,
137 * which creates a new one.
139 sample = dive->samples ? dive->sample+dive->samples-1 : NULL;
142 case SAMPLE_TYPE_TIME:
143 sample = prepare_sample(divep);
144 sample->time.seconds = value.time;
145 finish_sample(*divep, sample);
147 case SAMPLE_TYPE_DEPTH:
148 sample->depth.mm = value.depth * 1000 + 0.5;
150 case SAMPLE_TYPE_PRESSURE:
151 sample->cylinderindex = value.pressure.tank;
152 sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5;
154 case SAMPLE_TYPE_TEMPERATURE:
155 sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5;
157 case SAMPLE_TYPE_EVENT:
158 printf(" <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\n",
159 value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]);
161 case SAMPLE_TYPE_RBT:
162 printf(" <rbt>%u</rbt>\n", value.rbt);
164 case SAMPLE_TYPE_HEARTBEAT:
165 printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat);
167 case SAMPLE_TYPE_BEARING:
168 printf(" <bearing>%u</bearing>\n", value.bearing);
170 case SAMPLE_TYPE_VENDOR:
171 printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
172 for (i = 0; i < value.vendor.size; ++i)
173 printf("%02X", ((unsigned char *) value.vendor.data)[i]);
174 printf("</vendor>\n");
182 static int parse_samples(struct dive **divep, parser_t *parser)
184 // Parse the sample data.
185 printf("Parsing the sample data.\n");
186 return parser_samples_foreach(parser, sample_cb, divep);
189 static int dive_cb(const unsigned char *data, unsigned int size,
190 const unsigned char *fingerprint, unsigned int fsize,
194 parser_t *parser = NULL;
195 device_data_t *devdata = userdata;
196 dc_datetime_t dt = {0};
200 rc = create_parser(devdata, &parser);
201 if (rc != PARSER_STATUS_SUCCESS) {
202 fprintf(stderr, "Unable to create parser for %s", devdata->name);
206 rc = parser_set_data(parser, data, size);
207 if (rc != PARSER_STATUS_SUCCESS) {
208 fprintf(stderr, "Error registering the data.");
209 parser_destroy(parser);
214 rc = parser_get_datetime(parser, &dt);
215 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
216 fprintf(stderr, "Error parsing the datetime.");
217 parser_destroy (parser);
221 tm.tm_year = dt.year;
222 tm.tm_mon = dt.month-1;
224 tm.tm_hour = dt.hour;
225 tm.tm_min = dt.minute;
226 tm.tm_sec = dt.second;
227 dive->when = utc_mktime(&tm);
229 // Parse the divetime.
230 printf("Parsing the divetime.\n");
231 unsigned int divetime = 0;
232 rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
233 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
234 fprintf(stderr, "Error parsing the divetime.");
235 parser_destroy(parser);
238 dive->duration.seconds = divetime;
240 // Parse the maxdepth.
241 printf("Parsing the maxdepth.\n");
242 double maxdepth = 0.0;
243 rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
244 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
245 fprintf(stderr, "Error parsing the maxdepth.");
246 parser_destroy(parser);
249 dive->maxdepth.mm = maxdepth * 1000 + 0.5;
251 // Parse the gas mixes.
252 printf("Parsing the gas mixes.\n");
253 unsigned int ngases = 0;
254 rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
255 if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
256 fprintf(stderr, "Error parsing the gas mix count.");
257 parser_destroy(parser);
261 rc = parse_gasmixes(dive, parser, ngases);
262 if (rc != PARSER_STATUS_SUCCESS) {
263 fprintf(stderr, "Error parsing the gas mix.");
264 parser_destroy(parser);
268 // Initialize the sample data.
269 rc = parse_samples(&dive, parser);
270 if (rc != PARSER_STATUS_SUCCESS) {
271 fprintf(stderr, "Error parsing the samples.");
272 parser_destroy(parser);
277 parser_destroy(parser);
282 static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
284 return device_foreach(device, dive_cb, devicedata);
287 static device_status_t device_open(const char *devname,
292 case DEVICE_TYPE_SUUNTO_SOLUTION:
293 return suunto_solution_device_open(device, devname);
295 case DEVICE_TYPE_SUUNTO_EON:
296 return suunto_eon_device_open(device, devname);
298 case DEVICE_TYPE_SUUNTO_VYPER:
299 return suunto_vyper_device_open(device, devname);
301 case DEVICE_TYPE_SUUNTO_VYPER2:
302 return suunto_vyper2_device_open(device, devname);
304 case DEVICE_TYPE_SUUNTO_D9:
305 return suunto_d9_device_open(device, devname);
307 case DEVICE_TYPE_UWATEC_ALADIN:
308 return uwatec_aladin_device_open(device, devname);
310 case DEVICE_TYPE_UWATEC_MEMOMOUSE:
311 return uwatec_memomouse_device_open(device, devname);
313 case DEVICE_TYPE_UWATEC_SMART:
314 return uwatec_smart_device_open(device);
316 case DEVICE_TYPE_REEFNET_SENSUS:
317 return reefnet_sensus_device_open(device, devname);
319 case DEVICE_TYPE_REEFNET_SENSUSPRO:
320 return reefnet_sensuspro_device_open(device, devname);
322 case DEVICE_TYPE_REEFNET_SENSUSULTRA:
323 return reefnet_sensusultra_device_open(device, devname);
325 case DEVICE_TYPE_OCEANIC_VTPRO:
326 return oceanic_vtpro_device_open(device, devname);
328 case DEVICE_TYPE_OCEANIC_VEO250:
329 return oceanic_veo250_device_open(device, devname);
331 case DEVICE_TYPE_OCEANIC_ATOM2:
332 return oceanic_atom2_device_open(device, devname);
334 case DEVICE_TYPE_MARES_NEMO:
335 return mares_nemo_device_open(device, devname);
337 case DEVICE_TYPE_MARES_PUCK:
338 return mares_puck_device_open(device, devname);
340 case DEVICE_TYPE_MARES_ICONHD:
341 return mares_iconhd_device_open(device, devname);
343 case DEVICE_TYPE_HW_OSTC:
344 return hw_ostc_device_open(device, devname);
346 case DEVICE_TYPE_CRESSI_EDY:
347 return cressi_edy_device_open(device, devname);
349 case DEVICE_TYPE_ZEAGLE_N2ITION3:
350 return zeagle_n2ition3_device_open(device, devname);
352 case DEVICE_TYPE_ATOMICS_COBALT:
353 return atomics_cobalt_device_open(device);
356 return DEVICE_STATUS_ERROR;
360 static void event_cb(device_t *device, device_event_t event, const void *data, void *userdata)
362 const device_progress_t *progress = (device_progress_t *) data;
363 const device_devinfo_t *devinfo = (device_devinfo_t *) data;
364 const device_clock_t *clock = (device_clock_t *) data;
365 device_data_t *devdata = (device_data_t *) userdata;
368 case DEVICE_EVENT_WAITING:
369 printf("Event: waiting for user action\n");
371 case DEVICE_EVENT_PROGRESS:
372 update_progressbar(devdata->progress,
373 (double) progress->current / (double) progress->maximum);
375 case DEVICE_EVENT_DEVINFO:
376 devdata->devinfo = *devinfo;
377 printf("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n",
378 devinfo->model, devinfo->model,
379 devinfo->firmware, devinfo->firmware,
380 devinfo->serial, devinfo->serial);
382 case DEVICE_EVENT_CLOCK:
383 devdata->clock = *clock;
384 printf("Event: systime=%lld, devtime=%u\n",
385 clock->systime, clock->devtime);
392 static int import_thread_done = 0, import_thread_cancelled;
395 cancel_cb(void *userdata)
397 return import_thread_cancelled;
400 static const char *do_libdivecomputer_import(device_data_t *data)
402 device_t *device = NULL;
405 rc = device_open(data->devname, data->type, &device);
406 if (rc != DEVICE_STATUS_SUCCESS)
407 return "Unable to open %s (%s)";
409 // Register the event handler.
410 int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
411 rc = device_set_events(device, events, event_cb, data);
412 if (rc != DEVICE_STATUS_SUCCESS) {
413 device_close(device);
414 return "Error registering the event handler.";
417 // Register the cancellation handler.
418 rc = device_set_cancel(device, cancel_cb, data);
419 if (rc != DEVICE_STATUS_SUCCESS) {
420 device_close(device);
421 return "Error registering the cancellation handler.";
424 rc = import_device_data(device, data);
425 if (rc != DEVICE_STATUS_SUCCESS) {
426 device_close(device);
427 return "Dive data import error";
430 device_close(device);
434 static void *pthread_wrapper(void *_data)
436 device_data_t *data = _data;
437 const char *err_string = do_libdivecomputer_import(data);
438 import_thread_done = 1;
439 return (void *)err_string;
442 void do_import(device_data_t *data)
447 if (data->type == DEVICE_TYPE_UEMIS)
448 return uemis_import();
450 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
451 import_thread_done = 0;
452 pthread_create(&pthread, NULL, pthread_wrapper, data);
453 while (!import_thread_done) {
454 import_thread_cancelled = process_ui_events();
457 if (pthread_join(pthread, &retval) < 0)
458 retval = "Odd pthread error return";
460 error(retval, data->name, data->devname);
464 * Taken from 'example.c' in libdivecomputer.
466 * I really wish there was some way to just have
467 * libdivecomputer tell us what devices it supports,
468 * rather than have the application have to know..
470 struct device_list device_list[] = {
471 { "Suunto Solution", DEVICE_TYPE_SUUNTO_SOLUTION },
472 { "Suunto Eon", DEVICE_TYPE_SUUNTO_EON },
473 { "Suunto Vyper", DEVICE_TYPE_SUUNTO_VYPER },
474 { "Suunto Vyper Air", DEVICE_TYPE_SUUNTO_VYPER2 },
475 { "Suunto D9", DEVICE_TYPE_SUUNTO_D9 },
476 { "Uwatec Aladin", DEVICE_TYPE_UWATEC_ALADIN },
477 { "Uwatec Memo Mouse", DEVICE_TYPE_UWATEC_MEMOMOUSE },
478 { "Uwatec Smart", DEVICE_TYPE_UWATEC_SMART },
479 { "ReefNet Sensus", DEVICE_TYPE_REEFNET_SENSUS },
480 { "ReefNet Sensus Pro", DEVICE_TYPE_REEFNET_SENSUSPRO },
481 { "ReefNet Sensus Ultra",DEVICE_TYPE_REEFNET_SENSUSULTRA },
482 { "Oceanic VT Pro", DEVICE_TYPE_OCEANIC_VTPRO },
483 { "Oceanic Veo250", DEVICE_TYPE_OCEANIC_VEO250 },
484 { "Oceanic Atom 2", DEVICE_TYPE_OCEANIC_ATOM2 },
485 { "Mares Nemo", DEVICE_TYPE_MARES_NEMO },
486 { "Mares Puck", DEVICE_TYPE_MARES_PUCK },
487 { "Mares Icon HD", DEVICE_TYPE_MARES_ICONHD },
488 { "OSTC", DEVICE_TYPE_HW_OSTC },
489 { "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
490 { "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
491 { "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },
492 { "Uemis Zurich SDA", DEVICE_TYPE_UEMIS },