summaryrefslogtreecommitdiffstats
path: root/core/ostctools.c
diff options
context:
space:
mode:
Diffstat (limited to 'core/ostctools.c')
-rw-r--r--core/ostctools.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/core/ostctools.c b/core/ostctools.c
new file mode 100644
index 000000000..9be591b0e
--- /dev/null
+++ b/core/ostctools.c
@@ -0,0 +1,193 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "dive.h"
+#include "gettext.h"
+#include "divelist.h"
+#include "libdivecomputer.h"
+
+/*
+ * Returns a dc_descriptor_t structure based on dc model's number and family.
+ */
+
+static dc_descriptor_t *ostc_get_data_descriptor(int data_model, dc_family_t data_fam)
+{
+ dc_descriptor_t *descriptor = NULL, *current = NULL;
+ ;
+ dc_iterator_t *iterator = NULL;
+ dc_status_t rc;
+
+ rc = dc_descriptor_iterator(&iterator);
+ if (rc != DC_STATUS_SUCCESS) {
+ fprintf(stderr, "Error creating the device descriptor iterator.\n");
+ return current;
+ }
+ while ((dc_iterator_next(iterator, &descriptor)) == DC_STATUS_SUCCESS) {
+ int desc_model = dc_descriptor_get_model(descriptor);
+ dc_family_t desc_fam = dc_descriptor_get_type(descriptor);
+ if (data_model == desc_model && data_fam == desc_fam) {
+ current = descriptor;
+ break;
+ }
+ dc_descriptor_free(descriptor);
+ }
+ dc_iterator_free(iterator);
+ return current;
+}
+
+/*
+ * Fills a device_data_t structure with known dc data and a descriptor.
+ */
+static int ostc_prepare_data(int data_model, dc_family_t dc_fam, device_data_t *dev_data)
+{
+ dc_descriptor_t *data_descriptor;
+
+ dev_data->device = NULL;
+ dev_data->context = NULL;
+
+ data_descriptor = ostc_get_data_descriptor(data_model, dc_fam);
+ if (data_descriptor) {
+ dev_data->descriptor = data_descriptor;
+ dev_data->vendor = copy_string(data_descriptor->vendor);
+ dev_data->model = copy_string(data_descriptor->product);
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * OSTCTools stores the raw dive data in heavily padded files, one dive
+ * each file. So it's not necessary to iterate once and again on a parsing
+ * function. Actually there's only one kind of archive for every DC model.
+ */
+void ostctools_import(const char *file, struct dive_table *divetable)
+{
+ FILE *archive;
+ device_data_t *devdata = calloc(1, sizeof(device_data_t));
+ dc_family_t dc_fam;
+ unsigned char *buffer = calloc(65536, 1), *uc_tmp;
+ char *tmp;
+ struct dive *ostcdive = alloc_dive();
+ dc_status_t rc = 0;
+ int model, ret, i = 0;
+ unsigned int serial;
+ struct extra_data *ptr;
+
+ // Open the archive
+ if ((archive = subsurface_fopen(file, "rb")) == NULL) {
+ report_error(translate("gettextFromC", "Failed to read '%s'"), file);
+ free(ostcdive);
+ goto out;
+ }
+
+ // Read dive number from the log
+ uc_tmp = calloc(2, 1);
+ fseek(archive, 258, 0);
+ fread(uc_tmp, 1, 2, archive);
+ ostcdive->number = uc_tmp[0] + (uc_tmp[1] << 8);
+ free(uc_tmp);
+
+ // Read device's serial number
+ uc_tmp = calloc(2, 1);
+ fseek(archive, 265, 0);
+ fread(uc_tmp, 1, 2, archive);
+ serial = uc_tmp[0] + (uc_tmp[1] << 8);
+ free(uc_tmp);
+
+ // Read dive's raw data, header + profile
+ fseek(archive, 456, 0);
+ while (!feof(archive)) {
+ fread(buffer + i, 1, 1, archive);
+ if (buffer[i] == 0xFD && buffer[i - 1] == 0xFD)
+ break;
+ i++;
+ }
+
+ // Try to determine the dc family based on the header type
+ if (buffer[2] == 0x20 || buffer[2] == 0x21) {
+ dc_fam = DC_FAMILY_HW_OSTC;
+ } else {
+ switch (buffer[8]) {
+ case 0x22:
+ dc_fam = DC_FAMILY_HW_FROG;
+ break;
+ case 0x23:
+ dc_fam = DC_FAMILY_HW_OSTC3;
+ break;
+ default:
+ report_error(translate("gettextFromC", "Unknown DC in dive %d"), ostcdive->number);
+ free(ostcdive);
+ fclose(archive);
+ goto out;
+ }
+ }
+
+ // Try to determine the model based on serial number
+ switch (dc_fam) {
+ case DC_FAMILY_HW_OSTC:
+ if (serial > 7000)
+ model = 3; //2C
+ else if (serial > 2048)
+ model = 2; //2N
+ else if (serial > 300)
+ model = 1; //MK2
+ else
+ model = 0; //OSTC
+ break;
+ case DC_FAMILY_HW_FROG:
+ model = 0;
+ break;
+ default:
+ if (serial > 10000)
+ model = 0x12; //Sport
+ else
+ model = 0x0A; //OSTC3
+ }
+
+ // Prepare data to pass to libdivecomputer.
+ ret = ostc_prepare_data(model, dc_fam, devdata);
+ if (ret == 0) {
+ report_error(translate("gettextFromC", "Unknown DC in dive %d"), ostcdive->number);
+ free(ostcdive);
+ fclose(archive);
+ goto out;
+ }
+ tmp = calloc(strlen(devdata->vendor) + strlen(devdata->model) + 28, 1);
+ sprintf(tmp, "%s %s (Imported from OSTCTools)", devdata->vendor, devdata->model);
+ ostcdive->dc.model = copy_string(tmp);
+ free(tmp);
+
+ // Parse the dive data
+ rc = libdc_buffer_parser(ostcdive, devdata, buffer, i + 1);
+ if (rc != DC_STATUS_SUCCESS)
+ report_error(translate("gettextFromC", "Error - %s - parsing dive %d"), errmsg(rc), ostcdive->number);
+
+ // Serial number is not part of the header nor the profile, so libdc won't
+ // catch it. If Serial is part of the extra_data, and set to zero, remove
+ // it from the list and add again.
+ tmp = calloc(12, 1);
+ sprintf(tmp, "%d", serial);
+ ostcdive->dc.serial = copy_string(tmp);
+ free(tmp);
+
+ if (ostcdive->dc.extra_data) {
+ ptr = ostcdive->dc.extra_data;
+ while (strcmp(ptr->key, "Serial"))
+ ptr = ptr->next;
+ if (!strcmp(ptr->value, "0")) {
+ add_extra_data(&ostcdive->dc, "Serial", ostcdive->dc.serial);
+ *ptr = *(ptr)->next;
+ }
+ } else {
+ add_extra_data(&ostcdive->dc, "Serial", ostcdive->dc.serial);
+ }
+ record_dive_to_table(ostcdive, divetable);
+ mark_divelist_changed(true);
+ sort_table(divetable);
+ fclose(archive);
+out:
+ free(devdata);
+ free(buffer);
+}