dc_status_t hw_ostc_device_md2hash (dc_device_t *abstract, unsigned char data[], unsigned int size) { hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (size < SZ_MD2HASH) { ERROR (abstract->context, "Insufficient buffer space available."); return DC_STATUS_INVALIDARGS; } // Send the command. dc_status_t rc = hw_ostc_send (device, 'e', 0); if (rc != DC_STATUS_SUCCESS) return rc; // Read the answer. int n = serial_read (device->port, data, SZ_MD2HASH); if (n != SZ_MD2HASH) { ERROR (abstract->context, "Failed to receive the answer."); return EXITCODE (n); } return DC_STATUS_SUCCESS; }
dc_status_t hw_ostc_device_eeprom_write (dc_device_t *abstract, unsigned int bank, const unsigned char data[], unsigned int size) { hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (bank > 2) { ERROR (abstract->context, "Invalid eeprom bank specified."); return DC_STATUS_INVALIDARGS; } if (size != SZ_EEPROM) { ERROR (abstract->context, "Insufficient buffer space available."); return DC_STATUS_INVALIDARGS; } // Send the command. const unsigned char command[] = {'d', 'i', 'n'}; dc_status_t rc = hw_ostc_send (device, command[bank], 1); if (rc != DC_STATUS_SUCCESS) return rc; for (unsigned int i = 4; i < SZ_EEPROM; ++i) { // Send the data byte. rc = hw_ostc_send (device, data[i], 1); if (rc != DC_STATUS_SUCCESS) return rc; } return DC_STATUS_SUCCESS; }
dc_status_t hw_ostc_device_eeprom_read (dc_device_t *abstract, unsigned int bank, unsigned char data[], unsigned int size) { hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (bank > 2) { ERROR (abstract->context, "Invalid eeprom bank specified."); return DC_STATUS_INVALIDARGS; } if (size < SZ_EEPROM) { ERROR (abstract->context, "Insufficient buffer space available."); return DC_STATUS_INVALIDARGS; } // Send the command. const unsigned char command[] = {'g', 'j', 'm'}; dc_status_t rc = hw_ostc_send (device, command[bank], 0); if (rc != DC_STATUS_SUCCESS) return rc; // Read the answer. int n = serial_read (device->port, data, SZ_EEPROM); if (n != SZ_EEPROM) { ERROR (abstract->context, "Failed to receive the answer."); return EXITCODE (n); } return DC_STATUS_SUCCESS; }
dc_status_t hw_ostc_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime) { hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (datetime == NULL) { ERROR (abstract->context, "Invalid parameter specified."); return DC_STATUS_INVALIDARGS; } // Send the command. dc_status_t rc = hw_ostc_send (device, 'b', 1); if (rc != DC_STATUS_SUCCESS) return rc; // Send the data packet. unsigned char packet[6] = { datetime->hour, datetime->minute, datetime->second, datetime->month, datetime->day, datetime->year - 2000}; int n = serial_write (device->port, packet, sizeof (packet)); if (n != sizeof (packet)) { ERROR (abstract->context, "Failed to send the data packet."); return EXITCODE (n); } return DC_STATUS_SUCCESS; }
dc_status_t uwatec_meridian_extract_dives (dc_device_t *abstract, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata) { if (abstract && !ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; const unsigned char header[4] = {0xa5, 0xa5, 0x5a, 0x5a}; // Search the data stream for start markers. unsigned int previous = size; unsigned int current = (size >= 4 ? size - 4 : 0); while (current > 0) { current--; if (memcmp (data + current, header, sizeof (header)) == 0) { // Get the length of the profile data. unsigned int len = array_uint32_le (data + current + 4); // Check for a buffer overflow. if (current + len > previous) return DC_STATUS_DATAFORMAT; if (callback && !callback (data + current, len, data + current + 8, 4, userdata)) return DC_STATUS_SUCCESS; // Prepare for the next dive. previous = current; current = (current >= 4 ? current - 4 : 0); } } return DC_STATUS_SUCCESS; }
dc_status_t oceanic_vtpro_device_version (dc_device_t *abstract, unsigned char data[], unsigned int size) { oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t*) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (size < PAGESIZE) return DC_STATUS_INVALIDARGS; // Switch the device into download mode. The response is ignored here, // since it is identical (except for the missing trailing byte) to the // response of the first part of the other command in this function. unsigned char cmd[2] = {0x88, 0x00}; unsigned char ans[PAGESIZE / 2 + 1] = {0}; dc_status_t rc = oceanic_vtpro_transfer (device, cmd, sizeof (cmd), ans, sizeof (ans)); if (rc != DC_STATUS_SUCCESS) return rc; // Verify the checksum of the answer. unsigned char crc = ans[PAGESIZE / 2]; unsigned char ccrc = checksum_add_uint4 (ans, PAGESIZE / 2, 0x00); if (crc != ccrc) { ERROR (abstract->context, "Unexpected answer checksum."); return DC_STATUS_PROTOCOL; } // Obtain the device identification string. This string is // split over two packets, but we join both parts again. for (unsigned int i = 0; i < 2; ++i) { unsigned char command[4] = {0x72, 0x03, i * 0x10, 0x00}; unsigned char answer[PAGESIZE / 2 + 2] = {0}; rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer)); if (rc != DC_STATUS_SUCCESS) return rc; // Verify the checksum of the answer. unsigned char crc = answer[PAGESIZE / 2]; unsigned char ccrc = checksum_add_uint4 (answer, PAGESIZE / 2, 0x00); if (crc != ccrc) { ERROR (abstract->context, "Unexpected answer checksum."); return DC_STATUS_PROTOCOL; } // Verify the last byte of the answer. if (answer[PAGESIZE / 2 + 1] != END) { ERROR (abstract->context, "Unexpected answer byte."); return DC_STATUS_PROTOCOL; } // Append the answer to the output buffer. memcpy (data + i * PAGESIZE / 2, answer, PAGESIZE / 2); } return DC_STATUS_SUCCESS; }
dc_status_t atomics_cobalt_device_set_simulation (dc_device_t *abstract, unsigned int simulation) { atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; device->simulation = simulation; return DC_STATUS_SUCCESS; }
dc_status_t reefnet_sensus_parser_set_calibration (dc_parser_t *abstract, double atmospheric, double hydrostatic) { reefnet_sensus_parser_t *parser = (reefnet_sensus_parser_t*) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; parser->atmospheric = atmospheric; parser->hydrostatic = hydrostatic; return DC_STATUS_SUCCESS; }
dc_status_t atomics_cobalt_device_version (dc_device_t *abstract, unsigned char data[], unsigned int size) { atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (size < SZ_VERSION) return DC_STATUS_INVALIDARGS; #ifdef HAVE_LIBUSB // Send the command to the dive computer. uint8_t bRequest = 0x01; 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); // Receive the answer from the dive computer. int length = 0; unsigned char packet[SZ_VERSION + 2] = {0}; rc = libusb_bulk_transfer (device->handle, 0x82, packet, sizeof (packet), &length, TIMEOUT); if (rc != LIBUSB_SUCCESS || length != sizeof (packet)) { ERROR (abstract->context, "Failed to receive the answer."); return EXITCODE(rc); } HEXDUMP (abstract->context, DC_LOGLEVEL_INFO, "Read", packet, length); // Verify the checksum of the packet. unsigned short crc = array_uint16_le (packet + SZ_VERSION); unsigned short ccrc = checksum_add_uint16 (packet, SZ_VERSION, 0x0); if (crc != ccrc) { ERROR (abstract->context, "Unexpected answer checksum."); return DC_STATUS_PROTOCOL; } memcpy (data, packet, SZ_VERSION); return DC_STATUS_SUCCESS; #else return DC_STATUS_UNSUPPORTED; #endif }
dc_status_t hw_ostc3_device_config_reset (dc_device_t *abstract) { hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; // Send the command. dc_status_t rc = hw_ostc3_transfer (device, NULL, RESET, NULL, 0, NULL, 0); if (rc != DC_STATUS_SUCCESS) return rc; return DC_STATUS_SUCCESS; }
dc_status_t hw_ostc_device_reset (dc_device_t *abstract) { hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; // Send the command. dc_status_t rc = hw_ostc_send (device, 'h', 1); if (rc != DC_STATUS_SUCCESS) return rc; return DC_STATUS_SUCCESS; }
static dc_status_t shearwater_predator_extract_dives (dc_device_t *abstract, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata) { if (abstract && !ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (size < SZ_MEMORY) return DC_STATUS_DATAFORMAT; unsigned int model = data[0x2000D]; if (model == PETREL) { return shearwater_predator_extract_petrel (abstract, data, size, callback, userdata); } else { return shearwater_predator_extract_predator (abstract, data, size, callback, userdata); } }
dc_status_t reefnet_sensus_device_get_handshake (dc_device_t *abstract, unsigned char data[], unsigned int size) { reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (size < SZ_HANDSHAKE) { ERROR (abstract->context, "Insufficient buffer space available."); return DC_STATUS_INVALIDARGS; } memcpy (data, device->handshake, SZ_HANDSHAKE); return DC_STATUS_SUCCESS; }
dc_status_t hw_ostc3_device_version (dc_device_t *abstract, unsigned char data[], unsigned int size) { hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (size != SZ_VERSION) return DC_STATUS_INVALIDARGS; // Send the command. dc_status_t rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, data, size); if (rc != DC_STATUS_SUCCESS) return rc; return DC_STATUS_SUCCESS; }
dc_status_t hw_ostc_extract_dives (dc_device_t *abstract, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata) { hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (abstract && !ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; const unsigned char header[2] = {0xFA, 0xFA}; const unsigned char footer[2] = {0xFD, 0xFD}; // Initialize the data stream pointers. const unsigned char *current = data + size; const unsigned char *previous = data + size; // Search the data stream for header markers. while ((current = array_search_backward (data + 266, current - data - 266, header, sizeof (header))) != NULL) { // Move the pointer to the begin of the header. current -= sizeof (header); // Once a header marker is found, start searching // for the corresponding footer marker. The search is // now limited to the start of the previous dive. previous = array_search_forward (current, previous - current, footer, sizeof (footer)); if (previous) { // Move the pointer to the end of the footer. previous += sizeof (footer); if (device && memcmp (current + 3, device->fingerprint, sizeof (device->fingerprint)) == 0) return DC_STATUS_SUCCESS; if (callback && !callback (current, previous - current, current + 3, 5, userdata)) return DC_STATUS_SUCCESS; } // Prepare for the next iteration. previous = current; } return DC_STATUS_SUCCESS; }
dc_status_t hw_ostc3_device_config_read (dc_device_t *abstract, unsigned int config, unsigned char data[], unsigned int size) { hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (size > SZ_CONFIG) { ERROR (abstract->context, "Invalid parameter specified."); return DC_STATUS_INVALIDARGS; } // Send the command. unsigned char command[1] = {config}; dc_status_t rc = hw_ostc3_transfer (device, NULL, READ, command, sizeof (command), data, size); if (rc != DC_STATUS_SUCCESS) return rc; return DC_STATUS_SUCCESS; }
dc_status_t hw_ostc3_device_customtext (dc_device_t *abstract, const char *text) { hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; // Pad the data packet with spaces. unsigned char packet[SZ_CUSTOMTEXT] = {0}; if (hw_ostc3_strncpy (packet, sizeof (packet), text) != 0) { ERROR (abstract->context, "Invalid parameter specified."); return DC_STATUS_INVALIDARGS; } // Send the command. dc_status_t rc = hw_ostc3_transfer (device, NULL, CUSTOMTEXT, packet, sizeof (packet), NULL, 0); if (rc != DC_STATUS_SUCCESS) return rc; return DC_STATUS_SUCCESS; }
dc_status_t hw_ostc3_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime) { hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (datetime == NULL) { ERROR (abstract->context, "Invalid parameter specified."); return DC_STATUS_INVALIDARGS; } // Send the command. unsigned char packet[6] = { datetime->hour, datetime->minute, datetime->second, datetime->month, datetime->day, datetime->year - 2000}; dc_status_t rc = hw_ostc3_transfer (device, NULL, CLOCK, packet, sizeof (packet), NULL, 0); if (rc != DC_STATUS_SUCCESS) return rc; return DC_STATUS_SUCCESS; }
dc_status_t oceanic_vtpro_device_keepalive (dc_device_t *abstract) { oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t*) abstract; if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; // Send the command to the dive computer. unsigned char answer[1] = {0}; unsigned char command[4] = {0x6A, 0x08, 0x00, 0x00}; dc_status_t rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer)); if (rc != DC_STATUS_SUCCESS) return rc; // Verify the last byte of the answer. if (answer[0] != END) { ERROR (abstract->context, "Unexpected answer byte(s)."); return DC_STATUS_PROTOCOL; } return DC_STATUS_SUCCESS; }
int isUnicodeString(PyObject *arg) { return (PyObject_TypeCheck(arg, &UObjectType_) && ISINSTANCE(((t_uobject *) arg)->object, UnicodeString)); }
dc_status_t reefnet_sensus_extract_dives (dc_device_t *abstract, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata) { reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract; dc_context_t *context = (abstract ? abstract->context : NULL); if (abstract && !ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; // Search the entire data stream for start markers. unsigned int previous = size; unsigned int current = (size >= 7 ? size - 7 : 0); while (current > 0) { current--; if (data[current] == 0xFF && data[current + 6] == 0xFE) { // Once a start marker is found, start searching // for the end of the dive. The search is now // limited to the start of the previous dive. int found = 0; unsigned int nsamples = 0, count = 0; unsigned int offset = current + 7; // Skip non-sample data. while (offset + 1 <= previous) { // Depth (adjusted feet of seawater). unsigned char depth = data[offset++]; // Temperature (degrees Fahrenheit) if ((nsamples % 6) == 0) { if (offset + 1 > previous) break; offset++; } // Current sample is complete. nsamples++; // The end of a dive is reached when 17 consecutive // depth samples of less than 3 feet have been found. if (depth < 13 + 3) { count++; if (count == 17) { found = 1; break; } } else { count = 0; } } // Report an error if no end of dive was found. if (!found) { ERROR (context, "No end of dive found."); return DC_STATUS_DATAFORMAT; } // Automatically abort when a dive is older than the provided timestamp. unsigned int timestamp = array_uint32_le (data + current + 2); if (device && timestamp <= device->timestamp) return DC_STATUS_SUCCESS; if (callback && !callback (data + current, offset - current, data + current + 2, 4, userdata)) return DC_STATUS_SUCCESS; // Prepare for the next dive. previous = current; current = (current >= 7 ? current - 7 : 0); } } return DC_STATUS_SUCCESS; }
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; }
/* * Think twice before modifying the code for updating the ostc firmware! * It has been carefully developed and tested with assistance from * Heinrichs-Weikamp, using a special development unit. If you start * experimenting with a normal unit and accidentally screw up, you might * brick the device permanently and turn it into an expensive * paperweight. You have been warned! */ dc_status_t hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename) { dc_status_t rc = DC_STATUS_SUCCESS; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; dc_context_t *context = (abstract ? abstract->context : NULL); if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; // Allocate memory for the firmware data. hw_ostc_firmware_t *firmware = (hw_ostc_firmware_t *) malloc (sizeof (hw_ostc_firmware_t)); if (firmware == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Read the hex file. rc = hw_ostc_firmware_readfile (firmware, context, filename); if (rc != DC_STATUS_SUCCESS) { ERROR (context, "Failed to read the firmware file."); free (firmware); return rc; } // Temporary set a relative short timeout. The command to setup the // bootloader needs to be send repeatedly, until the response packet is // received. Thus the time between each two attempts is directly controlled // by the timeout value. serial_set_timeout (device->port, 300); // Setup the bootloader. const unsigned int baudrates[] = {19200, 115200}; for (unsigned int i = 0; i < C_ARRAY_SIZE(baudrates); ++i) { // Adjust the baudrate. if (serial_configure (device->port, baudrates[i], 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE) == -1) { ERROR (abstract->context, "Failed to set the terminal attributes."); free (firmware); return DC_STATUS_IO; } // Try to setup the bootloader. unsigned int maxretries = (i == 0 ? 1 : MAXRETRIES); rc = hw_ostc_firmware_setup (device, maxretries); if (rc == DC_STATUS_SUCCESS) break; } if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to setup the bootloader."); free (firmware); return rc; } // Increase the timeout again. serial_set_timeout (device->port, 1000); // Enable progress notifications. dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; progress.maximum = C_ARRAY_SIZE(firmware->bitmap); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); for (unsigned int i = 0; i < C_ARRAY_SIZE(firmware->bitmap); ++i) { // Skip empty blocks. if (firmware->bitmap[i] == 0) continue; // Create the packet. unsigned int address = i * SZ_BLOCK; unsigned char packet[4 + SZ_BLOCK + 1] = { (address >> 16) & 0xFF, (address >> 8) & 0xFF, (address ) & 0xFF, SZ_BLOCK }; memcpy (packet + 4, firmware->data + address, SZ_BLOCK); packet[sizeof (packet) - 1] = ~checksum_add_uint8 (packet, 4 + SZ_BLOCK, 0x00) + 1; // Send the packet. rc = hw_ostc_firmware_write (device, packet, sizeof (packet)); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the packet."); free (firmware); return rc; } // Update and emit a progress event. progress.current = i + 1; device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); } free (firmware); return DC_STATUS_SUCCESS; }
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; }
dc_status_t cressi_leonardo_extract_dives (dc_device_t *abstract, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata) { cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract; dc_context_t *context = (abstract ? abstract->context : NULL); if (abstract && !ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; if (size < SZ_MEMORY) return DC_STATUS_DATAFORMAT; // 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 = RB_LOGBOOK_BEGIN + i * RB_LOGBOOK_SIZE; // Ignore uninitialized header entries. if (array_isequal (data + offset, RB_LOGBOOK_SIZE, 0xFF)) break; // Get the internal dive number. unsigned int current = array_uint16_le (data + offset); if (current > maximum) { maximum = current; latest = i; } count++; } unsigned char *buffer = (unsigned char *) malloc (RB_LOGBOOK_SIZE + RB_PROFILE_END - RB_PROFILE_BEGIN); if (buffer == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } for (unsigned int i = 0; i < count; ++i) { unsigned int idx = (latest + RB_LOGBOOK_COUNT - i) % RB_LOGBOOK_COUNT; unsigned int offset = RB_LOGBOOK_BEGIN + idx * RB_LOGBOOK_SIZE; // Get the ringbuffer pointers. unsigned int header = array_uint16_le (data + offset + 2); unsigned int footer = array_uint16_le (data + offset + 4); if (header < RB_PROFILE_BEGIN || header + 2 > RB_PROFILE_END || footer < RB_PROFILE_BEGIN || footer + 2 > RB_PROFILE_END) { ERROR (abstract->context, "Invalid ringbuffer pointer detected."); free (buffer); return DC_STATUS_DATAFORMAT; } // Get the same pointers from the profile. unsigned int header2 = array_uint16_le (data + footer); unsigned int footer2 = array_uint16_le (data + header); if (header2 != header || footer2 != footer) { ERROR (abstract->context, "Invalid ringbuffer pointer detected."); free (buffer); return DC_STATUS_DATAFORMAT; } // Calculate the profile address and length. unsigned int address = header + 2; unsigned int length = RB_PROFILE_DISTANCE (header, footer) - 2; // Check the fingerprint data. if (device && memcmp (data + offset + 8, device->fingerprint, sizeof (device->fingerprint)) == 0) break; // Copy the logbook entry. memcpy (buffer, data + offset, RB_LOGBOOK_SIZE); // Copy the profile data. if (address + length > RB_PROFILE_END) { unsigned int len_a = RB_PROFILE_END - address; unsigned int len_b = length - len_a; memcpy (buffer + RB_LOGBOOK_SIZE, data + address, len_a); memcpy (buffer + RB_LOGBOOK_SIZE + len_a, data + RB_PROFILE_BEGIN, len_b); } else { memcpy (buffer + RB_LOGBOOK_SIZE, data + address, length); } if (callback && !callback (buffer, RB_LOGBOOK_SIZE + length, buffer + 8, sizeof (device->fingerprint), userdata)) { break; } } free (buffer); return DC_STATUS_SUCCESS; }