static char *parse_sample_unit(struct sample *sample, double val, char *unit) { char *end = unit, c; /* Skip over the unit */ while ((c = *end) != 0) { if (isspace(c)) { *end++ = 0; break; } end++; } /* The units are "°C", "m" or "bar", so let's just look at the first character */ switch (*unit) { case 'm': sample->depth.mm = rint(1000*val); break; case 'b': sample->cylinderpressure.mbar = rint(1000*val); break; default: sample->temperature.mkelvin = C_to_mkelvin(val); break; } return end; }
void add_sample_data(struct sample *sample, enum csv_format type, double val) { switch (type) { case CSV_DEPTH: sample->depth.mm = feet_to_mm(val); break; case CSV_TEMP: sample->temperature.mkelvin = F_to_mkelvin(val); break; case CSV_PRESSURE: sample->pressure[0].mbar = psi_to_mbar(val * 4); break; case POSEIDON_DEPTH: sample->depth.mm = lrint(val * 0.5 * 1000); break; case POSEIDON_TEMP: sample->temperature.mkelvin = C_to_mkelvin(val * 0.2); break; case POSEIDON_SETPOINT: sample->setpoint.mbar = lrint(val * 10); break; case POSEIDON_SENSOR1: sample->o2sensor[0].mbar = lrint(val * 10); break; case POSEIDON_SENSOR2: sample->o2sensor[1].mbar = lrint(val * 10); break; case POSEIDON_NDL: sample->ndl.seconds = lrint(val * 60); break; case POSEIDON_CEILING: sample->stopdepth.mm = lrint(val * 1000); break; } }
/* * Divinglog is crazy. The temperatures are in celsius. EXCEPT * for the sample temperatures, that are in Fahrenheit. * WTF? * * Oh, and I think Diving Log *internally* probably kept them * in celsius, because I'm seeing entries like * * <Temp>32.0</Temp> * * in there. Which is freezing, aka 0 degC. I bet the "0" is * what Diving Log uses for "no temperature". * * So throw away crap like that. * * It gets worse. Sometimes the sample temperatures are in * Celsius, which apparently happens if you are in a SI * locale. So we now do: * * - temperatures < 32.0 == Celsius * - temperature == 32.0 -> garbage, it's a missing temperature (zero converted from C to F) * - temperatures > 32.0 == Fahrenheit */ static void fahrenheit(char *buffer, void *_temperature) { temperature_t *temperature = _temperature; union int_or_float val; switch (integer_or_float(buffer, &val)) { case FLOAT: /* Floating point equality is evil, but works for small integers */ if (val.fp == 32.0) break; if (val.fp < 32.0) temperature->mkelvin = C_to_mkelvin(val.fp); else temperature->mkelvin = F_to_mkelvin(val.fp); break; default: fprintf(stderr, "Crazy Diving Log temperature reading %s\n", buffer); } }
int parseTemperatureToMkelvin(const QString &text) { int mkelvin; QString numOnly = text; numOnly.replace(",", ".").remove(QRegExp("[^-0-9.]")); if (numOnly.isEmpty()) return 0; double number = numOnly.toDouble(); switch (prefs.units.temperature) { case units::CELSIUS: mkelvin = C_to_mkelvin(number); break; case units::FAHRENHEIT: mkelvin = F_to_mkelvin(number); break; default: mkelvin = 0; } return mkelvin; }
void TestUnitConversion::testUnitConversions() { QCOMPARE(IS_FP_SAME(grams_to_lbs(1000), 2.204586), true); QCOMPARE(lbs_to_grams(1), 454); QCOMPARE(IS_FP_SAME(ml_to_cuft(1000), 0.0353147), true); QCOMPARE(IS_FP_SAME(cuft_to_l(1), 28.316847), true); QCOMPARE(IS_FP_SAME(mm_to_feet(1000), 3.280840), true); QCOMPARE(feet_to_mm(1), (long unsigned int) 305); QCOMPARE(to_feet((depth_t){ 1000 }), 3); QCOMPARE(IS_FP_SAME(mkelvin_to_C(647000), 373.85), true); QCOMPARE(IS_FP_SAME(mkelvin_to_F(647000), 704.93), true); QCOMPARE(F_to_mkelvin(704.93), (unsigned long)647000); QCOMPARE(C_to_mkelvin(373.85), (unsigned long)647000); QCOMPARE(IS_FP_SAME(psi_to_bar(14.6959488), 1.01325), true); QCOMPARE(psi_to_mbar(14.6959488), (long)1013); QCOMPARE(to_PSI((pressure_t){ 1013 }), (int)15); QCOMPARE(IS_FP_SAME(bar_to_atm(1.013), 1.0), true); QCOMPARE(IS_FP_SAME(mbar_to_atm(1013), 1.0), true); QCOMPARE(mbar_to_PSI(1013), (int)15); get_units(); }
static temperature_t get_temperature(const char *line) { temperature_t t; t.mkelvin = C_to_mkelvin(ascii_strtod(line, NULL)); return t; }
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); }
/* * Parse sample data, extract events and build a dive */ static void cochran_parse_samples(struct dive *dive, const unsigned char *log, const unsigned char *samples, unsigned int size, unsigned int *duration, double *max_depth, double *avg_depth, double *min_temp) { const unsigned char *s; unsigned int offset = 0, profile_period = 1, sample_cnt = 0; double depth = 0, temp = 0, depth_sample = 0, psi = 0, sgc_rate = 0; int ascent_rate = 0; unsigned int ndl = 0; unsigned int in_deco = 0, deco_ceiling = 0, deco_time = 0; struct divecomputer *dc = &dive->dc; struct sample *sample; // Initialize stat variables *max_depth = 0, *avg_depth = 0, *min_temp = 0xFF; // Get starting depth and temp (tank PSI???) switch (config.type) { case TYPE_GEMINI: depth = (float) (log[CMD_START_DEPTH] + log[CMD_START_DEPTH + 1] * 256) / 4; temp = log[CMD_START_TEMP]; psi = log[CMD_START_PSI] + log[CMD_START_PSI + 1] * 256; sgc_rate = (float)(log[CMD_START_SGC] + log[CMD_START_SGC + 1] * 256) / 2; profile_period = log[CMD_PROFILE_PERIOD]; break; case TYPE_COMMANDER: depth = (float) (log[CMD_START_DEPTH] + log[CMD_START_DEPTH + 1] * 256) / 4; temp = log[CMD_START_TEMP]; profile_period = log[CMD_PROFILE_PERIOD]; break; case TYPE_EMC: depth = (float) log [EMC_START_DEPTH] / 256 + log[EMC_START_DEPTH + 1]; temp = log[EMC_START_TEMP]; profile_period = log[EMC_PROFILE_PERIOD]; break; } // Skip past pre-dive events unsigned int x = 0; unsigned int c; while (x < size && (samples[x] & 0x80) == 0 && samples[x] != 0x40) { c = cochran_predive_event_bytes(samples[x]) + 1; #ifdef COCHRAN_DEBUG printf("Predive event: "); for (unsigned int y = 0; y < c && x + y < size; y++) printf("%02x ", samples[x + y]); putchar('\n'); #endif x += c; } // Now process samples offset = x; while (offset + config.sample_size < size) { s = samples + offset; // Start with an empty sample sample = prepare_sample(dc); sample->time.seconds = sample_cnt * profile_period; // Check for event if (s[0] & 0x80) { cochran_dive_event(dc, s, sample_cnt * profile_period, &in_deco, &deco_ceiling, &deco_time); offset += cochran_dive_event_bytes(s[0]) + 1; continue; } // Depth is in every sample depth_sample = (float)(s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1); depth += depth_sample; #ifdef COCHRAN_DEBUG cochran_debug_sample(s, sample_cnt); #endif switch (config.type) { case TYPE_COMMANDER: switch (sample_cnt % 2) { case 0: // Ascent rate ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1); break; case 1: // Temperature temp = s[1] / 2 + 20; break; } break; case TYPE_GEMINI: // Gemini with tank pressure and SAC rate. switch (sample_cnt % 4) { case 0: // Ascent rate ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1); break; case 2: // PSI change psi -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 4; break; case 1: // SGC rate sgc_rate -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 2; break; case 3: // Temperature temp = (float)s[1] / 2 + 20; break; } break; case TYPE_EMC: switch (sample_cnt % 2) { case 0: // Ascent rate ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1); break; case 1: // Temperature temp = (float)s[1] / 2 + 20; break; } // Get NDL and deco information switch (sample_cnt % 24) { case 20: if (offset + 5 < size) { if (in_deco) { // Fist stop time //first_deco_time = (s[2] + s[5] * 256 + 1) * 60; // seconds ndl = 0; } else { // NDL ndl = (s[2] + s[5] * 256 + 1) * 60; // seconds deco_time = 0; } } break; case 22: if (offset + 5 < size) { if (in_deco) { // Total stop time deco_time = (s[2] + s[5] * 256 + 1) * 60; // seconds ndl = 0; } } break; } } // Track dive stats if (depth > *max_depth) *max_depth = depth; if (temp < *min_temp) *min_temp = temp; *avg_depth = (*avg_depth * sample_cnt + depth) / (sample_cnt + 1); sample->depth.mm = lrint(depth * FEET * 1000); sample->ndl.seconds = ndl; sample->in_deco = in_deco; sample->stoptime.seconds = deco_time; sample->stopdepth.mm = lrint(deco_ceiling * FEET * 1000); sample->temperature.mkelvin = C_to_mkelvin((temp - 32) / 1.8); sample->sensor[0] = 0; sample->pressure[0].mbar = lrint(psi * PSI / 100); finish_sample(dc); offset += config.sample_size; sample_cnt++; } UNUSED(ascent_rate); // mark the variable as unused if (sample_cnt > 0) *duration = sample_cnt * profile_period - 1; }
static int dm5_dive(void *param, int columns, char **data, char **column) { UNUSED(columns); UNUSED(column); int i; int tempformat = 0; int interval, retval = 0, block_size; struct parser_state *state = (struct parser_state *)param; sqlite3 *handle = state->sql_handle; unsigned const char *sampleBlob; char *err = NULL; char get_events_template[] = "select * from Mark where DiveId = %d"; char get_tags_template[] = "select Text from DiveTag where DiveId = %d"; char get_cylinders_template[] = "select * from DiveMixture where DiveId = %d"; char get_gaschange_template[] = "select GasChangeTime,Oxygen,Helium from DiveGasChange join DiveMixture on DiveGasChange.DiveMixtureId=DiveMixture.DiveMixtureId where DiveId = %d"; char get_events[512]; dive_start(state); state->cur_dive->number = atoi(data[0]); state->cur_dive->when = (time_t)(atol(data[1])); if (data[2]) utf8_string(data[2], &state->cur_dive->notes); if (data[3]) state->cur_dive->duration.seconds = atoi(data[3]); if (data[15]) state->cur_dive->dc.duration.seconds = atoi(data[15]); /* * TODO: the deviceid hash should be calculated here. */ settings_start(state); dc_settings_start(state); if (data[4]) { utf8_string(data[4], &state->cur_settings.dc.serial_nr); state->cur_settings.dc.deviceid = atoi(data[4]); } if (data[5]) utf8_string(data[5], &state->cur_settings.dc.model); dc_settings_end(state); settings_end(state); if (data[6]) state->cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[6], NULL, 0) * 1000); if (data[8]) state->cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8])); if (data[9]) state->cur_dive->dc.watertemp.mkelvin = C_to_mkelvin(atoi(data[9])); if (data[4]) { state->cur_dive->dc.deviceid = atoi(data[4]); } if (data[5]) utf8_string(data[5], &state->cur_dive->dc.model); snprintf(get_events, sizeof(get_events) - 1, get_cylinders_template, state->cur_dive->number); retval = sqlite3_exec(handle, get_events, &dm5_cylinders, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query dm5_cylinders failed.\n"); return 1; } if (data[14]) state->cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) / 100); interval = data[16] ? atoi(data[16]) : 0; /* * sampleBlob[0] version number, indicates the size of one sample * * Following ones describe single sample, bugs in interpretation of the binary blob are likely: * * sampleBlob[3] depth * sampleBlob[7-9] pressure * sampleBlob[11] temperature - either full Celsius or float, might be different field for some version of DM */ sampleBlob = (unsigned const char *)data[24]; if (sampleBlob) { switch (sampleBlob[0]) { case 1: // Log is converted from DM4 to DM5 block_size = 16; break; case 2: block_size = 19; break; case 3: block_size = 23; break; case 4: // Temperature is stored in float tempformat = 1; block_size = 26; break; case 5: // Temperature is stored in float tempformat = 1; block_size = 30; break; default: block_size = 16; break; } } for (i = 0; interval && sampleBlob && i * interval < state->cur_dive->duration.seconds; i++) { float *depth = (float *)&sampleBlob[i * block_size + 3]; int32_t pressure = (sampleBlob[i * block_size + 9] << 16) + (sampleBlob[i * block_size + 8] << 8) + sampleBlob[i * block_size + 7]; sample_start(state); state->cur_sample->time.seconds = i * interval; state->cur_sample->depth.mm = lrintf(depth[0] * 1000.0f); if (tempformat == 1) { float *temp = (float *)&(sampleBlob[i * block_size + 11]); state->cur_sample->temperature.mkelvin = C_to_mkelvin(*temp); } else { if ((sampleBlob[i * block_size + 11]) != 0x7F) { state->cur_sample->temperature.mkelvin = C_to_mkelvin(sampleBlob[i * block_size + 11]); } } /* * Limit cylinder pressures to somewhat sensible values */ if (pressure >= 0 && pressure < 350000) state->cur_sample->pressure[0].mbar = pressure; sample_end(state); } /* * Log was converted from DM4, thus we need to parse the profile * from DM4 format */ if (i == 0) { float *profileBlob; unsigned char *tempBlob; int *pressureBlob; profileBlob = (float *)data[17]; tempBlob = (unsigned char *)data[18]; pressureBlob = (int *)data[19]; for (i = 0; interval && i * interval < state->cur_dive->duration.seconds; i++) { sample_start(state); state->cur_sample->time.seconds = i * interval; if (profileBlob) state->cur_sample->depth.mm = lrintf(profileBlob[i] * 1000.0f); else state->cur_sample->depth.mm = state->cur_dive->dc.maxdepth.mm; if (data[18] && data[18][0]) state->cur_sample->temperature.mkelvin = C_to_mkelvin(tempBlob[i]); if (data[19] && data[19][0]) state->cur_sample->pressure[0].mbar = pressureBlob[i]; sample_end(state); } } snprintf(get_events, sizeof(get_events) - 1, get_gaschange_template, state->cur_dive->number); retval = sqlite3_exec(handle, get_events, &dm5_gaschange, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query dm5_gaschange failed.\n"); return 1; } snprintf(get_events, sizeof(get_events) - 1, get_events_template, state->cur_dive->number); retval = sqlite3_exec(handle, get_events, &dm4_events, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query dm4_events failed.\n"); return 1; } snprintf(get_events, sizeof(get_events) - 1, get_tags_template, state->cur_dive->number); retval = sqlite3_exec(handle, get_events, &dm4_tags, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query dm4_tags failed.\n"); return 1; } dive_end(state); return SQLITE_OK; }
static int dm4_dive(void *param, int columns, char **data, char **column) { UNUSED(columns); UNUSED(column); int i; int interval, retval = 0; struct parser_state *state = (struct parser_state *)param; sqlite3 *handle = state->sql_handle; float *profileBlob; unsigned char *tempBlob; int *pressureBlob; char *err = NULL; char get_events_template[] = "select * from Mark where DiveId = %d"; char get_tags_template[] = "select Text from DiveTag where DiveId = %d"; char get_events[64]; dive_start(state); state->cur_dive->number = atoi(data[0]); state->cur_dive->when = (time_t)(atol(data[1])); if (data[2]) utf8_string(data[2], &state->cur_dive->notes); /* * DM4 stores Duration and DiveTime. It looks like DiveTime is * 10 to 60 seconds shorter than Duration. However, I have no * idea what is the difference and which one should be used. * Duration = data[3] * DiveTime = data[15] */ if (data[3]) state->cur_dive->duration.seconds = atoi(data[3]); if (data[15]) state->cur_dive->dc.duration.seconds = atoi(data[15]); /* * TODO: the deviceid hash should be calculated here. */ settings_start(state); dc_settings_start(state); if (data[4]) utf8_string(data[4], &state->cur_settings.dc.serial_nr); if (data[5]) utf8_string(data[5], &state->cur_settings.dc.model); state->cur_settings.dc.deviceid = 0xffffffff; dc_settings_end(state); settings_end(state); if (data[6]) state->cur_dive->dc.maxdepth.mm = lrint(strtod_flags(data[6], NULL, 0) * 1000); if (data[8]) state->cur_dive->dc.airtemp.mkelvin = C_to_mkelvin(atoi(data[8])); if (data[9]) state->cur_dive->dc.watertemp.mkelvin = C_to_mkelvin(atoi(data[9])); /* * TODO: handle multiple cylinders */ cylinder_start(state); if (data[22] && atoi(data[22]) > 0) state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atoi(data[22]); else if (data[10] && atoi(data[10]) > 0) state->cur_dive->cylinder[state->cur_cylinder_index].start.mbar = atoi(data[10]); if (data[23] && atoi(data[23]) > 0) state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = (atoi(data[23])); if (data[11] && atoi(data[11]) > 0) state->cur_dive->cylinder[state->cur_cylinder_index].end.mbar = (atoi(data[11])); if (data[12]) state->cur_dive->cylinder[state->cur_cylinder_index].type.size.mliter = lrint((strtod_flags(data[12], NULL, 0)) * 1000); if (data[13]) state->cur_dive->cylinder[state->cur_cylinder_index].type.workingpressure.mbar = (atoi(data[13])); if (data[20]) state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.o2.permille = atoi(data[20]) * 10; if (data[21]) state->cur_dive->cylinder[state->cur_cylinder_index].gasmix.he.permille = atoi(data[21]) * 10; cylinder_end(state); if (data[14]) state->cur_dive->dc.surface_pressure.mbar = (atoi(data[14]) * 1000); interval = data[16] ? atoi(data[16]) : 0; profileBlob = (float *)data[17]; tempBlob = (unsigned char *)data[18]; pressureBlob = (int *)data[19]; for (i = 0; interval && i * interval < state->cur_dive->duration.seconds; i++) { sample_start(state); state->cur_sample->time.seconds = i * interval; if (profileBlob) state->cur_sample->depth.mm = lrintf(profileBlob[i] * 1000.0f); else state->cur_sample->depth.mm = state->cur_dive->dc.maxdepth.mm; if (data[18] && data[18][0]) state->cur_sample->temperature.mkelvin = C_to_mkelvin(tempBlob[i]); if (data[19] && data[19][0]) state->cur_sample->pressure[0].mbar = pressureBlob[i]; sample_end(state); } snprintf(get_events, sizeof(get_events) - 1, get_events_template, state->cur_dive->number); retval = sqlite3_exec(handle, get_events, &dm4_events, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query dm4_events failed.\n"); return 1; } snprintf(get_events, sizeof(get_events) - 1, get_tags_template, state->cur_dive->number); retval = sqlite3_exec(handle, get_events, &dm4_tags, state, &err); if (retval != SQLITE_OK) { fprintf(stderr, "%s", "Database query dm4_tags failed.\n"); return 1; } dive_end(state); /* for (i=0; i<columns;++i) { fprintf(stderr, "%s\t", column[i]); } fprintf(stderr, "\n"); for (i=0; i<columns;++i) { fprintf(stderr, "%s\t", data[i]); } fprintf(stderr, "\n"); //exit(0); */ return SQLITE_OK; }