Пример #1
0
device_status_t
suunto_common2_device_dump (device_t *abstract, dc_buffer_t *buffer)
{
	// Erase the current contents of the buffer and
	// allocate the required amount of memory.
	if (!dc_buffer_clear (buffer) || !dc_buffer_resize (buffer, SZ_MEMORY)) {
		WARNING ("Insufficient buffer space available.");
		return DEVICE_STATUS_MEMORY;
	}

	return device_dump_read (abstract, dc_buffer_get_data (buffer),
		dc_buffer_get_size (buffer), SZ_PACKET);
}
Пример #2
0
static int
shearwater_common_decompress_lre (unsigned char *data, unsigned int size, dc_buffer_t *buffer, unsigned int *isfinal)
{
	// The RLE decompression algorithm does interpret the binary data as a
	// stream of 9 bit values. Therefore, the total number of bits needs to be
	// a multiple of 9 bits.
	unsigned int nbits = size * 8;
	if (nbits % 9 != 0)
		return -1;

	unsigned int offset = 0;
	while (offset + 9 <= nbits) {
		// Extract the 9 bit value.
		unsigned int byte = offset / 8;
		unsigned int bit  = offset % 8;
		unsigned int shift = 16 - (bit + 9);
		unsigned int value = (array_uint16_be (data + byte) >> shift) & 0x1FF;

		// The 9th bit indicates whether the remaining 8 bits represent
		// a run of zero bytes or not. If the bit is set, the value is
		// not a run and doesn’t need expansion. If the bit is not set,
		// the value contains the number of zero bytes in the run. A
		// zero-length run indicates the end of the compressed stream.
		if (value & 0x100) {
			// Append the data byte directly.
			unsigned char c = value & 0xFF;
			if (!dc_buffer_append (buffer, &c, 1))
				return -1;
		} else if (value == 0) {
			// Reached the end of the compressed stream.
			if (isfinal)
				*isfinal = 1;
			break;
		} else {
			// Expand the run with zero bytes.
			if (!dc_buffer_resize (buffer, dc_buffer_get_size (buffer) + value))
				return -1;
		}

		offset += 9;
	}

	return 0;
}
Пример #3
0
static dc_status_t
uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{
	uwatec_meridian_device_t *device = (uwatec_meridian_device_t*) abstract;
	dc_status_t rc = DC_STATUS_SUCCESS;

	// 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;
	device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress);

	// Command template.
	unsigned char command[9] = {0x00,
			(device->timestamp      ) & 0xFF,
			(device->timestamp >> 8 ) & 0xFF,
			(device->timestamp >> 16) & 0xFF,
			(device->timestamp >> 24) & 0xFF,
			0x10,
			0x27,
			0,
			0};

	// Read the model number.
	command[0] = 0x10;
	unsigned char model[1] = {0};
	rc = uwatec_meridian_transfer (device, command, 1, model, sizeof (model));
	if (rc != DC_STATUS_SUCCESS)
		return rc;

	// Read the serial number.
	command[0] = 0x14;
	unsigned char serial[4] = {0};
	rc = uwatec_meridian_transfer (device, command, 1, serial, sizeof (serial));
	if (rc != DC_STATUS_SUCCESS)
		return rc;

	// Read the device clock.
	command[0] = 0x1A;
	unsigned char devtime[4] = {0};
	rc = uwatec_meridian_transfer (device, command, 1, devtime, sizeof (devtime));
	if (rc != DC_STATUS_SUCCESS)
		return rc;

	// Store the clock calibration values.
	device->systime = dc_datetime_now ();
	device->devtime = array_uint32_le (devtime);

	// Update and emit a progress event.
	progress.current += 9;
	device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress);

	// Emit a clock event.
	dc_event_clock_t clock;
	clock.systime = device->systime;
	clock.devtime = device->devtime;
	device_event_emit (&device->base, DC_EVENT_CLOCK, &clock);

	// Emit a device info event.
	dc_event_devinfo_t devinfo;
	devinfo.model = model[0];
	devinfo.firmware = 0;
	devinfo.serial = array_uint32_le (serial);
	device_event_emit (&device->base, DC_EVENT_DEVINFO, &devinfo);

	// Data Length.
	command[0] = 0xC6;
	unsigned char answer[4] = {0};
	rc = uwatec_meridian_transfer (device, command, sizeof (command), answer, sizeof (answer));
	if (rc != DC_STATUS_SUCCESS)
		return rc;

	unsigned int length = array_uint32_le (answer);

	// Update and emit a progress event.
	progress.maximum = 4 + 9 + (length ? length + 4 : 0);
	progress.current += 4;
	device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress);

	if (length == 0)
		return DC_STATUS_SUCCESS;

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

	unsigned char *data = dc_buffer_get_data (buffer);

	// Data.
	command[0] = 0xC4;
	rc = uwatec_meridian_transfer (device, command, sizeof (command), answer, sizeof (answer));
	if (rc != DC_STATUS_SUCCESS)
		return rc;

	unsigned int total = array_uint32_le (answer);

	// Update and emit a progress event.
	progress.current += 4;
	device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress);

	if (total != length + 4) {
		ERROR (abstract->context, "Received an unexpected size.");
		return DC_STATUS_PROTOCOL;
	}

	unsigned int nbytes = 0;
	while (nbytes < length) {

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

		// Get the packet size.
		unsigned int packetsize = array_uint32_le (header);
		if (packetsize < 1 || nbytes + packetsize - 1 > length) {
			WARNING (abstract->context, "Unexpected header.");
			return DC_STATUS_PROTOCOL;
		}

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

		// Read the checksum.
		unsigned char csum = 0x00;
		n = serial_read (device->port, &csum, sizeof (csum));
		if (n != sizeof (csum)) {
			ERROR (abstract->context, "Failed to receive the checksum.");
			return EXITCODE (n);
		}

		// Verify the checksum.
		unsigned char ccsum = 0x00;
		ccsum = checksum_xor_uint8 (header, sizeof (header), ccsum);
		ccsum = checksum_xor_uint8 (data + nbytes, packetsize - 1, ccsum);
		if (csum != ccsum) {
			ERROR (abstract->context, "Unexpected answer checksum.");
			return DC_STATUS_PROTOCOL;
		}


		// Update and emit a progress event.
		progress.current += packetsize - 1;
		device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress);

		nbytes += packetsize - 1;
	}

	return DC_STATUS_SUCCESS;
}
Пример #4
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;
}
Пример #5
0
dc_status_t
hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_format_t format)
{
	hw_ostc_device_t *device = (hw_ostc_device_t *) abstract;

	if (!ISINSTANCE (abstract))
		return DC_STATUS_INVALIDARGS;

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

	// Bytes per pixel (RGB formats only).
	unsigned int bpp = 0;

	if (format == HW_OSTC_FORMAT_RAW) {
		// The RAW format has a variable size, depending on the actual image
		// content. Usually the total size is around 4K, which is used as an
		// initial guess and expanded when necessary.
		if (!dc_buffer_reserve (buffer, 4096)) {
			ERROR (abstract->context, "Insufficient buffer space available.");
			return DC_STATUS_NOMEMORY;
		}
	} else {
		// The RGB formats have a fixed size, depending only on the dimensions
		// and the number of bytes per pixel. The required amount of memory is
		// allocated immediately.
		bpp = (format == HW_OSTC_FORMAT_RGB16) ? 2 : 3;
		if (!dc_buffer_resize (buffer, WIDTH * HEIGHT * bpp)) {
			ERROR (abstract->context, "Insufficient buffer space available.");
			return DC_STATUS_NOMEMORY;
		}
	}

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

	// Send the command.
	dc_status_t rc = hw_ostc_send (device, 'l', 1);
	if (rc != DC_STATUS_SUCCESS)
		return rc;

	// Cache the pointer to the image data (RGB formats only).
	unsigned char *image = dc_buffer_get_data (buffer);

	// The OSTC sends the image data in a column by column layout, which is
	// converted on the fly to a more convenient row by row layout as used
	// in the majority of image formats. This conversions requires knowledge
	// of the pixel coordinates.
	unsigned int x = 0, y = 0;

	unsigned int npixels = 0;
	while (npixels < WIDTH * HEIGHT) {
		unsigned char raw[3] = {0};
		int n = serial_read (device->port, raw, 1);
		if (n != 1) {
			ERROR (abstract->context, "Failed to receive the packet.");
			return EXITCODE (n);
		}

		unsigned int nbytes = n;
		unsigned int count = raw[0];
		if ((count & 0x80) == 0x00) {
			// Black pixel.
			raw[1] = raw[2] = BLACK;
			count &= 0x7F;
		} else if ((count & 0xC0) == 0xC0) {
			// White pixel.
			raw[1] = raw[2] = WHITE;
			count &= 0x3F;
		} else {
			// Color pixel.
			n = serial_read (device->port, raw + 1, 2);
			if (n != 2) {
				ERROR (abstract->context, "Failed to receive the packet.");
				return EXITCODE (n);
			}

			nbytes += n;
			count &= 0x3F;
		}
		count++;

		// Check for buffer overflows.
		if (npixels + count > WIDTH * HEIGHT) {
			ERROR (abstract->context, "Unexpected number of pixels received.");
			return DC_STATUS_DATAFORMAT;
		}

		if (format == HW_OSTC_FORMAT_RAW) {
			// Append the raw data to the output buffer.
			dc_buffer_append (buffer, raw, nbytes);
		} else {
			// Store the decompressed data in the output buffer.
			for (unsigned int i = 0; i < count; ++i) {
				// Calculate the offset to the current pixel (row layout)
				unsigned int offset = (y * WIDTH + x) * bpp;

				if (format == HW_OSTC_FORMAT_RGB16) {
					image[offset + 0] = raw[1];
					image[offset + 1] = raw[2];
				} else {
					unsigned int value = (raw[1] << 8) + raw[2];
					unsigned char r = (value & 0xF800) >> 11;
					unsigned char g = (value & 0x07E0) >> 5;
					unsigned char b = (value & 0x001F);
					image[offset + 0] = 255 * r / 31;
					image[offset + 1] = 255 * g / 63;
					image[offset + 2] = 255 * b / 31;
				}

				// Move to the next pixel coordinate (column layout).
				y++;
				if (y == HEIGHT) {
					y = 0;
					x++;
				}
			}
		}

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

		npixels += count;
	}

	return DC_STATUS_SUCCESS;
}
Пример #6
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;
}