static void record_uemis_dive(device_data_t *devdata, struct dive *dive) { if (devdata->create_new_trip) { if (!devdata->trip) devdata->trip = create_and_hookup_trip_from_dive(dive); else add_dive_to_trip(dive, devdata->trip); } record_dive_to_table(dive, devdata->download_table); }
static void dive_end(void) { if (!cur_dive) return; if (!is_dive()) free(cur_dive); else record_dive_to_table(cur_dive, target_table); cur_dive = NULL; cur_dc = NULL; cur_cylinder_index = 0; cur_ws_index = 0; }
/* * 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); }
/* * OSTCTools stores the raw dive data in heavily padded files, one dive * each file. So it's not necesary 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), *tmp; struct dive *ostcdive = alloc_dive(); dc_status_t rc = 0; int model = 0, i = 0; unsigned int serial; struct extra_data *ptr; // Open the archive if ((archive = subsurface_fopen(file, "rb")) == NULL) { report_error(translate("gettextFromC", "Error: couldn't open the file")); return; } // Read dive number from the log tmp = calloc(2,1); fseek(archive, 258, 0); fread(tmp, 1, 2, archive); ostcdive->number = tmp[0] + (tmp[1] << 8); free(tmp); // Read device's serial number tmp = calloc(2, 1); fseek(archive, 265, 0); fread(tmp, 1, 2, archive); serial = tmp[0] + (tmp[1] << 8); free(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 switch (buffer[2]) { case 0x20: case 0x21: dc_fam = DC_FAMILY_HW_OSTC; break; case 0x22: dc_fam = DC_FAMILY_HW_FROG; break; case 0x23: dc_fam = DC_FAMILY_HW_OSTC3; break; } // Prepare data to pass to libdivecomputer. OSTC protocol doesn't include // a model number so will use 0. ostc_prepare_data(model, dc_fam, devdata); 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("Libdc returned error -%s- for 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); 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; } free(devdata); free(buffer); record_dive_to_table(ostcdive, divetable); mark_divelist_changed(true); sort_table(divetable); fclose(archive); }
void record_dive(struct dive *dive) { record_dive_to_table(dive, &dive_table); }
static void cochran_parse_dive(const unsigned char *decode, unsigned mod, const unsigned char *in, unsigned size, struct dive_table *table) { unsigned char *buf = malloc(size); struct dive *dive; struct divecomputer *dc; struct tm tm = {0}; uint32_t csum[5]; double max_depth, avg_depth, min_temp; unsigned int duration = 0, corrupt_dive = 0; /* * The scrambling has odd boundaries. I think the boundaries * match some data structure size, but I don't know. They were * discovered the same way we dynamically discover the decode * size: automatically looking for least random output. * * The boundaries are also this confused "off-by-one" thing, * the same way the file size is off by one. It's as if the * cochran software forgot to write one byte at the beginning. */ partial_decode(0, 0x0fff, decode, 1, mod, in, size, buf); partial_decode(0x0fff, 0x1fff, decode, 0, mod, in, size, buf); partial_decode(0x1fff, 0x2fff, decode, 0, mod, in, size, buf); partial_decode(0x2fff, 0x48ff, decode, 0, mod, in, size, buf); /* * This is not all the descrambling you need - the above are just * what appears to be the fixed-size blocks. The rest is also * scrambled, but there seems to be size differences in the data, * so this just descrambles part of it: */ if (size < 0x4914 + config.logbook_size) { // Analyst calls this a "Corrupt Beginning Summary" free(buf); return; } // Decode log entry (512 bytes + random prefix) partial_decode(0x48ff, 0x4914 + config.logbook_size, decode, 0, mod, in, size, buf); unsigned int sample_size = size - 0x4914 - config.logbook_size; int g; unsigned int sample_pre_offset = 0, sample_end_offset = 0; // Decode sample data partial_decode(0x4914 + config.logbook_size, size, decode, 0, mod, in, size, buf); #ifdef COCHRAN_DEBUG // Display pre-logbook data puts("\nPre Logbook Data\n"); cochran_debug_write(buf, 0x4914); // Display log book puts("\nLogbook Data\n"); cochran_debug_write(buf + 0x4914, config.logbook_size + 0x400); // Display sample data puts("\nSample Data\n"); #endif dive = alloc_dive(); dc = &dive->dc; unsigned char *log = (buf + 0x4914); switch (config.type) { case TYPE_GEMINI: case TYPE_COMMANDER: if (config.type == TYPE_GEMINI) { dc->model = "Gemini"; dc->deviceid = buf[0x18c] * 256 + buf[0x18d]; // serial no fill_default_cylinder(&dive->cylinder[0]); dive->cylinder[0].gasmix.o2.permille = (log[CMD_O2_PERCENT] / 256 + log[CMD_O2_PERCENT + 1]) * 10; dive->cylinder[0].gasmix.he.permille = 0; } else { dc->model = "Commander"; dc->deviceid = array_uint32_le(buf + 0x31e); // serial no for (g = 0; g < 2; g++) { fill_default_cylinder(&dive->cylinder[g]); dive->cylinder[g].gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256 + log[CMD_O2_PERCENT + g * 2 + 1]) * 10; dive->cylinder[g].gasmix.he.permille = 0; } } tm.tm_year = log[CMD_YEAR]; tm.tm_mon = log[CMD_MON] - 1; tm.tm_mday = log[CMD_DAY]; tm.tm_hour = log[CMD_HOUR]; tm.tm_min = log[CMD_MIN]; tm.tm_sec = log[CMD_SEC]; tm.tm_isdst = -1; dive->when = dc->when = utc_mktime(&tm); dive->number = log[CMD_NUMBER] + log[CMD_NUMBER + 1] * 256 + 1; dc->duration.seconds = (log[CMD_BT] + log[CMD_BT + 1] * 256) * 60; dc->surfacetime.seconds = (log[CMD_SIT] + log[CMD_SIT + 1] * 256) * 60; dc->maxdepth.mm = lrint((log[CMD_MAX_DEPTH] + log[CMD_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000); dc->meandepth.mm = lrint((log[CMD_AVG_DEPTH] + log[CMD_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000); dc->watertemp.mkelvin = C_to_mkelvin((log[CMD_MIN_TEMP] / 32) - 1.8); dc->surface_pressure.mbar = lrint(ATM / BAR * pow(1 - 0.0000225577 * (double) log[CMD_ALTITUDE] * 250 * FEET, 5.25588) * 1000); dc->salinity = 10000 + 150 * log[CMD_WATER_CONDUCTIVITY]; SHA1(log + CMD_NUMBER, 2, (unsigned char *)csum); dc->diveid = csum[0]; if (log[CMD_MAX_DEPTH] == 0xff && log[CMD_MAX_DEPTH + 1] == 0xff) corrupt_dive = 1; sample_pre_offset = array_uint32_le(log + CMD_PREDIVE_OFFSET); sample_end_offset = array_uint32_le(log + CMD_END_OFFSET); break; case TYPE_EMC: dc->model = "EMC"; dc->deviceid = array_uint32_le(buf + 0x31e); // serial no for (g = 0; g < 4; g++) { fill_default_cylinder(&dive->cylinder[g]); dive->cylinder[g].gasmix.o2.permille = (log[EMC_O2_PERCENT + g * 2] / 256 + log[EMC_O2_PERCENT + g * 2 + 1]) * 10; dive->cylinder[g].gasmix.he.permille = (log[EMC_HE_PERCENT + g * 2] / 256 + log[EMC_HE_PERCENT + g * 2 + 1]) * 10; } tm.tm_year = log[EMC_YEAR]; tm.tm_mon = log[EMC_MON] - 1; tm.tm_mday = log[EMC_DAY]; tm.tm_hour = log[EMC_HOUR]; tm.tm_min = log[EMC_MIN]; tm.tm_sec = log[EMC_SEC]; tm.tm_isdst = -1; dive->when = dc->when = utc_mktime(&tm); dive->number = log[EMC_NUMBER] + log[EMC_NUMBER + 1] * 256 + 1; dc->duration.seconds = (log[EMC_BT] + log[EMC_BT + 1] * 256) * 60; dc->surfacetime.seconds = (log[EMC_SIT] + log[EMC_SIT + 1] * 256) * 60; dc->maxdepth.mm = lrint((log[EMC_MAX_DEPTH] + log[EMC_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000); dc->meandepth.mm = lrint((log[EMC_AVG_DEPTH] + log[EMC_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000); dc->watertemp.mkelvin = C_to_mkelvin((log[EMC_MIN_TEMP] - 32) / 1.8); dc->surface_pressure.mbar = lrint(ATM / BAR * pow(1 - 0.0000225577 * (double) log[EMC_ALTITUDE] * 250 * FEET, 5.25588) * 1000); dc->salinity = 10000 + 150 * (log[EMC_WATER_CONDUCTIVITY] & 0x3); SHA1(log + EMC_NUMBER, 2, (unsigned char *)csum); dc->diveid = csum[0]; if (log[EMC_MAX_DEPTH] == 0xff && log[EMC_MAX_DEPTH + 1] == 0xff) corrupt_dive = 1; sample_pre_offset = array_uint32_le(log + EMC_PREDIVE_OFFSET); sample_end_offset = array_uint32_le(log + EMC_END_OFFSET); break; } // Use the log information to determine actual profile sample size // Otherwise we will get surface time at end of dive. if (sample_pre_offset < sample_end_offset && sample_end_offset != 0xffffffff) sample_size = sample_end_offset - sample_pre_offset; cochran_parse_samples(dive, buf + 0x4914, buf + 0x4914 + config.logbook_size, sample_size, &duration, &max_depth, &avg_depth, &min_temp); // Check for corrupt dive if (corrupt_dive) { dc->maxdepth.mm = lrint(max_depth * FEET * 1000); dc->meandepth.mm = lrint(avg_depth * FEET * 1000); dc->watertemp.mkelvin = C_to_mkelvin((min_temp - 32) / 1.8); dc->duration.seconds = duration; } record_dive_to_table(dive, table); mark_divelist_changed(true); free(buf); }