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);
309 static void event_cb(dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
311 const dc_event_progress_t *progress = data;
312 const dc_event_devinfo_t *devinfo = data;
313 const dc_event_clock_t *clock = data;
314 device_data_t *devdata = userdata;
317 case DC_EVENT_WAITING:
318 dev_info(devdata, "Event: waiting for user action");
320 case DC_EVENT_PROGRESS:
321 update_progressbar(&devdata->progress,
322 (double) progress->current / (double) progress->maximum);
324 case DC_EVENT_DEVINFO:
325 dev_info(devdata, "model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)",
326 devinfo->model, devinfo->model,
327 devinfo->firmware, devinfo->firmware,
328 devinfo->serial, devinfo->serial);
331 dev_info(devdata, "Event: systime=%"PRId64", devtime=%u\n",
332 (uint64_t)clock->systime, clock->devtime);
339 static int import_thread_done = 0, import_thread_cancelled;
342 cancel_cb(void *userdata)
344 return import_thread_cancelled;
347 static const char *do_device_import(device_data_t *data)
350 dc_device_t *device = data->device;
352 // Register the event handler.
353 int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK;
354 rc = dc_device_set_events(device, events, event_cb, data);
355 if (rc != DC_STATUS_SUCCESS)
356 return "Error registering the event handler.";
358 // Register the cancellation handler.
359 rc = dc_device_set_cancel(device, cancel_cb, data);
360 if (rc != DC_STATUS_SUCCESS)
361 return "Error registering the cancellation handler.";
363 rc = import_device_data(device, data);
364 if (rc != DC_STATUS_SUCCESS)
365 return "Dive data import error";
371 static const char *do_libdivecomputer_import(device_data_t *data)
376 import_dive_number = 0;
378 data->context = NULL;
380 rc = dc_context_new(&data->context);
381 if (rc != DC_STATUS_SUCCESS)
382 return "Unable to create libdivecomputer context";
384 err = "Unable to open %s %s (%s)";
385 rc = dc_device_open(&data->device, data->context, data->descriptor, data->devname);
386 if (rc == DC_STATUS_SUCCESS) {
387 err = do_device_import(data);
388 dc_device_close(data->device);
390 dc_context_free(data->context);
394 static void *pthread_wrapper(void *_data)
396 device_data_t *data = _data;
397 const char *err_string = do_libdivecomputer_import(data);
398 import_thread_done = 1;
399 return (void *)err_string;
402 GError *do_import(device_data_t *data)
407 /* I'm sure there is some better interface for waiting on a thread in a UI main loop */
408 import_thread_done = 0;
409 pthread_create(&pthread, NULL, pthread_wrapper, data);
410 while (!import_thread_done) {
411 import_thread_cancelled = process_ui_events();
414 if (pthread_join(pthread, &retval) < 0)
415 retval = "Odd pthread error return";
417 return error(retval, data->vendor, data->product, data->devname);