Esempio n. 1
0
static device_status_t
suunto_eon_device_dump (device_t *abstract, dc_buffer_t *buffer)
{
	suunto_eon_device_t *device = (suunto_eon_device_t*) abstract;

	if (! device_is_suunto_eon (abstract))
		return DEVICE_STATUS_TYPE_MISMATCH;

	// Erase the current contents of the buffer and
	// pre-allocate the required amount of memory.
	if (!dc_buffer_clear (buffer) || !dc_buffer_reserve (buffer, SUUNTO_EON_MEMORY_SIZE)) {
		WARNING ("Insufficient buffer space available.");
		return DEVICE_STATUS_MEMORY;
	}

	// Enable progress notifications.
	device_progress_t progress = DEVICE_PROGRESS_INITIALIZER;
	progress.maximum = SUUNTO_EON_MEMORY_SIZE + 1;
	device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress);

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

	// Receive the answer.
	unsigned char answer[SUUNTO_EON_MEMORY_SIZE + 1] = {0};
	rc = serial_read (device->port, answer, sizeof (answer));
	if (rc != sizeof (answer)) {
		WARNING ("Failed to receive the answer.");
		return EXITCODE (rc);
	}

	// Update and emit a progress event.
	progress.current += sizeof (answer);
	device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress);

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

	dc_buffer_append (buffer, answer, SUUNTO_EON_MEMORY_SIZE);

	return DEVICE_STATUS_SUCCESS;
}
Esempio n. 2
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);
}
static dc_status_t
shearwater_predator_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{
	shearwater_common_device_t *device = (shearwater_common_device_t *) abstract;

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

	return shearwater_common_download (device, buffer, 0xDD000000, SZ_MEMORY, 0);
}
static dc_status_t
shearwater_predator_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{
	shearwater_common_device_t *device = (shearwater_common_device_t *) abstract;

	// Erase the current contents of the buffer.
	if (!dc_buffer_clear (buffer) || !dc_buffer_reserve (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.current = 0;
	progress.maximum = NSTEPS;

	return shearwater_common_download (device, buffer, 0xDD000000, SZ_MEMORY, 0, &progress);
}
Esempio n. 5
0
dc_status_t
shearwater_common_identifier (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int id)
{
	dc_device_t *abstract = (dc_device_t *) device;
	dc_status_t rc = DC_STATUS_SUCCESS;

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

	// Transfer the request.
	unsigned int n = 0;
	unsigned char request[] = {0x22,
		(id >> 8) & 0xFF,
		(id     ) & 0xFF};
	unsigned char response[SZ_PACKET];
	rc = shearwater_common_transfer (device, request, sizeof (request), response, sizeof (response), &n);
	if (rc != DC_STATUS_SUCCESS) {
		return rc;
	}

	// Verify the response.
	if (n < 3 || response[0] != 0x62 || response[1] != request[1] || response[2] != request[2]) {
		ERROR (abstract->context, "Unexpected response packet.");
		return DC_STATUS_PROTOCOL;
	}

	// Append the packet to the output buffer.
	if (!dc_buffer_append (buffer, response + 3, n - 3)) {
		ERROR (abstract->context, "Insufficient buffer space available.");
		return DC_STATUS_NOMEMORY;
	}

	return rc;
}
Esempio n. 6
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;
}
Esempio n. 7
0
static dc_status_t
reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{
	reefnet_sensus_device_t *device = (reefnet_sensus_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_reserve (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 = 4 + SZ_MEMORY + 2 + 3;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Wake-up the device.
	dc_status_t rc = reefnet_sensus_handshake (device);
	if (rc != DC_STATUS_SUCCESS)
		return rc;

	// Send the command to the device.
	unsigned char command = 0x40;
	int n = serial_write (device->port, &command, 1);
	if (n != 1) {
		ERROR (abstract->context, "Failed to send the command.");
		return EXITCODE (n);
	}

	// The device leaves the waiting state.
	device->waiting = 0;

	// Receive the answer from the device.
	unsigned int nbytes = 0;
	unsigned char answer[4 + SZ_MEMORY + 2 + 3] = {0};
	while (nbytes < sizeof (answer)) {
		unsigned int len = sizeof (answer) - nbytes;
		if (len > 128)
			len = 128;

		n = serial_read (device->port, answer + 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;
	}

	// Verify the headers of the package.
	if (memcmp (answer, "DATA", 4) != 0 ||
		memcmp (answer + sizeof (answer) - 3, "END", 3) != 0) {
		ERROR (abstract->context, "Unexpected answer start or end byte(s).");
		return DC_STATUS_PROTOCOL;
	}

	// Verify the checksum of the package.
	unsigned short crc = array_uint16_le (answer + 4 + SZ_MEMORY);
	unsigned short ccrc = checksum_add_uint16 (answer + 4, SZ_MEMORY, 0x00);
	if (crc != ccrc) {
		ERROR (abstract->context, "Unexpected answer checksum.");
		return DC_STATUS_PROTOCOL;
	}

	dc_buffer_append (buffer, answer + 4, SZ_MEMORY);

	return DC_STATUS_SUCCESS;
}
Esempio n. 8
0
static dc_status_t
atomics_cobalt_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc_event_progress_t *progress)
{
#ifdef HAVE_LIBUSB
	atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract;

	if (device_is_cancelled (abstract))
		return DC_STATUS_CANCELLED;

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

	// Send the command to the dive computer.
	uint8_t bRequest = 0;
	if (device->simulation)
		bRequest = init ? 0x02 : 0x03;
	else
		bRequest = init ? 0x09 : 0x0A;
	int rc = libusb_control_transfer (device->handle,
		LIBUSB_RECIPIENT_DEVICE | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
		bRequest, 0, 0, NULL, 0, TIMEOUT);
	if (rc != LIBUSB_SUCCESS) {
		ERROR (abstract->context, "Failed to send the command.");
		return EXITCODE(rc);
	}

	HEXDUMP (abstract->context, DC_LOGLEVEL_INFO, "Write", &bRequest, 1);

	unsigned int nbytes = 0;
	while (1) {
		// Receive the answer from the dive computer.
		int length = 0;
		unsigned char packet[8 * 1024] = {0};
		rc = libusb_bulk_transfer (device->handle, 0x82,
			packet, sizeof (packet), &length, TIMEOUT);
		if (rc != LIBUSB_SUCCESS) {
			ERROR (abstract->context, "Failed to receive the answer.");
			return EXITCODE(rc);
		}

		HEXDUMP (abstract->context, DC_LOGLEVEL_INFO, "Read", packet, length);

		// Update and emit a progress event.
		if (progress) {
			progress->current += length;
			device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
		}

		// Append the packet to the output buffer.
		dc_buffer_append (buffer, packet, length);
		nbytes += length;

		// If we received fewer bytes than requested, the transfer is finished.
		if (length < sizeof (packet))
			break;
	}

	// Check for a buffer error.
	if (dc_buffer_get_size (buffer) != nbytes) {
		ERROR (abstract->context, "Insufficient buffer space available.");
		return DC_STATUS_NOMEMORY;
	}

	// Check for the minimum length.
	if (nbytes < 2) {
		ERROR (abstract->context, "Data packet is too short.");
		return DC_STATUS_PROTOCOL;
	}

	// When only two 0xFF bytes are received, there are no more dives.
	unsigned char *data = dc_buffer_get_data (buffer);
	if (nbytes == 2 && data[0] == 0xFF && data[1] == 0xFF) {
		dc_buffer_clear (buffer);
		return DC_STATUS_SUCCESS;
	}

	// Verify the checksum of the packet.
	unsigned short crc = array_uint16_le (data + nbytes - 2);
	unsigned short ccrc = checksum_add_uint16 (data, nbytes - 2, 0x0);
	if (crc != ccrc) {
		ERROR (abstract->context, "Unexpected answer checksum.");
		return DC_STATUS_PROTOCOL;
	}

	// Remove the checksum bytes.
	dc_buffer_slice (buffer, 0, nbytes - 2);

	return DC_STATUS_SUCCESS;
#else
	return DC_STATUS_UNSUPPORTED;
#endif
}
static dc_status_t
diverite_nitekq_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
{
	diverite_nitekq_device_t *device = (diverite_nitekq_device_t*) abstract;
	dc_status_t rc = DC_STATUS_SUCCESS;
	unsigned char packet[256] = {0};

	// Erase the current contents of the buffer.
	if (!dc_buffer_clear (buffer) || !dc_buffer_reserve (buffer, SZ_PACKET + 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_PACKET + SZ_MEMORY;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Emit a vendor event.
	dc_event_vendor_t vendor;
	vendor.data = device->version;
	vendor.size = sizeof (device->version);
	device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);

	// Emit a device info event.
	dc_event_devinfo_t devinfo;
	devinfo.model = 0;
	devinfo.firmware = 0;
	devinfo.serial = array_uint32_be (device->version + 0x0A);
	device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);

	// Send the upload request. It's not clear whether this request is
	// actually needed, but let's send it anyway.
	rc = diverite_nitekq_send (device, UPLOAD);
	if (rc != DC_STATUS_SUCCESS) {
		return rc;
	}

	// Receive the response packet. It's currently not used (or needed)
	// for anything, but we prepend it to the main data anyway, in case
	// we ever need it in the future.
	rc = diverite_nitekq_receive (device, packet, sizeof (packet));
	if (rc != DC_STATUS_SUCCESS) {
		return rc;
	}

	dc_buffer_append (buffer, packet, sizeof (packet));

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

	// Send the request to initiate downloading memory blocks.
	rc = diverite_nitekq_send (device, RESET);
	if (rc != DC_STATUS_SUCCESS) {
		return rc;
	}

	for (unsigned int i = 0; i < 128; ++i) {
		// Request the next memory block.
		rc = diverite_nitekq_send (device, BLOCK);
		if (rc != DC_STATUS_SUCCESS) {
			return rc;
		}

		// Receive the memory block.
		rc = diverite_nitekq_receive (device, packet, sizeof (packet));
		if (rc != DC_STATUS_SUCCESS) {
			return rc;
		}

		dc_buffer_append (buffer, packet, sizeof (packet));

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

	return DC_STATUS_SUCCESS;
}
Esempio n. 10
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;
}
Esempio n. 11
0
dc_status_t
shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int address, unsigned int size, unsigned int compression)
{
	dc_device_t *abstract = (dc_device_t *) device;
	dc_status_t rc = DC_STATUS_SUCCESS;
	unsigned int n = 0;

	unsigned char req_init[] = {
		0x35,
		(compression ? 0x10 : 0x00),
		0x34,
		(address >> 24) & 0xFF,
		(address >> 16) & 0xFF,
		(address >>  8) & 0xFF,
		(address      ) & 0xFF,
		(size >> 16) & 0xFF,
		(size >>  8) & 0xFF,
		(size      ) & 0xFF};
	unsigned char req_block[] = {0x36, 0x00};
	unsigned char req_quit[] = {0x37};
	unsigned char response[SZ_PACKET];

	// 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 = 3 + size + 1;
	device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);

	// Transfer the init request.
	rc = shearwater_common_transfer (device, req_init, sizeof (req_init), response, 3, &n);
	if (rc != DC_STATUS_SUCCESS) {
		return rc;
	}

	// Verify the init response.
	if (n != 3 || response[0] != 0x75 || response[1] != 0x10 || response[2] > SZ_PACKET) {
		ERROR (abstract->context, "Unexpected response packet.");
		return DC_STATUS_PROTOCOL;
	}

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

	unsigned int done = 0;
	unsigned char block = 1;
	unsigned int nbytes = 0;
	while (nbytes < size && !done) {
		// Transfer the block request.
		req_block[1] = block;
		rc = shearwater_common_transfer (device, req_block, sizeof (req_block), response, sizeof (response), &n);
		if (rc != DC_STATUS_SUCCESS) {
			return rc;
		}

		// Verify the block header.
		if (n < 2 || response[0] != 0x76 || response[1] != block) {
			ERROR (abstract->context, "Unexpected response packet.");
			return DC_STATUS_PROTOCOL;
		}

		// Verify the block length.
		unsigned int length = n - 2;
		if (nbytes + length > size) {
			ERROR (abstract->context, "Unexpected packet size.");
			return DC_STATUS_PROTOCOL;
		}

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

		if (compression) {
			if (shearwater_common_decompress_lre (response + 2, length, buffer, &done) != 0) {
				ERROR (abstract->context, "Decompression error (LRE phase).");
				return DC_STATUS_PROTOCOL;
			}
		} else {
			if (!dc_buffer_append (buffer, response + 2, length)) {
				ERROR (abstract->context, "Insufficient buffer space available.");
				return DC_STATUS_PROTOCOL;
			}
		}

		nbytes += length;
		block++;
	}

	if (compression) {
		if (shearwater_common_decompress_xor (dc_buffer_get_data (buffer), dc_buffer_get_size (buffer)) != 0) {
			ERROR (abstract->context, "Decompression error (XOR phase).");
			return DC_STATUS_PROTOCOL;
		}
	}

	// Transfer the quit request.
	rc = shearwater_common_transfer (device, req_quit, sizeof (req_quit), response, 2, &n);
	if (rc != DC_STATUS_SUCCESS) {
		return rc;
	}

	// Verify the quit response.
	if (n != 2 || response[0] != 0x77 || response[1] != 0x00) {
		ERROR (abstract->context, "Unexpected response packet.");
		return DC_STATUS_PROTOCOL;
	}

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

	return DC_STATUS_SUCCESS;
}
Esempio n. 12
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;
}
Esempio n. 13
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;
}