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; }
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); }
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; }
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; }
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; }