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; }
static dc_status_t shearwater_predator_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) { const unsigned char *data = abstract->data; unsigned int size = abstract->size; if (size < 2 * SZ_BLOCK) return DC_STATUS_DATAFORMAT; unsigned int ticks = array_uint32_be (data + 12); if (!dc_datetime_gmtime (datetime, ticks)) return DC_STATUS_DATAFORMAT; return DC_STATUS_SUCCESS; }
device_status_t suunto_common2_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata) { suunto_common2_device_t *device = (suunto_common2_device_t*) abstract; // Enable progress notifications. device_progress_t progress = DEVICE_PROGRESS_INITIALIZER; progress.maximum = RB_PROFILE_END - RB_PROFILE_BEGIN + 8 + SZ_VERSION + (SZ_MINIMUM > 4 ? SZ_MINIMUM : 4); device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); // Read the version info. unsigned char version[SZ_VERSION] = {0}; device_status_t rc = suunto_common2_device_version (abstract, version, sizeof (version)); if (rc != DEVICE_STATUS_SUCCESS) { WARNING ("Cannot read memory header."); return rc; } // Update and emit a progress event. progress.current += sizeof (version); device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); // Read the serial number. unsigned char serial[SZ_MINIMUM > 4 ? SZ_MINIMUM : 4] = {0}; rc = suunto_common2_device_read (abstract, 0x0023, serial, sizeof (serial)); if (rc != DEVICE_STATUS_SUCCESS) { WARNING ("Cannot read memory header."); return rc; } // Update and emit a progress event. progress.current += sizeof (serial); device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); // Emit a device info event. device_devinfo_t devinfo; devinfo.model = version[0]; devinfo.firmware = array_uint24_be (version + 1); devinfo.serial = array_uint32_be (serial); device_event_emit (abstract, DEVICE_EVENT_DEVINFO, &devinfo); // Read the header bytes. unsigned char header[8] = {0}; rc = suunto_common2_device_read (abstract, 0x0190, header, sizeof (header)); if (rc != DEVICE_STATUS_SUCCESS) { WARNING ("Cannot read memory header."); return rc; } // Obtain the pointers from the header. unsigned int last = array_uint16_le (header + 0); unsigned int count = array_uint16_le (header + 2); unsigned int end = array_uint16_le (header + 4); unsigned int begin = array_uint16_le (header + 6); // Memory buffer to store all the dives. unsigned char data[SZ_MINIMUM + RB_PROFILE_END - RB_PROFILE_BEGIN] = {0}; // Calculate the total amount of bytes. unsigned int remaining = RB_PROFILE_DISTANCE (begin, end, count != 0); // Update and emit a progress event. progress.maximum -= (RB_PROFILE_END - RB_PROFILE_BEGIN) - remaining; progress.current += sizeof (header); device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); // To reduce the number of read operations, we always try to read // packages with the largest possible size. As a consequence, the // last package of a dive can contain data from more than one dive. // Therefore, the remaining data of this package (and its size) // needs to be preserved for the next dive. unsigned int available = 0; // The ring buffer is traversed backwards to retrieve the most recent // dives first. This allows us to download only the new dives. unsigned int current = last; unsigned int previous = end; unsigned int address = previous; unsigned int offset = remaining + SZ_MINIMUM; while (remaining) { // Calculate the size of the current dive. unsigned int size = RB_PROFILE_DISTANCE (current, previous, 1); if (size < 4 || size > remaining) { WARNING ("Unexpected profile size."); return DEVICE_STATUS_ERROR; } unsigned int nbytes = available; while (nbytes < size) { // Handle the ringbuffer wrap point. if (address == RB_PROFILE_BEGIN) address = RB_PROFILE_END; // Calculate the package size. Try with the largest possible // size first, and adjust when the end of the ringbuffer or // the end of the profile data is reached. unsigned int len = SZ_PACKET; if (RB_PROFILE_BEGIN + len > address) len = address - RB_PROFILE_BEGIN; // End of ringbuffer. if (nbytes + len > remaining) len = remaining - nbytes; // End of profile. /*if (nbytes + len > size) len = size - nbytes;*/ // End of dive (for testing only). // Move to the begin of the current package. offset -= len; address -= len; // Always read at least the minimum amount of bytes, because // reading fewer bytes is unreliable. The memory buffer is // large enough to prevent buffer overflows, and the extra // bytes are automatically ignored (due to reading backwards). unsigned int extra = 0; if (len < SZ_MINIMUM) extra = SZ_MINIMUM - len; // Read the package. rc = suunto_common2_device_read (abstract, address - extra, data + offset - extra, len + extra); if (rc != DEVICE_STATUS_SUCCESS) { WARNING ("Cannot read memory."); return rc; } // Update and emit a progress event. progress.current += len; device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); // Next package. nbytes += len; } // The last package of the current dive contains the previous and // next pointers (in a continuous memory area). It can also contain // a number of bytes from the next dive. remaining -= size; available = nbytes - size; unsigned char *p = data + offset + available; unsigned int prev = array_uint16_le (p + 0); unsigned int next = array_uint16_le (p + 2); if (next != previous) { WARNING ("Profiles are not continuous."); return DEVICE_STATUS_ERROR; } // Next dive. previous = current; current = prev; unsigned int fp_offset = FP_OFFSET; if (devinfo.model == 0x15) fp_offset += 6; // HelO2 if (memcmp (p + fp_offset, device->fingerprint, sizeof (device->fingerprint)) == 0) return DEVICE_STATUS_SUCCESS; if (callback && !callback (p + 4, size - 4, p + fp_offset, sizeof (device->fingerprint), userdata)) return DEVICE_STATUS_SUCCESS; } return DEVICE_STATUS_SUCCESS; }
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; }
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; }
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; }
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; }