X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=libdivecomputer.c;h=2b62fa3652b58e556684ca87df48f7364573a6a6;hb=518ec33ba3bf9c5e9966ef108c1673223337b0fa;hp=c08b1175fe42654e1aa4b2c128b41c39e7b885d7;hpb=7d8fed4eee77ed8e011762bde6f5691f0fa81f39;p=ext%2Fsubsurface.git diff --git a/libdivecomputer.c b/libdivecomputer.c index c08b117..2b62fa3 100644 --- a/libdivecomputer.c +++ b/libdivecomputer.c @@ -2,6 +2,7 @@ #include #include "dive.h" +#include "divelist.h" #include "display.h" /* libdivecomputer */ @@ -17,6 +18,21 @@ #include #include +/* handling uemis Zurich SDA files */ +#include "uemis.h" + +/* + * I'd love to do a while-loop here for pending events, but + * that seems to screw up with the dive computer reading timing. + * + * I may need to spawn a new thread to do the computer + * reading stuff.. + */ +static int run_gtk_mainloop(void) +{ + return gtk_main_iteration_do(0); +} + static void error(const char *fmt, ...) { va_list args; @@ -33,7 +49,8 @@ static void error(const char *fmt, ...) typedef struct device_data_t { device_type_t type; - const char *name; + const char *name, *devname; + GtkWidget *progressbar; device_devinfo_t devinfo; device_clock_t clock; } device_data_t; @@ -103,6 +120,105 @@ static parser_status_t create_parser(device_data_t *devdata, parser_t **parser) } } +static int parse_gasmixes(struct dive *dive, parser_t *parser, int ngases) +{ + int i; + + for (i = 0; i < ngases; i++) { + int rc; + gasmix_t gasmix = {0}; + int o2, he; + + rc = parser_get_field(parser, FIELD_TYPE_GASMIX, i, &gasmix); + if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) + return rc; + + if (i >= MAX_CYLINDERS) + continue; + + o2 = gasmix.oxygen * 1000 + 0.5; + he = gasmix.helium * 1000 + 0.5; + + /* Ignore bogus data - libdivecomputer does some crazy stuff */ + if (o2 < 210 || o2 >= 1000) + o2 = 0; + if (he < 0 || he >= 800 || o2+he >= 1000) + he = 0; + + dive->cylinder[i].gasmix.o2.permille = o2; + dive->cylinder[i].gasmix.he.permille = he; + } + return PARSER_STATUS_SUCCESS; +} + +void +sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata) +{ + int i; + static const char *events[] = { + "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter", + "violation", "bookmark", "surface", "safety stop", "gaschange", + "safety stop (voluntary)", "safety stop (mandatory)", "deepstop", + "ceiling (safety stop)", "unknown", "divetime", "maxdepth", + "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning"}; + struct dive **divep = userdata; + struct dive *dive = *divep; + struct sample *sample; + + /* + * We fill in the "previous" sample - except for SAMPLE_TYPE_TIME, + * which creates a new one. + */ + sample = dive->samples ? dive->sample+dive->samples-1 : NULL; + + switch (type) { + case SAMPLE_TYPE_TIME: + sample = prepare_sample(divep); + sample->time.seconds = value.time; + finish_sample(*divep, sample); + break; + case SAMPLE_TYPE_DEPTH: + sample->depth.mm = value.depth * 1000 + 0.5; + break; + case SAMPLE_TYPE_PRESSURE: + sample->cylinderindex = value.pressure.tank; + sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5; + break; + case SAMPLE_TYPE_TEMPERATURE: + sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5; + break; + case SAMPLE_TYPE_EVENT: + printf(" %s\n", + value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]); + break; + case SAMPLE_TYPE_RBT: + printf(" %u\n", value.rbt); + break; + case SAMPLE_TYPE_HEARTBEAT: + printf(" %u\n", value.heartbeat); + break; + case SAMPLE_TYPE_BEARING: + printf(" %u\n", value.bearing); + break; + case SAMPLE_TYPE_VENDOR: + printf(" ", value.vendor.type, value.vendor.size); + for (i = 0; i < value.vendor.size; ++i) + printf("%02X", ((unsigned char *) value.vendor.data)[i]); + printf("\n"); + break; + default: + break; + } +} + + +static int parse_samples(struct dive **divep, parser_t *parser) +{ + // Parse the sample data. + printf("Parsing the sample data.\n"); + return parser_samples_foreach(parser, sample_cb, divep); +} + static int dive_cb(const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata) @@ -111,6 +227,11 @@ static int dive_cb(const unsigned char *data, unsigned int size, parser_t *parser = NULL; device_data_t *devdata = userdata; dc_datetime_t dt = {0}; + struct tm tm; + struct dive *dive; + + /* Christ, this is hacky */ + run_gtk_mainloop(); rc = create_parser(devdata, &parser); if (rc != PARSER_STATUS_SUCCESS) { @@ -125,6 +246,7 @@ static int dive_cb(const unsigned char *data, unsigned int size, return rc; } + dive = alloc_dive(); rc = parser_get_datetime(parser, &dt); if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) { error("Error parsing the datetime."); @@ -132,12 +254,64 @@ static int dive_cb(const unsigned char *data, unsigned int size, return rc; } - printf("%04i-%02i-%02i %02i:%02i:%02i\n", - dt.year, dt.month, dt.day, - dt.hour, dt.minute, dt.second); + tm.tm_year = dt.year; + tm.tm_mon = dt.month-1; + tm.tm_mday = dt.day; + tm.tm_hour = dt.hour; + tm.tm_min = dt.minute; + tm.tm_sec = dt.second; + dive->when = utc_mktime(&tm); + + // Parse the divetime. + printf("Parsing the divetime.\n"); + unsigned int divetime = 0; + rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime); + if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) { + error("Error parsing the divetime."); + parser_destroy(parser); + return rc; + } + dive->duration.seconds = divetime; + + // Parse the maxdepth. + printf("Parsing the maxdepth.\n"); + double maxdepth = 0.0; + rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth); + if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) { + error("Error parsing the maxdepth."); + parser_destroy(parser); + return rc; + } + dive->maxdepth.mm = maxdepth * 1000 + 0.5; + + // Parse the gas mixes. + printf("Parsing the gas mixes.\n"); + unsigned int ngases = 0; + rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases); + if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) { + error("Error parsing the gas mix count."); + parser_destroy(parser); + return rc; + } + + rc = parse_gasmixes(dive, parser, ngases); + if (rc != PARSER_STATUS_SUCCESS) { + error("Error parsing the gas mix."); + parser_destroy(parser); + return rc; + } + + // Initialize the sample data. + rc = parse_samples(&dive, parser); + if (rc != PARSER_STATUS_SUCCESS) { + error("Error parsing the samples."); + parser_destroy(parser); + return rc; + } + record_dive(dive); parser_destroy(parser); - return PARSER_STATUS_SUCCESS; + return 1; } @@ -220,21 +394,23 @@ static device_status_t device_open(const char *devname, } static void -event_cb (device_t *device, device_event_t event, const void *data, void *userdata) +event_cb(device_t *device, device_event_t event, const void *data, void *userdata) { const device_progress_t *progress = (device_progress_t *) data; const device_devinfo_t *devinfo = (device_devinfo_t *) data; const device_clock_t *clock = (device_clock_t *) data; device_data_t *devdata = (device_data_t *) userdata; + /* Christ, this is hacky */ + run_gtk_mainloop(); + switch (event) { case DEVICE_EVENT_WAITING: printf("Event: waiting for user action\n"); break; case DEVICE_EVENT_PROGRESS: - printf("Event: progress %3.2f%% (%u/%u)\n", - 100.0 * (double) progress->current / (double) progress->maximum, - progress->current, progress->maximum); + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(devdata->progressbar), + (double) progress->current / (double) progress->maximum); break; case DEVICE_EVENT_DEVINFO: devdata->devinfo = *devinfo; @@ -254,31 +430,29 @@ event_cb (device_t *device, device_event_t event, const void *data, void *userda } static int -cancel_cb (void *userdata) +cancel_cb(void *userdata) { - return 0; + return run_gtk_mainloop(); } -static void do_import(const char *computer, device_type_t type) +static void do_import(device_data_t *data) { - /* FIXME! Needs user input! */ - const char *devname = "/dev/ttyUSB0"; device_t *device = NULL; device_status_t rc; - device_data_t devicedata = { - .type = type, - .name = computer, - }; - rc = device_open(devname, type, &device); + if (data->type == DEVICE_TYPE_UEMIS) { + return uemis_import(); + } + + rc = device_open(data->devname, data->type, &device); if (rc != DEVICE_STATUS_SUCCESS) { - error("Unable to open %s (%s)", computer, devname); + error("Unable to open %s (%s)", data->name, data->devname); return; } // Register the event handler. int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK; - rc = device_set_events(device, events, event_cb, &devicedata); + rc = device_set_events(device, events, event_cb, data); if (rc != DEVICE_STATUS_SUCCESS) { error("Error registering the event handler."); device_close(device); @@ -286,14 +460,14 @@ static void do_import(const char *computer, device_type_t type) } // Register the cancellation handler. - rc = device_set_cancel(device, cancel_cb, &devicedata); + rc = device_set_cancel(device, cancel_cb, data); if (rc != DEVICE_STATUS_SUCCESS) { error("Error registering the cancellation handler."); device_close(device); return; } - rc = import_device_data(device, &devicedata); + rc = import_device_data(device, data); if (rc != DEVICE_STATUS_SUCCESS) { error("Dive data import error"); device_close(device); @@ -335,6 +509,7 @@ struct device_list { { "Cressi Edy", DEVICE_TYPE_CRESSI_EDY }, { "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 }, { "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT }, + { "Uemis Zurich SDA", DEVICE_TYPE_UEMIS }, { NULL } }; @@ -359,7 +534,7 @@ static GtkComboBox *dive_computer_selector(GtkWidget *dialog) GtkCellRenderer *renderer; hbox = gtk_hbox_new(FALSE, 6); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE, FALSE, 3); model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); fill_computer_list(model); @@ -377,8 +552,11 @@ static GtkComboBox *dive_computer_selector(GtkWidget *dialog) void import_dialog(GtkWidget *w, gpointer data) { int result; - GtkWidget *dialog; + GtkWidget *dialog, *hbox; GtkComboBox *computer; + device_data_t devicedata = { + .devname = "/dev/ttyUSB0", + }; dialog = gtk_dialog_new_with_buttons("Import from dive computer", GTK_WINDOW(main_window), @@ -389,6 +567,11 @@ void import_dialog(GtkWidget *w, gpointer data) computer = dive_computer_selector(dialog); + hbox = gtk_hbox_new(FALSE, 6); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE, TRUE, 3); + devicedata.progressbar = gtk_progress_bar_new(); + gtk_container_add(GTK_CONTAINER(hbox), devicedata.progressbar); + gtk_widget_show_all(dialog); result = gtk_dialog_run(GTK_DIALOG(dialog)); switch (result) { @@ -404,11 +587,15 @@ void import_dialog(GtkWidget *w, gpointer data) 0, &comp, 1, &type, -1); - do_import(comp, type); + devicedata.type = type; + devicedata.name = comp; + do_import(&devicedata); break; default: break; } gtk_widget_destroy(dialog); -} + report_dives(); + dive_list_update_dives(dive_list); +}