Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
	}
}
Exemplo n.º 3
0
/*
 * 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);
	}
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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();
}
Exemplo n.º 6
0
static temperature_t get_temperature(const char *line)
{
	temperature_t t;
	t.mkelvin = C_to_mkelvin(ascii_strtod(line, NULL));
	return t;
}
Exemplo n.º 7
0
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);
}
Exemplo n.º 8
0
/*
* 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;
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
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;
}