Ejemplo n.º 1
0
dc_status_t
test_dump_memory (const char* name, const char* filename)
{
	dc_context_t *context = NULL;
	dc_device_t *device = NULL;

	dc_context_new (&context);
	dc_context_set_loglevel (context, DC_LOGLEVEL_ALL);
	dc_context_set_logfunc (context, logfunc, NULL);

	message ("oceanic_atom2_device_open\n");
	dc_status_t rc = oceanic_atom2_device_open (&device, context, name);
	if (rc != DC_STATUS_SUCCESS) {
		WARNING ("Error opening serial port.");
		dc_context_free (context);
		return rc;
	}

	dc_buffer_t *buffer = dc_buffer_new (0);

	message ("dc_device_dump\n");
	rc = dc_device_dump (device, buffer);
	if (rc != DC_STATUS_SUCCESS) {
		WARNING ("Cannot read memory.");
		dc_buffer_free (buffer);
		dc_device_close (device);
		dc_context_free (context);
		return rc;
	}

	message ("Dumping data\n");
	FILE* fp = fopen (filename, "wb");
	if (fp != NULL) {
		fwrite (dc_buffer_get_data (buffer), sizeof (unsigned char), dc_buffer_get_size (buffer), fp);
		fclose (fp);
	}

	dc_buffer_free (buffer);

	message ("dc_device_foreach\n");
	rc = dc_device_foreach (device, NULL, NULL);
	if (rc != DC_STATUS_SUCCESS) {
		WARNING ("Cannot read dives.");
		dc_device_close (device);
		dc_context_free (context);
		return rc;
	}

	message ("dc_device_close\n");
	rc = dc_device_close (device);
	if (rc != DC_STATUS_SUCCESS) {
		WARNING ("Cannot close device.");
		dc_context_free (context);
		return rc;
	}

	dc_context_free (context);

	return DC_STATUS_SUCCESS;
}
static dc_status_t
shearwater_predator_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
{
	dc_buffer_t *buffer = dc_buffer_new (SZ_MEMORY);
	if (buffer == NULL)
		return DC_STATUS_NOMEMORY;

	dc_status_t rc = shearwater_predator_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.model = data[0x2000D];
	devinfo.firmware = bcd2dec (data[0x2000A]);
	devinfo.serial = array_uint32_be (data + 0x20002);
	device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);

	rc = shearwater_predator_extract_dives (abstract, data, SZ_MEMORY, callback, userdata);

	dc_buffer_free (buffer);

	return rc;
}
Ejemplo n.º 3
0
static device_status_t
suunto_eon_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata)
{
	dc_buffer_t *buffer = dc_buffer_new (SUUNTO_EON_MEMORY_SIZE);
	if (buffer == NULL)
		return DEVICE_STATUS_MEMORY;

	device_status_t rc = suunto_eon_device_dump (abstract, buffer);
	if (rc != DEVICE_STATUS_SUCCESS) {
		dc_buffer_free (buffer);
		return rc;
	}

	// Emit a device info event.
	unsigned char *data = dc_buffer_get_data (buffer);
	device_devinfo_t devinfo;
	devinfo.model = 0;
	devinfo.firmware = 0;
	devinfo.serial = array_uint24_be (data + 244);
	device_event_emit (abstract, DEVICE_EVENT_DEVINFO, &devinfo);

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

	dc_buffer_free (buffer);

	return rc;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
static int
dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata)
{
	dive_data_t *divedata = (dive_data_t *) userdata;
	dc_status_t rc = DC_STATUS_SUCCESS;
	dc_parser_t *parser = NULL;

	divedata->number++;

	message ("Dive: number=%u, size=%u, fingerprint=", divedata->number, size);
	for (unsigned int i = 0; i < fsize; ++i)
		message ("%02X", fingerprint[i]);
	message ("\n");

	// Keep a copy of the most recent fingerprint. Because dives are
	// guaranteed to be downloaded in reverse order, the most recent
	// dive is always the first dive.
	if (divedata->number == 1) {
		dc_buffer_t *fp = dc_buffer_new (fsize);
		dc_buffer_append (fp, fingerprint, fsize);
		*divedata->fingerprint = fp;
	}

	// Create the parser.
	message ("Creating the parser.\n");
	rc = dc_parser_new (&parser, divedata->device);
	if (rc != DC_STATUS_SUCCESS) {
		ERROR ("Error creating the parser.");
		goto cleanup;
	}

	// Register the data.
	message ("Registering the data.\n");
	rc = dc_parser_set_data (parser, data, size);
	if (rc != DC_STATUS_SUCCESS) {
		ERROR ("Error registering the data.");
		goto cleanup;
	}

	// Parse the dive data.
	message ("Parsing the dive data.\n");
	rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize);
	if (rc != DC_STATUS_SUCCESS) {
		ERROR ("Error parsing the dive data.");
		goto cleanup;
	}

cleanup:
	dc_parser_destroy (parser);
	return 1;
}
Ejemplo n.º 6
0
device_status_t
test_dump_memory (const char* filename)
{
	device_t *device = NULL;

	message ("uwatec_smart_device_open\n");
	device_status_t rc = uwatec_smart_device_open (&device);
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Cannot open device.");
		return rc;
	}

	message ("device_version\n");
	unsigned char version[UWATEC_SMART_VERSION_SIZE] = {0};
	rc = device_version (device, version, sizeof (version));
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Cannot identify computer.");
		device_close (device);
		return rc;
	}

	dc_buffer_t *buffer = dc_buffer_new (0);

	message ("device_dump\n");
	rc = device_dump (device, buffer);
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Cannot read memory.");
		dc_buffer_free (buffer);
		device_close (device);
		return rc;
	}

	message ("Dumping data\n");
	FILE* fp = fopen (filename, "wb");
	if (fp != NULL) {
		fwrite (dc_buffer_get_data (buffer), sizeof (unsigned char), dc_buffer_get_size (buffer), fp);
		fclose (fp);
	}

	dc_buffer_free (buffer);

	message ("device_close\n");
	rc = device_close (device);
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Cannot close device.");
		return rc;
	}

	return DEVICE_STATUS_SUCCESS;
}
device_status_t
test_dump_memory (const char* name, const char* filename)
{
	device_t *device = NULL;

	message ("reefnet_sensuspro_device_open\n");
	device_status_t rc = reefnet_sensuspro_device_open (&device, name);
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Error opening serial port.");
		return rc;
	}

	time_t now = time (NULL);
	char datetime[21] = {0};
	strftime (datetime, sizeof (datetime), "%Y-%m-%dT%H:%M:%SZ", gmtime (&now));
	message ("time=%lu (%s)\n", (unsigned long)now, datetime);

	dc_buffer_t *buffer = dc_buffer_new (0);

	message ("device_dump\n");
	rc = device_dump (device, buffer);
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Cannot read memory.");
		dc_buffer_free (buffer);
		device_close (device);
		return rc;
	}

	message ("Dumping data\n");
	FILE* fp = fopen (filename, "wb");
	if (fp != NULL) {
		fwrite (dc_buffer_get_data (buffer), sizeof (unsigned char), dc_buffer_get_size (buffer), fp);
		fclose (fp);
	}

	dc_buffer_free (buffer);

	message ("device_close\n");
	rc = device_close (device);
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Cannot close device.");
		return rc;
	}

	return DEVICE_STATUS_SUCCESS;
}
Ejemplo n.º 8
0
static dc_status_t
uwatec_meridian_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 = uwatec_meridian_device_dump (abstract, buffer);
	if (rc != DC_STATUS_SUCCESS) {
		dc_buffer_free (buffer);
		return rc;
	}

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

	dc_buffer_free (buffer);

	return rc;
}
Ejemplo n.º 9
0
device_status_t
test_dump_memory (const char* name, const char* filename)
{
	device_t *device = NULL;

	message ("suunto_solution_device_open\n");
	int rc = suunto_solution_device_open (&device, name);
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Error opening serial port.");
		return rc;
	}

	dc_buffer_t *buffer = dc_buffer_new (0);

	message ("device_dump\n");
	rc = device_dump (device, buffer);
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Cannot read memory.");
		dc_buffer_free (buffer);
		device_close (device);
		return rc;
	}

	message ("Dumping data\n");
	FILE* fp = fopen (filename, "wb");
	if (fp != NULL) {
		fwrite (dc_buffer_get_data (buffer), sizeof (unsigned char), dc_buffer_get_size (buffer), fp);
		fclose (fp);
	}

	dc_buffer_free (buffer);

	message ("device_close\n");
	rc = device_close (device);
	if (rc != DEVICE_STATUS_SUCCESS) {
		WARNING ("Cannot close device.");
		return rc;
	}

	return DEVICE_STATUS_SUCCESS;
}
Ejemplo n.º 10
0
static dc_buffer_t *
fpconvert (const char *fingerprint) {
    unsigned int i = 0;

    /* get the length of the fingerprint data */
    size_t nbytes = (fingerprint ? strlen(fingerprint) / 2 : 0);
    if (nbytes == 0) {
        return NULL;
    }

    /* allocate a memory buffer */
    dc_buffer_t *buffer = dc_buffer_new(nbytes);

    /* convert the hexadecimal string */
    for (i = 0; i < nbytes; ++i) {
        unsigned char msn = hex2dec(fingerprint[i*2+0]);
        unsigned char lsn = hex2dec(fingerprint[i*2+1]);
        unsigned char byte = (msn << 4) + lsn;

        dc_buffer_append(buffer, &byte, 1);
    }

    return buffer;
}
Ejemplo n.º 11
0
static dc_status_t
atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
{
	atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract;

	// Enable progress notifications.
	dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
	progress.maximum = SZ_MEMORY + 2;
	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 = array_uint16_le (device->version + 12);
	devinfo.firmware = (array_uint16_le (device->version + 8) << 16)
		+ array_uint16_le (device->version + 10);
	devinfo.serial = 0;
	for (unsigned int i = 0; i < 8; ++i) {
		devinfo.serial *= 10;
		devinfo.serial += device->version[i] - '0';
	}
	device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);

	// Allocate a memory buffer.
	dc_buffer_t *buffer = dc_buffer_new (0);
	if (buffer == NULL)
		return DC_STATUS_NOMEMORY;

	unsigned int ndives = 0;
	dc_status_t rc = DC_STATUS_SUCCESS;
	while ((rc = atomics_cobalt_read_dive (abstract, buffer, (ndives == 0), &progress)) == DC_STATUS_SUCCESS) {
		unsigned char *data = dc_buffer_get_data (buffer);
		unsigned int size = dc_buffer_get_size (buffer);

		if (size == 0) {
			dc_buffer_free (buffer);
			return DC_STATUS_SUCCESS;
		}

		if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) {
			dc_buffer_free (buffer);
			return DC_STATUS_SUCCESS;
		}

		if (callback && !callback (data, size, data + FP_OFFSET, sizeof (device->fingerprint), userdata)) {
			dc_buffer_free (buffer);
			return DC_STATUS_SUCCESS;
		}

		// Adjust the maximum value to take into account the two checksum bytes
		// for the next dive. Since we don't know the total number of dives in
		// advance, we can't calculate the total number of checksum bytes and
		// adjust the maximum on the fly.
		progress.maximum += 2;

		ndives++;
	}

	dc_buffer_free (buffer);

	return rc;
}
Ejemplo n.º 12
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;
}
Ejemplo n.º 13
0
void Java_com_libdivecomputer_android_Buffer_alloc(JNIEnv* envPtr, jobject object_Buffer, jlong capacity) {
	dc_buffer_t* bufferPtr = dc_buffer_new((size_t)capacity);
	setNativePtr(envPtr, object_Buffer, bufferPtr);
}
Ejemplo n.º 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;
}