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 dc_status_t create_parser(device_data_t *devdata, dc_parser_t **parser)
36 return dc_parser_new(parser, devdata->device);
39 static int parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t *parser, int ngases)
43 for (i = 0; i < ngases; i++) {
45 dc_gasmix_t gasmix = {0};
48 rc = dc_parser_get_field(parser, DC_FIELD_GASMIX, i, &gasmix);
49 if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED)
52 if (i >= MAX_CYLINDERS)
55 o2 = gasmix.oxygen * 1000 + 0.5;
56 he = gasmix.helium * 1000 + 0.5;
58 /* Ignore bogus data - libdivecomputer does some crazy stuff */
59 if (o2 <= AIR_PERMILLE || o2 >= 1000)
61 if (he < 0 || he >= 800 || o2+he >= 1000)
64 dive->cylinder[i].gasmix.o2.permille = o2;
65 dive->cylinder[i].gasmix.he.permille = he;
67 return DC_STATUS_SUCCESS;
70 static void handle_event(struct dive *dive, struct sample *sample, dc_sample_value_t value)
73 static const char *events[] = {
74 "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
75 "violation", "bookmark", "surface", "safety stop", "gaschange",
76 "safety stop (voluntary)", "safety stop (mandatory)", "deepstop",
77 "ceiling (safety stop)", "unknown", "divetime", "maxdepth",
78 "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning"
80 const int nr_events = sizeof(events) / sizeof(const char *);
84 * Just ignore surface events. They are pointless. What "surface"
85 * means depends on the dive computer (and possibly even settings
86 * in the dive computer). It does *not* necessarily mean "depth 0",
87 * so don't even turn it into that.
89 if (value.event.type == SAMPLE_EVENT_SURFACE)
93 * Other evens might be more interesting, but for now we just print them out.
95 type = value.event.type;
96 name = "invalid event number";
100 time = value.event.time;
102 time += sample->time.seconds;
104 add_event(dive, time, type, value.event.flags, value.event.value, name);
108 sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata)
111 struct dive **divep = userdata;
112 struct dive *dive = *divep;
113 struct sample *sample;
116 * We fill in the "previous" sample - except for DC_SAMPLE_TIME,
117 * which creates a new one.
119 sample = dive->samples ? dive->sample+dive->samples-1 : NULL;
123 sample = prepare_sample(divep);
124 sample->time.seconds = value.time;
125 finish_sample(*divep);
127 case DC_SAMPLE_DEPTH:
128 sample->depth.mm = value.depth * 1000 + 0.5;
130 case DC_SAMPLE_PRESSURE:
131 sample->cylinderindex = value.pressure.tank;
132 sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5;
134 case DC_SAMPLE_TEMPERATURE:
135 sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5;
137 case DC_SAMPLE_EVENT:
138 handle_event(dive, sample, value);
141 printf(" <rbt>%u</rbt>\n", value.rbt);
143 case DC_SAMPLE_HEARTBEAT:
144 printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat);
146 case DC_SAMPLE_BEARING:
147 printf(" <bearing>%u</bearing>\n", value.bearing);
149 case DC_SAMPLE_VENDOR:
150 printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
151 for (i = 0; i < value.vendor.size; ++i)
152 printf("%02X", ((unsigned char *) value.vendor.data)[i]);
153 printf("</vendor>\n");
160 static void dev_info(device_data_t *devdata, const char *fmt, ...)
166 vsnprintf(buffer, sizeof(buffer), fmt, ap);
168 update_progressbar_text(&devdata->progress, buffer);
171 static int import_dive_number = 0;
173 static int parse_samples(device_data_t *devdata, struct dive **divep, dc_parser_t *parser)
175 // Parse the sample data.
176 return dc_parser_samples_foreach(parser, sample_cb, divep);
180 * Check if this dive already existed before the import
182 static int find_dive(struct dive *dive, device_data_t *devdata)
186 for (i = 0; i < dive_table.preexisting; i++) {
187 struct dive *old = dive_table.dives[i];
189 if (dive->when != old->when)
196 static inline int year(int year)
205 static int dive_cb(const unsigned char *data, unsigned int size,
206 const unsigned char *fingerprint, unsigned int fsize,
210 dc_parser_t *parser = NULL;
211 device_data_t *devdata = userdata;
212 dc_datetime_t dt = {0};
216 rc = create_parser(devdata, &parser);
217 if (rc != DC_STATUS_SUCCESS) {
218 dev_info(devdata, "Unable to create parser for %s %s", devdata->vendor, devdata->product);
222 rc = dc_parser_set_data(parser, data, size);
223 if (rc != DC_STATUS_SUCCESS) {
224 dev_info(devdata, "Error registering the data");
225 dc_parser_destroy(parser);
229 import_dive_number++;
231 rc = dc_parser_get_datetime(parser, &dt);
232 if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
233 dev_info(devdata, "Error parsing the datetime");
234 dc_parser_destroy(parser);
238 tm.tm_year = dt.year;
239 tm.tm_mon = dt.month-1;
241 tm.tm_hour = dt.hour;
242 tm.tm_min = dt.minute;
243 tm.tm_sec = dt.second;
244 dive->when = utc_mktime(&tm);
246 // Parse the divetime.
247 dev_info(devdata, "Dive %d: %s %d %04d", import_dive_number,
248 monthname(tm.tm_mon), tm.tm_mday, year(tm.tm_year));
249 unsigned int divetime = 0;
250 rc = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime);
251 if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
252 dev_info(devdata, "Error parsing the divetime");
253 dc_parser_destroy(parser);
256 dive->duration.seconds = divetime;
258 // Parse the maxdepth.
259 double maxdepth = 0.0;
260 rc = dc_parser_get_field(parser, DC_FIELD_MAXDEPTH, 0, &maxdepth);
261 if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
262 dev_info(devdata, "Error parsing the maxdepth");
263 dc_parser_destroy(parser);
266 dive->maxdepth.mm = maxdepth * 1000 + 0.5;
268 // Parse the gas mixes.
269 unsigned int ngases = 0;
270 rc = dc_parser_get_field(parser, DC_FIELD_GASMIX_COUNT, 0, &ngases);
271 if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
272 dev_info(devdata, "Error parsing the gas mix count");
273 dc_parser_destroy(parser);
277 rc = parse_gasmixes(devdata, dive, parser, ngases);
278 if (rc != DC_STATUS_SUCCESS) {
279 dev_info(devdata, "Error parsing the gas mix");
280 dc_parser_destroy(parser);
284 // Initialize the sample data.
285 rc = parse_samples(devdata, &dive, parser);
286 if (rc != DC_STATUS_SUCCESS) {
287 dev_info(devdata, "Error parsing the samples");
288 dc_parser_destroy(parser);
292 dc_parser_destroy(parser);
294 /* If we already saw this dive, abort. */
295 if (find_dive(dive, devdata))
303 static dc_status_t import_device_data(dc_device_t *device, device_data_t *devicedata)
305 return dc_device_foreach(device, dive_cb, devicedata);
308 static dc_status_t device_open(const char *devname,
309 dc_descriptor_t *descriptor,
310 dc_device_t **device)
312 return dc_device_open(device, descriptor, devname);
316 static void event_cb(dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
318 const dc_event_progress_t *progress = data;
319 const dc_event_devinfo_t *devinfo = data;
320 const dc_event_clock_t *clock = data;
321 device_data_t *devdata = userdata;
324 case DC_EVENT_WAITING:
325 dev_info(devdata, "Event: waiting for user action");
327 case DC_EVENT_PROGRESS:
328 update_progressbar(&devdata->progress,
329 (double) progress->current / (double) progress->maximum);
331 case DC_EVENT_DEVINFO:
332 dev_info(devdata, "model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)",
333 devinfo->model, devinfo->model,
334 devinfo->firmware, devinfo->firmware,
335 devinfo->serial, devinfo->serial);
338 dev_info(devdata, "Event: systime=%"PRId64", devtime=%u\n",
339 (uint64_t)clock->systime, clock->devtime);
346 static int import_thread_done = 0, import_thread_cancelled;
349 cancel_cb(void *userdata)
351 return import_thread_cancelled;
354 static const char *do_libdivecomputer_import(device_data_t *data)
356 dc_device_t *device = NULL;
359 import_dive_number = 0;
360 rc = device_open(data->devname, data->descriptor, &device);
361 if (rc != DC_STATUS_SUCCESS)
362 return "Unable to open %s %s (%s)";
363 data->device = device;
365 // Register the event handler.
366 int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK;
367 rc = dc_device_set_events(device, events, event_cb, data);
368 if (rc != DC_STATUS_SUCCESS) {
369 dc_device_close(device);
370 return "Error registering the event handler.";
373 // Register the cancellation handler.
374 rc = dc_device_set_cancel(device, cancel_cb, data);
375 if (rc != DC_STATUS_SUCCESS) {
376 dc_device_close(device);
377 return "Error registering the cancellation handler.";
380 rc = import_device_data(device, data);
381 if (rc != DC_STATUS_SUCCESS) {
382 dc_device_close(device);
383 return "Dive data import error";
386 dc_device_close(device);
390 static void *pthread_wrapper(void *_data)
392 device_data_t *data = _data;
393 const char *err_string = do_libdivecomputer_import(data);
394 import_thread_done = 1;
395 return (void *)err_string;
398 GError *do_import(device_data_t *data)
403 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
404 import_thread_done = 0;
405 pthread_create(&pthread, NULL, pthread_wrapper, data);
406 while (!import_thread_done) {
407 import_thread_cancelled = process_ui_events();
410 if (pthread_join(pthread, &retval) < 0)
411 retval = "Odd pthread error return";
413 return error(retval, data->vendor, data->product, data->devname);