Пример #1
0
static dc_status_t
hw_ostc_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
{
	dc_buffer_t *buffer = dc_buffer_new (0);
	if (buffer == NULL)
		return DC_STATUS_NOMEMORY;

	dc_status_t rc = hw_ostc_device_dump (abstract, buffer);
	if (rc != DC_STATUS_SUCCESS) {
		dc_buffer_free (buffer);
		return rc;
	}

	// Emit a device info event.
	unsigned char *data = dc_buffer_get_data (buffer);
	dc_event_devinfo_t devinfo;
	devinfo.firmware = array_uint16_be (data + 264);
	devinfo.serial = array_uint16_le (data + 6);
	if (devinfo.serial > 7000)
		devinfo.model = 3; // OSTC 2C
	else if (devinfo.serial > 2048)
		devinfo.model = 2; // OSTC 2N
	else if (devinfo.serial > 300)
		devinfo.model = 1; // OSTC Mk2
	else
		devinfo.model = 0; // OSTC
	device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);

	rc = hw_ostc_extract_dives (abstract, dc_buffer_get_data (buffer),
		dc_buffer_get_size (buffer), callback, userdata);

	dc_buffer_free (buffer);

	return rc;
}
Пример #2
0
static dc_status_t
mares_darwin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{
	mares_darwin_parser_t *parser = (mares_darwin_parser_t *) abstract;

	if (abstract->size < parser->headersize)
		return DC_STATUS_DATAFORMAT;

	const unsigned char *p = abstract->data;

	if (datetime) {
		datetime->year   = array_uint16_be (p);
		datetime->month  = p[2];
		datetime->day    = p[3];
		datetime->hour   = p[4];
		datetime->minute = p[5];
		datetime->second = 0;
	}

	return DC_STATUS_SUCCESS;
}
static dc_status_t
shearwater_predator_extract_predator (dc_device_t *abstract, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata)
{
	shearwater_predator_device_t *device = (shearwater_predator_device_t*) abstract;
	dc_context_t *context = (abstract ? abstract->context : NULL);

	// Locate the most recent dive.
	// The device maintains an internal counter which is incremented for every
	// dive, and the current value at the time of the dive is stored in the
	// dive header. Thus the most recent dive will have the highest value.
	unsigned int maximum = 0;
	unsigned int eop = RB_PROFILE_END;

	// Search the ringbuffer backwards to locate matching header and
	// footer markers. Because the ringbuffer search algorithm starts at
	// some arbitrary position, which does not necessary corresponds
	// with a boundary between two dives, the begin position is adjusted
	// as soon as the first dive has been found. Without this step,
	// dives crossing the ringbuffer wrap point won't be detected when
	// searching backwards from the ringbuffer end offset.
	unsigned int footer = 0;
	unsigned int have_footer = 0;
	unsigned int begin = RB_PROFILE_BEGIN;
	unsigned int offset = RB_PROFILE_END;
	while (offset != begin) {
		// Handle the ringbuffer wrap point.
		if (offset == RB_PROFILE_BEGIN)
			offset = RB_PROFILE_END;

		// Move to the start of the block.
		offset -= SZ_BLOCK;

		if (array_isequal (data + offset, SZ_BLOCK, 0xFF)) {
			// Ignore empty blocks explicitly, because otherwise they are
			// incorrectly recognized as header markers.
		} else if (data[offset + 0] == 0xFF && data[offset + 1] == 0xFF && have_footer) {
			// If the first header marker is found, the begin offset is moved
			// after the corresponding footer marker. This is necessary to be
			// able to detect dives that cross the ringbuffer wrap point.
			if (begin == RB_PROFILE_BEGIN)
				begin = footer + SZ_BLOCK;

			// Get the internal dive number.
			unsigned int current = array_uint16_be (data + offset + 2);
			if (current > maximum) {
				maximum = current;
				eop = footer + SZ_BLOCK;
			}

			// The dive number in the header and footer should be identical.
			if (current != array_uint16_be (data + footer + 2)) {
				ERROR (context, "Unexpected dive number.");
				return DC_STATUS_DATAFORMAT;
			}

			// Reset the footer marker.
			have_footer = 0;
		} else if (data[offset + 0] == 0xFF && data[offset + 1] == 0xFE) {
			// Remember the footer marker.
			footer = offset;
			have_footer = 1;
		}
	}

	// Allocate memory for the profiles.
	unsigned char *buffer = (unsigned char *) malloc (RB_PROFILE_END - RB_PROFILE_BEGIN + SZ_BLOCK);
	if (buffer == NULL) {
		return DC_STATUS_NOMEMORY;
	}

	// Linearize the ringbuffer.
	memcpy (buffer + 0, data + eop, RB_PROFILE_END - eop);
	memcpy (buffer + RB_PROFILE_END - eop, data + RB_PROFILE_BEGIN, eop - RB_PROFILE_BEGIN);

	// Find the dives again in the linear buffer.
	footer = 0;
	have_footer = 0;
	offset = RB_PROFILE_END;
	while (offset != RB_PROFILE_BEGIN) {
		// Move to the start of the block.
		offset -= SZ_BLOCK;

		if (array_isequal (buffer + offset, SZ_BLOCK, 0xFF)) {
			break;
		} else if (buffer[offset + 0] == 0xFF && buffer[offset + 1] == 0xFF && have_footer) {
			// Append the final block.
			unsigned int length = footer + SZ_BLOCK - offset;
			memcpy (buffer + offset + length, data + SZ_MEMORY - SZ_BLOCK, SZ_BLOCK);

			// Check the fingerprint data.
			if (device && memcmp (buffer + offset + 12, device->fingerprint, sizeof (device->fingerprint)) == 0)
				break;

			if (callback && !callback (buffer + offset, length + SZ_BLOCK, buffer + offset + 12, sizeof (device->fingerprint), userdata))
				break;

			have_footer = 0;
		} else if (buffer[offset + 0] == 0xFF && buffer[offset + 1] == 0xFE) {
			footer = offset;
			have_footer = 1;
		}
	}

	free (buffer);

	return DC_STATUS_SUCCESS;
}
Пример #4
0
static dc_status_t
hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
{
	hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;

	// Enable progress notifications.
	dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
	progress.maximum = (RB_LOGBOOK_SIZE * RB_LOGBOOK_COUNT) + SZ_MEMORY;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Download the version data.
	unsigned char id[SZ_VERSION] = {0};
	dc_status_t rc = hw_ostc3_device_version (abstract, id, sizeof (id));
	if (rc != DC_STATUS_SUCCESS) {
		ERROR (abstract->context, "Failed to read the version.");
		return rc;
	}

	// Emit a device info event.
	dc_event_devinfo_t devinfo;
	devinfo.model = 0;
	devinfo.firmware = array_uint16_be (id + 2);
	devinfo.serial = array_uint16_le (id + 0);
	device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);

	// Allocate memory.
	unsigned char *header = (unsigned char *) malloc (RB_LOGBOOK_SIZE * RB_LOGBOOK_COUNT);
	if (header == NULL) {
		ERROR (abstract->context, "Failed to allocate memory.");
		return DC_STATUS_NOMEMORY;
	}

	// Download the logbook headers.
	rc = hw_ostc3_transfer (device, &progress, HEADER,
              NULL, 0, header, RB_LOGBOOK_SIZE * RB_LOGBOOK_COUNT);
	if (rc != DC_STATUS_SUCCESS) {
		ERROR (abstract->context, "Failed to read the header.");
		free (header);
		return rc;
	}

	// Locate the most recent dive.
	// The device maintains an internal counter which is incremented for every
	// dive, and the current value at the time of the dive is stored in the
	// dive header. Thus the most recent dive will have the highest value.
	unsigned int count = 0;
	unsigned int latest = 0;
	unsigned int maximum = 0;
	for (unsigned int i = 0; i < RB_LOGBOOK_COUNT; ++i) {
		unsigned int offset = i * RB_LOGBOOK_SIZE;

		// Ignore uninitialized header entries.
		if (array_isequal (header + offset, RB_LOGBOOK_SIZE, 0xFF))
			continue;

		// Get the internal dive number.
		unsigned int current = array_uint16_le (header + offset + 80);
		if (current > maximum) {
			maximum = current;
			latest = i;
		}

		count++;
	}

	// Calculate the total and maximum size.
	unsigned int ndives = 0;
	unsigned int size = 0;
	unsigned int maxsize = 0;
	for (unsigned int i = 0; i < count; ++i) {
		unsigned int idx = (latest + RB_LOGBOOK_COUNT - i) % RB_LOGBOOK_COUNT;
		unsigned int offset = idx * RB_LOGBOOK_SIZE;

		// Uninitialized header entries should no longer be present at this
		// stage, unless the dives are interleaved with empty entries. But
		// that's something we don't support at all.
		if (array_isequal (header + offset, RB_LOGBOOK_SIZE, 0xFF)) {
			WARNING (abstract->context, "Unexpected empty header found.");
			break;
		}

		// Get the firmware version.
		unsigned int firmware = array_uint16_be (header + offset + 0x30);

		// Calculate the profile length.
		unsigned int length = RB_LOGBOOK_SIZE + array_uint24_le (header + offset + 9) - 6;
		if (firmware >= 93)
			length += 3;

		// Check the fingerprint data.
		if (memcmp (header + offset + 12, device->fingerprint, sizeof (device->fingerprint)) == 0)
			break;

		if (length > maxsize)
			maxsize = length;
		size += length;
		ndives++;
	}

	// Update and emit a progress event.
	progress.maximum = (RB_LOGBOOK_SIZE * RB_LOGBOOK_COUNT) + size;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Finish immediately if there are no dives available.
	if (ndives == 0) {
		free (header);
		return DC_STATUS_SUCCESS;
	}

	// Allocate enough memory for the largest dive.
	unsigned char *profile = (unsigned char *) malloc (maxsize);
	if (profile == NULL) {
		ERROR (abstract->context, "Failed to allocate memory.");
		free (header);
		return DC_STATUS_NOMEMORY;
	}

	// Download the dives.
	for (unsigned int i = 0; i < ndives; ++i) {
		unsigned int idx = (latest + RB_LOGBOOK_COUNT - i) % RB_LOGBOOK_COUNT;
		unsigned int offset = idx * RB_LOGBOOK_SIZE;

		// Get the firmware version.
		unsigned int firmware = array_uint16_be (header + offset + 0x30);

		// Calculate the profile length.
		unsigned int length = RB_LOGBOOK_SIZE + array_uint24_le (header + offset + 9) - 6;
		if (firmware >= 93)
			length += 3;

		// Download the dive.
		unsigned char number[1] = {idx};
		rc = hw_ostc3_transfer (device, &progress, DIVE,
			number, sizeof (number), profile, length);
		if (rc != DC_STATUS_SUCCESS) {
			ERROR (abstract->context, "Failed to read the dive.");
			free (profile);
			free (header);
			return rc;
		}

		// Verify the header in the logbook and profile are identical.
		if (memcmp (profile, header + offset, RB_LOGBOOK_SIZE) != 0) {
			ERROR (abstract->context, "Unexpected profile header.");
			free (profile);
			free (header);
			return rc;

		}

		if (callback && !callback (profile, length, profile + 12, sizeof (device->fingerprint), userdata))
			break;
	}

	free (profile);
	free (header);

	return DC_STATUS_SUCCESS;
}
static dc_status_t
shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
{
	shearwater_predator_parser_t *parser = (shearwater_predator_parser_t *) abstract;

	const unsigned char *data = abstract->data;
	unsigned int size = abstract->size;

	if (size < 2 * SZ_BLOCK)
		return DC_STATUS_DATAFORMAT;

	// Get the offset to the footer record.
	unsigned int footer = size - SZ_BLOCK;
	if (parser->petrel || array_uint16_be (data + footer) == 0xFFFD) {
		if (size < 3 * SZ_BLOCK)
			return DC_STATUS_DATAFORMAT;

		footer -= SZ_BLOCK;
	}

	// Get the sample size.
	unsigned int samplesize = SZ_SAMPLE_PREDATOR;
	if (parser->petrel) {
		samplesize = SZ_SAMPLE_PETREL;
	}

	// Get the unit system.
	unsigned int units = data[8];

	// Previous gas mix.
	unsigned int o2_previous = 0, he_previous = 0;

	unsigned int time = 0;
	unsigned int offset = SZ_BLOCK;
	while (offset < footer) {
		dc_sample_value_t sample = {0};

		// Ignore empty samples.
		if (array_isequal (data + offset, samplesize, 0x00)) {
			offset += samplesize;
			continue;
		}

		// Time (seconds).
		time += 10;
		sample.time = time;
		if (callback) callback (DC_SAMPLE_TIME, sample, userdata);

		// Depth (1/10 m or ft).
		unsigned int depth = array_uint16_be (data + offset);
		if (units == IMPERIAL)
			sample.depth = depth * FEET / 10.0;
		else
			sample.depth = depth / 10.0;
		if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);

		// Temperature (°C or °F).
		unsigned int temperature = data[offset + 13];
		if (units == IMPERIAL)
			sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
		else
			sample.temperature = temperature;
		if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);

		// PPO2
		sample.ppo2 = data[offset + 6] / 100.0;
		if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);

		// Gaschange.
		unsigned int o2 = data[offset + 7];
		unsigned int he = data[offset + 8];
		if (o2 != o2_previous || he != he_previous) {
			sample.event.type = SAMPLE_EVENT_GASCHANGE2;
			sample.event.time = 0;
			sample.event.flags = 0;
			sample.event.value = o2 | (he << 16);
			if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
			o2_previous = o2;
			he_previous = he;
		}

		// Deco stop / NDL.
		unsigned int decostop = array_uint16_be (data + offset + 2);
		if (decostop) {
			sample.deco.type = DC_DECO_DECOSTOP;
			if (units == IMPERIAL)
				sample.deco.depth = decostop * FEET;
			else
				sample.deco.depth = decostop;
		} else {
			sample.deco.type = DC_DECO_NDL;
			sample.deco.depth = 0.0;
		}
		sample.deco.time = data[offset + 9] * 60;
		if (callback) callback (DC_SAMPLE_DECO, sample, userdata);

		offset += samplesize;
	}

	return DC_STATUS_SUCCESS;
}
static dc_status_t
shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
{
	shearwater_predator_parser_t *parser = (shearwater_predator_parser_t *) abstract;

	const unsigned char *data = abstract->data;
	unsigned int size = abstract->size;

	if (size < 2 * SZ_BLOCK)
		return DC_STATUS_DATAFORMAT;

	// Get the offset to the footer record.
	unsigned int footer = size - SZ_BLOCK;
	if (parser->petrel || array_uint16_be (data + footer) == 0xFFFD) {
		if (size < 3 * SZ_BLOCK)
			return DC_STATUS_DATAFORMAT;

		footer -= SZ_BLOCK;
	}

	// Get the unit system.
	unsigned int units = data[8];

	// Get the gas mixes.
	unsigned int ngasmixes = 0;
	unsigned int oxygen[NGASMIXES] = {0};
	unsigned int helium[NGASMIXES] = {0};
	for (unsigned int i = 0; i < NGASMIXES; ++i) {
		unsigned int o2 = data[20 + i];
		unsigned int he = data[30 + i];
		if (o2 == 0 && he == 0)
			continue; // Skip disabled gas mixes.
		oxygen[ngasmixes] = o2;
		helium[ngasmixes] = he;
		ngasmixes++;
	}

	dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
	dc_salinity_t *water = (dc_salinity_t *) value;
	unsigned int density = 0;

	if (value) {
		switch (type) {
		case DC_FIELD_DIVETIME:
			*((unsigned int *) value) = array_uint16_be (data + footer + 6) * 60;
			break;
		case DC_FIELD_MAXDEPTH:
			if (units == IMPERIAL)
				*((double *) value) = array_uint16_be (data + footer + 4) * FEET;
			else
				*((double *) value) = array_uint16_be (data + footer + 4);
			break;
		case DC_FIELD_GASMIX_COUNT:
			*((unsigned int *) value) = ngasmixes;
			break;
		case DC_FIELD_GASMIX:
			gasmix->oxygen = oxygen[flags] / 100.0;
			gasmix->helium = helium[flags] / 100.0;
			gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
			break;
		case DC_FIELD_SALINITY:
			density = array_uint16_be (data + 83);
			if (density == 1000)
				water->type = DC_WATER_FRESH;
			else
				water->type = DC_WATER_SALT;
			water->density = density;
			break;
		case DC_FIELD_ATMOSPHERIC:
			*((double *) value) = array_uint16_be (data + 47) / 1000.0;
			break;
		default:
			return DC_STATUS_UNSUPPORTED;
		}
	}

	return DC_STATUS_SUCCESS;
}
Пример #7
0
static device_status_t
suunto_d9_device_packet (device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size)
{
	suunto_d9_device_t *device = (suunto_d9_device_t *) abstract;

	if (device_is_cancelled (abstract))
		return DEVICE_STATUS_CANCELLED;

	// Clear RTS to send the command.
	serial_set_rts (device->port, 0);

	// Send the command to the dive computer.
	int n = serial_write (device->port, command, csize);
	if (n != csize) {
		WARNING ("Failed to send the command.");
		return EXITCODE (n);
	}

	// Wait until all data has been transmitted.
	serial_drain (device->port);

	// Receive the echo.
	unsigned char echo[128] = {0};
	assert (sizeof (echo) >= csize);
	n = serial_read (device->port, echo, csize);
	if (n != csize) {
		WARNING ("Failed to receive the echo.");
		return EXITCODE (n);
	}

	// Verify the echo.
	if (memcmp (command, echo, csize) != 0) {
		WARNING ("Unexpected echo.");
		return DEVICE_STATUS_PROTOCOL;
	}

	// Set RTS to receive the reply.
	serial_set_rts (device->port, 1);

	// Receive the answer of the dive computer.
	n = serial_read (device->port, answer, asize);
	if (n != asize) {
		WARNING ("Failed to receive the answer.");
		return EXITCODE (n);
	}

	// Verify the header of the package.
	if (answer[0] != command[0]) {
		WARNING ("Unexpected answer header.");
		return DEVICE_STATUS_PROTOCOL;
	}

	// Verify the size of the package.
	if (array_uint16_be (answer + 1) + 4 != asize) {
		WARNING ("Unexpected answer size.");
		return DEVICE_STATUS_PROTOCOL;
	}

	// Verify the parameters of the package.
	if (memcmp (command + 3, answer + 3, asize - size - 4) != 0) {
		WARNING ("Unexpected answer parameters.");
		return DEVICE_STATUS_PROTOCOL;
	}

	// Verify the checksum of the package.
	unsigned char crc = answer[asize - 1];
	unsigned char ccrc = checksum_xor_uint8 (answer, asize - 1, 0x00);
	if (crc != ccrc) {
		WARNING ("Unexpected answer CRC.");
		return DEVICE_STATUS_PROTOCOL;
	}

	return DEVICE_STATUS_SUCCESS;
}
Пример #8
0
dc_status_t
suunto_common_extract_dives (suunto_common_device_t *device, const suunto_common_layout_t *layout, const unsigned char data[], dc_dive_callback_t callback, void *userdata)
{
	assert (layout != NULL);

	unsigned int eop;
	if (layout->eop) {
		// Get the end-of-profile pointer directly from the header.
		eop = array_uint16_be (data + layout->eop);
	} else {
		// Get the end-of-profile pointer by searching for the
		// end-of-profile marker in the profile ringbuffer.
		eop = layout->rb_profile_begin;
		while (eop < layout->rb_profile_end) {
			if (data[eop] == 0x82)
				break;
			eop++;
		}
	}

	// Validate the end-of-profile pointer.
	if (eop < layout->rb_profile_begin || 
		eop >= layout->rb_profile_end ||
		data[eop] != 0x82)
	{
		return DC_STATUS_DATAFORMAT;
	}

	// Memory buffer for the profile ringbuffer.
	unsigned int length = layout->rb_profile_end - layout->rb_profile_begin;
	unsigned char *buffer = (unsigned char *) malloc (length);
	if (buffer == NULL)
		return DC_STATUS_NOMEMORY;

	unsigned int current = eop;
	unsigned int previous = eop;
	for (unsigned int i = 0; i < length; ++i) {
		// Move backwards through the ringbuffer.
		if (current == layout->rb_profile_begin)
			current = layout->rb_profile_end;
		current--;

		// Check for an end of profile marker.
		if (data[current] == 0x82)
			break;

		// Check for an end of dive marker (of the next dive),
		// to find the start of the current dive.
		unsigned int idx = RB_PROFILE_PEEK (current, layout);
		if (data[idx] == 0x80) {
			unsigned int len = RB_PROFILE_DISTANCE (current, previous, layout);
			if (current + len > layout->rb_profile_end) {
				unsigned int a = layout->rb_profile_end - current;
				unsigned int b = (current + len) - layout->rb_profile_end;
				memcpy (buffer + 0, data + current, a);
				memcpy (buffer + a, data + layout->rb_profile_begin,   b);
			} else {
				memcpy (buffer, data + current, len);
			}

			if (device && memcmp (buffer + layout->fp_offset, device->fingerprint, sizeof (device->fingerprint)) == 0) {
				free (buffer);
				return DC_STATUS_SUCCESS;
			}

			if (callback && !callback (buffer, len, buffer + layout->fp_offset, sizeof (device->fingerprint), userdata)) {
				free (buffer);
				return DC_STATUS_SUCCESS;
			}

			previous = current;
		}
	}

	free (buffer);

	if (data[current] != 0x82)
		return DC_STATUS_DATAFORMAT;

	return DC_STATUS_SUCCESS;
}
Пример #9
0
static dc_status_t
mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
{
	mares_darwin_parser_t *parser = (mares_darwin_parser_t *) abstract;

	if (abstract->size < parser->headersize)
		return DC_STATUS_DATAFORMAT;

	unsigned int time = 0;

	unsigned int pressure = array_uint16_be (abstract->data + 0x17);

	unsigned int offset = parser->headersize;
	while (offset + parser->samplesize <= abstract->size) {
			dc_sample_value_t sample = {0};

			unsigned int value = array_uint16_le (abstract->data + offset);
			unsigned int depth = value & 0x07FF;
			unsigned int ascent = (value & 0xE000) >> 13;
			unsigned int violation = (value & 0x1000) >> 12;
			unsigned int deco = (value & 0x0800) >> 11;

			// Surface Time (seconds).
			time += 20;
			sample.time = time;
			if (callback) callback (DC_SAMPLE_TIME, sample, userdata);

			// Depth (1/10 m).
			sample.depth = depth / 10.0;
			if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);

			// Ascent rate
			if (ascent) {
				sample.event.type = SAMPLE_EVENT_ASCENT;
				sample.event.time = 0;
				sample.event.flags = 0;
				sample.event.value = ascent;
				if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
			}

			// Deco violation
			if (violation) {
				sample.event.type = SAMPLE_EVENT_CEILING;
				sample.event.time = 0;
				sample.event.flags = 0;
				sample.event.value = 0;
				if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
			}

			// Deco stop
			if (deco) {
				sample.event.type = SAMPLE_EVENT_DECOSTOP;
				sample.event.time = 0;
				sample.event.flags = 0;
				sample.event.value = 0;
				if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
			}

			if (parser->samplesize == 3) {
				unsigned int type = (time / 20 + 2) % 3;
				if (type == 0) {
					// Tank Pressure (bar)
					pressure -= abstract->data[offset + 2];
					sample.pressure.tank = 0;
					sample.pressure.value = pressure;
					if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
				}
			}

			offset += parser->samplesize;
	}

	return DC_STATUS_SUCCESS;
}
Пример #10
0
static dc_status_t
shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
{
	shearwater_petrel_device_t *device = (shearwater_petrel_device_t *) abstract;
	dc_status_t rc = DC_STATUS_SUCCESS;

	// Allocate memory buffers for the manifests.
	dc_buffer_t *buffer = dc_buffer_new (MANIFEST_SIZE);
	dc_buffer_t *manifests = dc_buffer_new (MANIFEST_SIZE);
	if (buffer == NULL || manifests == NULL) {
		ERROR (abstract->context, "Insufficient buffer space available.");
		dc_buffer_free (buffer);
		dc_buffer_free (manifests);
		return DC_STATUS_NOMEMORY;
	}

	// Enable progress notifications.
	unsigned int current = 0, maximum = 0;
	dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Read the serial number.
	rc = shearwater_common_identifier (&device->base, buffer, ID_SERIAL);
	if (rc != DC_STATUS_SUCCESS) {
		ERROR (abstract->context, "Failed to read the serial number.");
		dc_buffer_free (buffer);
		dc_buffer_free (manifests);
		return rc;
	}

	// Convert to a number.
	unsigned char serial[4] = {0};
	if (array_convert_hex2bin (dc_buffer_get_data (buffer), dc_buffer_get_size (buffer),
		serial, sizeof (serial)) != 0 ) {
		ERROR (abstract->context, "Failed to convert the serial number.");
		dc_buffer_free (buffer);
		dc_buffer_free (manifests);
		return DC_STATUS_DATAFORMAT;

	}

	// Read the firmware version.
	rc = shearwater_common_identifier (&device->base, buffer, ID_FIRMWARE);
	if (rc != DC_STATUS_SUCCESS) {
		ERROR (abstract->context, "Failed to read the firmware version.");
		dc_buffer_free (buffer);
		dc_buffer_free (manifests);
		return rc;
	}

	// Convert to a number.
	unsigned int firmware = str2num (dc_buffer_get_data (buffer), dc_buffer_get_size (buffer), 1);

	// Read the hardware type.
	rc = shearwater_common_identifier (&device->base, buffer, ID_HARDWARE);
	if (rc != DC_STATUS_SUCCESS) {
		ERROR (abstract->context, "Failed to read the hardware type.");
		dc_buffer_free (buffer);
		dc_buffer_free (manifests);
		return rc;
	}

	// Convert and map to the model number.
	unsigned int hardware = array_uint_be (dc_buffer_get_data (buffer), dc_buffer_get_size (buffer));
	unsigned int model = 0;
	switch (hardware) {
	case 0x0808: // Petrel 2
	case 0x0909: // Petrel 1
	case 0x0B0B: // Petrel 1 (newer hardware)
		model = PETREL;
		break;
	case 0x0A0A: // Nerd 1
	case 0x0E0D: // Nerd 2
		model = NERD;
		break;
	case 0x0707:
		model = PERDIX;
		break;
	case 0x0C0D:
		model = PERDIXAI;
		break;
	default:
		WARNING (abstract->context, "Unknown hardware type %04x.", hardware);
	}

	// Emit a device info event.
	dc_event_devinfo_t devinfo;
	devinfo.model = model;
	devinfo.firmware = firmware;
	devinfo.serial = array_uint32_be (serial);
	device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);

	while (1) {
		// Update the progress state.
		// Assume the worst case scenario of a full manifest, and adjust the
		// value with the actual number of dives after the manifest has been
		// processed.
		maximum += 1 + RECORD_COUNT;

		// Download a manifest.
		progress.current = NSTEPS * current;
		progress.maximum = NSTEPS * maximum;
		rc = shearwater_common_download (&device->base, buffer, MANIFEST_ADDR, MANIFEST_SIZE, 0, &progress);
		if (rc != DC_STATUS_SUCCESS) {
			ERROR (abstract->context, "Failed to download the manifest.");
			dc_buffer_free (buffer);
			dc_buffer_free (manifests);
			return rc;
		}

		// Cache the buffer pointer and size.
		unsigned char *data = dc_buffer_get_data (buffer);
		unsigned int size = dc_buffer_get_size (buffer);

		// Process the records in the manifest.
		unsigned int count = 0;
		unsigned int offset = 0;
		while (offset < size) {
			// Check for a valid dive header.
			unsigned int header = array_uint16_be (data + offset);
			if (header != 0xA5C4)
				break;

			// Check the fingerprint data.
			if (memcmp (data + offset + 4, device->fingerprint, sizeof (device->fingerprint)) == 0)
				break;

			offset += RECORD_SIZE;
			count++;
		}

		// Update the progress state.
		current += 1;
		maximum -= RECORD_COUNT - count;

		// Append the manifest records to the main buffer.
		if (!dc_buffer_append (manifests, data, count * RECORD_SIZE)) {
			ERROR (abstract->context, "Insufficient buffer space available.");
			dc_buffer_free (buffer);
			dc_buffer_free (manifests);
			return DC_STATUS_NOMEMORY;
		}

		// Stop downloading manifest if there are no more records.
		if (count != RECORD_COUNT)
			break;
	}

	// Update and emit a progress event.
	progress.current = NSTEPS * current;
	progress.maximum = NSTEPS * maximum;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Cache the buffer pointer and size.
	unsigned char *data = dc_buffer_get_data (manifests);
	unsigned int size = dc_buffer_get_size (manifests);

	unsigned int offset = 0;
	while (offset < size) {
		// Get the address of the dive.
		unsigned int address = array_uint32_be (data + offset + 20);

		// Download the dive.
		progress.current = NSTEPS * current;
		progress.maximum = NSTEPS * maximum;
		rc = shearwater_common_download (&device->base, buffer, DIVE_ADDR + address, DIVE_SIZE, 1, &progress);
		if (rc != DC_STATUS_SUCCESS) {
			ERROR (abstract->context, "Failed to download the dive.");
			dc_buffer_free (buffer);
			dc_buffer_free (manifests);
			return rc;
		}

		// Update the progress state.
		current += 1;

		unsigned char *buf = dc_buffer_get_data (buffer);
		unsigned int len = dc_buffer_get_size (buffer);
		if (callback && !callback (buf, len, buf + 12, sizeof (device->fingerprint), userdata))
			break;

		offset += RECORD_SIZE;
	}

	// Update and emit a progress event.
	progress.current = NSTEPS * current;
	progress.maximum = NSTEPS * maximum;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	dc_buffer_free (manifests);
	dc_buffer_free (buffer);

	return rc;
}
Пример #11
0
int
irda_socket_open (irda **out)
{
	if (out == NULL)
		return -1; // EINVAL (Invalid argument)

	// Allocate memory.
	struct irda *device = (struct irda *) malloc (sizeof (struct irda));
	if (device == NULL) {
		TRACE ("malloc");
		return -1; // ENOMEM (Not enough space)
	}

	// Default to blocking reads.
	device->timeout = -1;

	// Open the socket.
	device->fd = socket (AF_IRDA, SOCK_STREAM, 0);
#ifdef _WIN32
	if (device->fd == INVALID_SOCKET) {
#else
	if (device->fd == -1) {
#endif
		TRACE ("socket");
		free (device);
		return -1;
	}

	*out = device;

    return 0;
}


int
irda_socket_close (irda *device)
{
	if (device == NULL)
		return -1;

	// Terminate all send and receive operations.
	shutdown (device->fd, 0);

	// Close the socket.
#ifdef _WIN32
	if (closesocket (device->fd) != 0) {
		TRACE ("closesocket");
#else
	if (close (device->fd) != 0) {
		TRACE ("close");
#endif
		free (device);
		return -1;
	}

	// Free memory.	
	free (device);

	return 0;
}


int
irda_socket_set_timeout (irda *device, long timeout)
{
	if (device == NULL)
		return -1; // EINVAL (Invalid argument)

	device->timeout = timeout;

	return 0;
}


#define DISCOVER_MAX_DEVICES 16	// Maximum number of devices.
#define DISCOVER_MAX_RETRIES 4	// Maximum number of retries.

#ifdef _WIN32
#define DISCOVER_BUFSIZE sizeof (DEVICELIST) + \
				sizeof (IRDA_DEVICE_INFO) * (DISCOVER_MAX_DEVICES - 1)
#else
#define DISCOVER_BUFSIZE sizeof (struct irda_device_list) + \
				sizeof (struct irda_device_info) * (DISCOVER_MAX_DEVICES - 1)
#endif

int
irda_socket_discover (irda *device, irda_callback_t callback, void *userdata)
{
	if (device == NULL)
		return -1;

	unsigned char data[DISCOVER_BUFSIZE] = {0};
#ifdef _WIN32
	DEVICELIST *list = (DEVICELIST *) data;
	int size = sizeof (data);
#else
	struct irda_device_list *list = (struct irda_device_list *) data;
	socklen_t size = sizeof (data);
#endif

	int rc = 0;
	unsigned int nretries = 0;
	while ((rc = getsockopt (device->fd, SOL_IRLMP, IRLMP_ENUMDEVICES, (char*) data, &size)) != 0 ||
#ifdef _WIN32
		list->numDevice == 0)
#else
		list->len == 0)
#endif
	{
		// Automatically retry the discovery when no devices were found.
		// On Linux, getsockopt fails with EAGAIN when no devices are
		// discovered, while on Windows it succeeds and sets the number
		// of devices to zero. Both situations are handled the same here.
		if (rc != 0) {
#ifdef _WIN32
			if (WSAGetLastError() != WSAEWOULDBLOCK) {
#else
			if (errno != EAGAIN) {
#endif
				TRACE ("getsockopt");
				return -1; // Error during getsockopt call.
			}
		}

		// Abort if the maximum number of retries is reached.
		if (nretries++ >= DISCOVER_MAX_RETRIES)
			return 0;

		// Restore the size parameter in case it was
		// modified by the previous getsockopt call.
		size = sizeof (data);

#ifdef _WIN32
		Sleep (1000);
#else
		sleep (1);
#endif
	}

	if (callback) {
#ifdef _WIN32
		for (unsigned int i = 0; i < list->numDevice; ++i) {
			unsigned int address = array_uint32_be (list->Device[i].irdaDeviceID);
			unsigned int hints = (list->Device[i].irdaDeviceHints1 << 8) + 
									list->Device[i].irdaDeviceHints2;
			callback (address, 
				list->Device[i].irdaDeviceName,
				list->Device[i].irdaCharSet,
				hints, 
				userdata);
		}
#else
		for (unsigned int i = 0; i < list->len; ++i) {
			unsigned int hints = array_uint16_be (list->dev[i].hints);
			callback (list->dev[i].daddr, 
				list->dev[i].info, 
				list->dev[i].charset, 
				hints,
				userdata);
		}
#endif
	}

	return 0;
}


int
irda_socket_connect_name (irda *device, unsigned int address, const char *name)
{
	if (device == NULL)
		return -1;

#ifdef _WIN32
	SOCKADDR_IRDA peer;
	peer.irdaAddressFamily = AF_IRDA;
	peer.irdaDeviceID[0] = (address >> 24) & 0xFF;
	peer.irdaDeviceID[1] = (address >> 16) & 0xFF;
	peer.irdaDeviceID[2] = (address >>  8) & 0xFF;
	peer.irdaDeviceID[3] = (address      ) & 0xFF;
    if (name)
		strncpy (peer.irdaServiceName, name, 25);
	else
		memset (peer.irdaServiceName, 0x00, 25);
#else
	struct sockaddr_irda peer;
	peer.sir_family = AF_IRDA;
	peer.sir_addr = address;
	if (name)
		strncpy (peer.sir_name, name, 25);
	else
		memset (peer.sir_name, 0x00, 25);
#endif

	if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
		TRACE ("connect");
		return -1;
	}

	return 0;
}

int
irda_socket_connect_lsap (irda *device, unsigned int address, unsigned int lsap)
{
	if (device == NULL)
		return -1;

#ifdef _WIN32
	SOCKADDR_IRDA peer;
	peer.irdaAddressFamily = AF_IRDA;
	peer.irdaDeviceID[0] = (address >> 24) & 0xFF;
	peer.irdaDeviceID[1] = (address >> 16) & 0xFF;
	peer.irdaDeviceID[2] = (address >>  8) & 0xFF;
	peer.irdaDeviceID[3] = (address      ) & 0xFF;
	snprintf (peer.irdaServiceName, 25, "LSAP-SEL%u", lsap);
#else
	struct sockaddr_irda peer;
	peer.sir_family = AF_IRDA;
	peer.sir_addr = address;
	peer.sir_lsap_sel = lsap;
	memset (peer.sir_name, 0x00, 25);
#endif

	if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
		TRACE ("connect");
		return -1;
	}

	return 0;
}


int
irda_socket_available (irda* device)
{
	if (device == NULL)
		return -1; // EINVAL (Invalid argument)

#ifdef _WIN32
	unsigned long bytes = 0;
	if (ioctlsocket (device->fd, FIONREAD, &bytes) != 0) {
		TRACE ("ioctlsocket");
#else
	int bytes = 0;
	if (ioctl (device->fd, FIONREAD, &bytes) != 0) {
		TRACE ("ioctl");
#endif
		return -1;
	}

	return bytes;
}


int
irda_socket_read (irda* device, void* data, unsigned int size)
{
	if (device == NULL)
		return -1; // EINVAL (Invalid argument)

	struct timeval tv;
	if (device->timeout >= 0) {
		tv.tv_sec  = (device->timeout / 1000);
		tv.tv_usec = (device->timeout % 1000) * 1000;
	}

	fd_set fds;
	FD_ZERO (&fds);
	FD_SET (device->fd, &fds);

	unsigned int nbytes = 0;
	while (nbytes < size) {
		int rc = select (device->fd + 1, &fds, NULL, NULL, (device->timeout >= 0 ? &tv : NULL));
		if (rc < 0) {
			TRACE ("select");
			return -1; // Error during select call.
		} else if (rc == 0) {
			break; // Timeout.
		}

		int n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0);
		if (n < 0) {
			TRACE ("recv");
			return -1; // Error during recv call.
		} else if (n == 0) {
			break; // EOF reached.
		}

		nbytes += n;
	}

	return nbytes;
}


int
irda_socket_write (irda* device, const void *data, unsigned int size)
{
	if (device == NULL)
		return -1; // EINVAL (Invalid argument)

	unsigned int nbytes = 0;
	while (nbytes < size) {
		int n = send (device->fd, (char*) data + nbytes, size - nbytes, 0);
		if (n < 0) {
			TRACE ("send");
			return -1; // Error during send call.
		}

		nbytes += n;
	}

	return nbytes;
}
dc_status_t
diverite_nitekq_extract_dives (dc_device_t *abstract, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata)
{
	diverite_nitekq_device_t *device = (diverite_nitekq_device_t *) abstract;
	dc_context_t *context = (abstract ? abstract->context : NULL);

	if (abstract && !ISINSTANCE (abstract))
		return DC_STATUS_INVALIDARGS;

	if (size < SZ_PACKET + SZ_MEMORY)
		return DC_STATUS_DATAFORMAT;

	// Skip the first packet. We don't need it for anything. It also
	// makes the logic easier because all offsets in the data are
	// relative to the real start of the memory (e.g. excluding this
	// artificial first block).
	data += SZ_PACKET;

	// Allocate memory.
	unsigned char *buffer = (unsigned char *) malloc (RB_PROFILE_END - RB_PROFILE_BEGIN);
	if (buffer == NULL) {
		ERROR (context, "Failed to allocate memory.");
		return DC_STATUS_NOMEMORY;
	}

	// Get the end of profile pointer.
	unsigned int eop = array_uint16_be(data + EOP);
	if (eop < RB_PROFILE_BEGIN || eop >= RB_PROFILE_END) {
		ERROR (context, "Invalid ringbuffer pointer detected.");
		free (buffer);
		return DC_STATUS_DATAFORMAT;
	}

	// When a new dive is added, the device moves all existing logbook
	// and address entries towards the end, such that the most recent
	// one is always the first one. This is not the case for the profile
	// data, which is added at the end.
	unsigned int previous = eop;
	for (unsigned int i = 0; i < 10; ++i) {
		// Get the pointer to the logbook entry.
		const unsigned char *p = data + LOGBOOK + i * SZ_LOGBOOK;

		// Abort if an empty logbook is found.
		if (array_isequal (p, SZ_LOGBOOK, 0x00))
			break;

		// Get the address of the profile data.
		unsigned int address = array_uint16_be(data + ADDRESS + i * 2);
		if (address < RB_PROFILE_BEGIN || address >= RB_PROFILE_END) {
			ERROR (context, "Invalid ringbuffer pointer detected.");
			free (buffer);
			return DC_STATUS_DATAFORMAT;
		}

		// Check the fingerprint data.
		if (device && memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)
			break;

		// Copy the logbook entry.
		memcpy (buffer, p, SZ_LOGBOOK);

		// Copy the profile data.
		unsigned int length = 0;
		if (previous > address) {
			length = previous - address;
			memcpy (buffer + SZ_LOGBOOK, data + address, length);
		} else {
			unsigned int len_a = RB_PROFILE_END - address;
			unsigned int len_b = previous - RB_PROFILE_BEGIN;
			length = len_a + len_b;
			memcpy (buffer + SZ_LOGBOOK, data + address, len_a);
			memcpy (buffer + SZ_LOGBOOK + len_a, data + RB_PROFILE_BEGIN, len_b);
		}

		if (callback && !callback (buffer, length + SZ_LOGBOOK, buffer, SZ_LOGBOOK, userdata)) {
			break;
		}

		previous = address;
	}

	free (buffer);

	return DC_STATUS_SUCCESS;
}
Пример #13
0
static dc_status_t
cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{
	cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract;

	// Erase the current contents of the buffer and
	// pre-allocate the required amount of memory.
	if (!dc_buffer_clear (buffer) || !dc_buffer_resize (buffer, SZ_MEMORY)) {
		ERROR (abstract->context, "Insufficient buffer space available.");
		return DC_STATUS_NOMEMORY;
	}

	// Enable progress notifications.
	dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
	progress.maximum = SZ_MEMORY;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Send the command header to the dive computer.
	const unsigned char command[] = {0x7B, 0x31, 0x32, 0x33, 0x44, 0x42, 0x41, 0x7d};
	int n = serial_write (device->port, command, sizeof (command));
	if (n != sizeof (command)) {
		ERROR (abstract->context, "Failed to send the command.");
		return EXITCODE (n);
	}

	// Receive the header packet.
	unsigned char header[7] = {0};
	n = serial_read (device->port, header, sizeof (header));
	if (n != sizeof (header)) {
		ERROR (abstract->context, "Failed to receive the answer.");
		return EXITCODE (n);
	}

	// Verify the header packet.
	const unsigned char expected[] = {0x7B, 0x21, 0x44, 0x35, 0x42, 0x33, 0x7d};
	if (memcmp (header, expected, sizeof (expected)) != 0) {
		ERROR (abstract->context, "Unexpected answer byte.");
		return DC_STATUS_PROTOCOL;
	}

	unsigned char *data = dc_buffer_get_data (buffer);

	unsigned int nbytes = 0;
	while (nbytes < SZ_MEMORY) {
		// Set the minimum packet size.
		unsigned int len = 1024;

		// Increase the packet size if more data is immediately available.
		int available = serial_get_received (device->port);
		if (available > len)
			len = available;

		// Limit the packet size to the total size.
		if (nbytes + len > SZ_MEMORY)
			len = SZ_MEMORY - nbytes;

		// Read the packet.
		n = serial_read (device->port, data + nbytes, len);
		if (n != len) {
			ERROR (abstract->context, "Failed to receive the answer.");
			return EXITCODE (n);
		}

		// Update and emit a progress event.
		progress.current += len;
		device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

		nbytes += len;
	}

	// Receive the trailer packet.
	unsigned char trailer[4] = {0};
	n = serial_read (device->port, trailer, sizeof (trailer));
	if (n != sizeof (trailer)) {
		ERROR (abstract->context, "Failed to receive the answer.");
		return EXITCODE (n);
	}

	// Convert to a binary checksum.
	unsigned char checksum[2] = {0};
	array_convert_hex2bin (trailer, sizeof (trailer), checksum, sizeof (checksum));

	// Verify the checksum.
	unsigned int csum1 = array_uint16_be (checksum);
	unsigned int csum2 = checksum_crc_ccitt_uint16 (data, SZ_MEMORY);
	if (csum1 != csum2) {
		ERROR (abstract->context, "Unexpected answer bytes.");
		return DC_STATUS_PROTOCOL;
	}

	return DC_STATUS_SUCCESS;
}
Пример #14
0
static dc_status_t
shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
{
	shearwater_petrel_device_t *device = (shearwater_petrel_device_t *) abstract;
	dc_status_t rc = DC_STATUS_SUCCESS;

	// Allocate memory buffers for the manifests.
	dc_buffer_t *buffer = dc_buffer_new (MANIFEST_SIZE);
	dc_buffer_t *manifests = dc_buffer_new (MANIFEST_SIZE);
	if (buffer == NULL || manifests == NULL) {
		ERROR (abstract->context, "Insufficient buffer space available.");
		dc_buffer_free (buffer);
		dc_buffer_free (manifests);
		return DC_STATUS_NOMEMORY;
	}

	while (1) {
		// Download a manifest.
		rc = shearwater_common_download (&device->base, buffer, MANIFEST_ADDR, MANIFEST_SIZE, 0);
		if (rc != DC_STATUS_SUCCESS) {
			ERROR (abstract->context, "Failed to download the manifest.");
			dc_buffer_free (buffer);
			dc_buffer_free (manifests);
			return rc;
		}

		// Cache the buffer pointer and size.
		unsigned char *data = dc_buffer_get_data (buffer);
		unsigned int size = dc_buffer_get_size (buffer);

		// Process the records in the manifest.
		unsigned int count = 0;
		unsigned int offset = 0;
		while (offset < size) {
			// Check for a valid dive header.
			unsigned int header = array_uint16_be (data + offset);
			if (header != 0xA5C4)
				break;

			// Check the fingerprint data.
			if (memcmp (data + offset + 4, device->fingerprint, sizeof (device->fingerprint)) == 0)
				break;

			offset += RECORD_SIZE;
			count++;
		}

		// Append the manifest records to the main buffer.
		if (!dc_buffer_append (manifests, data, count * RECORD_SIZE)) {
			ERROR (abstract->context, "Insufficient buffer space available.");
			dc_buffer_free (buffer);
			dc_buffer_free (manifests);
			return DC_STATUS_NOMEMORY;
		}

		// Stop downloading manifest if there are no more records.
		if (count != RECORD_COUNT)
			break;
	}

	// Cache the buffer pointer and size.
	unsigned char *data = dc_buffer_get_data (manifests);
	unsigned int size = dc_buffer_get_size (manifests);

	unsigned int offset = 0;
	while (offset < size) {
		// Get the address of the dive.
		unsigned int address = array_uint32_be (data + offset + 20);

		// Download the dive.
		rc = shearwater_common_download (&device->base, buffer, DIVE_ADDR + address, DIVE_SIZE, 1);
		if (rc != DC_STATUS_SUCCESS) {
			ERROR (abstract->context, "Failed to download the dive.");
			dc_buffer_free (buffer);
			dc_buffer_free (manifests);
			return rc;
		}

		unsigned char *buf = dc_buffer_get_data (buffer);
		unsigned int len = dc_buffer_get_size (buffer);
		if (callback && !callback (buf, len, buf + 12, sizeof (device->fingerprint), userdata))
			break;

		offset += RECORD_SIZE;
	}

	dc_buffer_free (manifests);
	dc_buffer_free (buffer);

	return rc;
}
Пример #15
0
static dc_status_t
hw_ostc_firmware_readfile (hw_ostc_firmware_t *firmware, dc_context_t *context, const char *filename)
{
	dc_status_t rc = DC_STATUS_SUCCESS;

	if (firmware == NULL) {
		ERROR (context, "Invalid arguments.");
		return DC_STATUS_INVALIDARGS;
	}

	// Initialize the buffers.
	memset (firmware->data, 0xFF, sizeof (firmware->data));
	memset (firmware->bitmap, 0x00, sizeof (firmware->bitmap));

	// Open the hex file.
	dc_ihex_file_t *file = NULL;
	rc = dc_ihex_file_open (&file, context, filename);
	if (rc != DC_STATUS_SUCCESS) {
		ERROR (context, "Failed to open the hex file.");
		return rc;
	}

	// Read the hex file.
	unsigned int lba = 0;
	dc_ihex_entry_t entry;
	while ((rc = dc_ihex_file_read (file, &entry)) == DC_STATUS_SUCCESS) {
		if (entry.type == 0) {
			// Data record.
			unsigned int address = (lba << 16) + entry.address;
			if (address + entry.length > SZ_FIRMWARE) {
				WARNING (context, "Ignoring out of range record (0x%08x,%u).", address, entry.length);
				continue;
			}

			// Copy the record to the buffer.
			memcpy (firmware->data + address, entry.data, entry.length);

			// Mark the corresponding blocks in the bitmap.
			unsigned int begin = address / SZ_BLOCK;
			unsigned int end = (address + entry.length + SZ_BLOCK - 1) / SZ_BLOCK;
			for (unsigned int i = begin; i < end; ++i) {
				firmware->bitmap[i] = 1;
			}
		} else if (entry.type == 1) {
			// End of file record.
			break;
		} else if (entry.type == 4) {
			// Extended linear address record.
			lba = array_uint16_be (entry.data);
		} else {
			ERROR (context, "Unexpected record type.");
			dc_ihex_file_close (file);
			return DC_STATUS_DATAFORMAT;
		}
	}
	if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_DONE) {
		ERROR (context, "Failed to read the record.");
		dc_ihex_file_close (file);
		return rc;
	}

	// Close the file.
	dc_ihex_file_close (file);

	// Verify the presence of the first block.
	if (firmware->bitmap[0] == 0) {
		ERROR (context, "No first data block.");
		return DC_STATUS_DATAFORMAT;
	}

	// Setup the last block.
	// Copy the "goto main" instruction, stored in the first 8 bytes of the hex
	// file, to the end of the last block at address 0x17F38. This last block
	// needs to be present, regardless of whether it's included in the hex file
	// or not!
	memset (firmware->data + SZ_FIRMWARE - SZ_BLOCK, 0xFF, SZ_BLOCK - 8);
	memcpy (firmware->data + SZ_FIRMWARE - 8, firmware->data, 8);
	firmware->bitmap[C_ARRAY_SIZE(firmware->bitmap) - 1] = 1;

	// Setup the first block.
	// Copy the hardcoded "goto 0x17F40" instruction to the start of the first
	// block at address 0x00000.
	const unsigned char header[] = {0xA0, 0xEF, 0xBF, 0xF0};
	memcpy (firmware->data, header, sizeof (header));

	return rc;
}
Пример #16
0
static dc_status_t
hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{
	hw_ostc_device_t *device = (hw_ostc_device_t*) abstract;

	// Erase the current contents of the buffer.
	if (!dc_buffer_clear (buffer)) {
		ERROR (abstract->context, "Insufficient buffer space available.");
		return DC_STATUS_NOMEMORY;
	}

	// Enable progress notifications.
	dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
	progress.maximum = SZ_HEADER + SZ_FW_NEW;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Send the command.
	unsigned char command[1] = {'a'};
	int rc = serial_write (device->port, command, sizeof (command));
	if (rc != sizeof (command)) {
		ERROR (abstract->context, "Failed to send the command.");
		return EXITCODE (rc);
	}

	// Read the header.
	unsigned char header[SZ_HEADER] = {0};
	int n = serial_read (device->port, header, sizeof (header));
	if (n != sizeof (header)) {
		ERROR (abstract->context, "Failed to receive the header.");
		return EXITCODE (n);
	}

	// Verify the header.
	unsigned char preamble[] = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55};
	if (memcmp (header, preamble, sizeof (preamble)) != 0) {
		ERROR (abstract->context, "Unexpected answer header.");
		return DC_STATUS_DATAFORMAT;
	}

	// Get the firmware version.
	unsigned int firmware = array_uint16_be (header + 264);

	// Get the amount of profile data.
	unsigned int size = sizeof (header);
	if (firmware > FW_190)
		size += SZ_FW_NEW;
	else
		size += SZ_FW_190;

	// Update and emit a progress event.
	progress.current = sizeof (header);
	progress.maximum = size;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Allocate the required amount of memory.
	if (!dc_buffer_resize (buffer, size)) {
		ERROR (abstract->context, "Insufficient buffer space available.");
		return DC_STATUS_NOMEMORY;
	}

	unsigned char *data = dc_buffer_get_data (buffer);

	// Copy the header to the output buffer.
	memcpy (data, header, sizeof (header));

	unsigned int nbytes = sizeof (header);
	while (nbytes < size) {
		// Set the minimum packet size.
		unsigned int len = 1024;

		// Increase the packet size if more data is immediately available.
		int available = serial_get_received (device->port);
		if (available > len)
			len = available;

		// Limit the packet size to the total size.
		if (nbytes + len > size)
			len = size - nbytes;

		// Read the packet.
		int n = serial_read (device->port, data + nbytes, len);
		if (n != len) {
			ERROR (abstract->context, "Failed to receive the answer.");
			return EXITCODE (n);
		}

		// Update and emit a progress event.
		progress.current += len;
		device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

		nbytes += len;
	}

	return DC_STATUS_SUCCESS;
}