Add support for the OSTC screenshot feature.

This commit is contained in:
Jef Driesen 2011-07-24 07:34:37 +02:00
parent 57615abc0c
commit d3e522b070
3 changed files with 150 additions and 0 deletions

View File

@ -42,6 +42,11 @@
#define SZ_FW_190 0x8000
#define SZ_FW_NEW 0x10000
#define WIDTH 320
#define HEIGHT 240
#define BLACK 0x00
#define WHITE 0xFF
typedef struct hw_ostc_device_t {
device_t base;
serial_t *port;
@ -476,6 +481,141 @@ hw_ostc_device_reset (device_t *abstract)
}
device_status_t
hw_ostc_device_screenshot (device_t *abstract, dc_buffer_t *buffer, hw_ostc_format_t format)
{
hw_ostc_device_t *device = (hw_ostc_device_t *) abstract;
if (! device_is_hw_ostc (abstract))
return DEVICE_STATUS_TYPE_MISMATCH;
// Erase the current contents of the buffer.
if (!dc_buffer_clear (buffer)) {
WARNING ("Insufficient buffer space available.");
return DEVICE_STATUS_MEMORY;
}
// 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)) {
WARNING ("Insufficient buffer space available.");
return DEVICE_STATUS_MEMORY;
}
} 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)) {
WARNING ("Insufficient buffer space available.");
return DEVICE_STATUS_MEMORY;
}
}
// Enable progress notifications.
device_progress_t progress = DEVICE_PROGRESS_INITIALIZER;
progress.maximum = WIDTH * HEIGHT;
device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress);
// Send the command.
device_status_t rc = hw_ostc_send (device, 'l', 1);
if (rc != DEVICE_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) {
WARNING ("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) {
WARNING ("Failed to receive the packet.");
return EXITCODE (n);
}
nbytes += n;
count &= 0x3F;
}
count++;
// Check for buffer overflows.
if (npixels + count > WIDTH * HEIGHT) {
WARNING ("Unexpected number of pixels received.");
return DEVICE_STATUS_ERROR;
}
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, DEVICE_EVENT_PROGRESS, &progress);
npixels += count;
}
return DEVICE_STATUS_SUCCESS;
}
device_status_t
hw_ostc_extract_dives (device_t *abstract, const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata)
{

View File

@ -30,6 +30,12 @@
extern "C" {
#endif /* __cplusplus */
typedef enum hw_ostc_format_t {
HW_OSTC_FORMAT_RAW,
HW_OSTC_FORMAT_RGB16,
HW_OSTC_FORMAT_RGB24
} hw_ostc_format_t;
device_status_t
hw_ostc_device_open (device_t **device, const char* name);
@ -48,6 +54,9 @@ hw_ostc_device_eeprom_write (device_t *abstract, unsigned int bank, const unsign
device_status_t
hw_ostc_device_reset (device_t *abstract);
device_status_t
hw_ostc_device_screenshot (device_t *abstract, dc_buffer_t *buffer, hw_ostc_format_t format);
device_status_t
hw_ostc_extract_dives (device_t *abstract, const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata);

View File

@ -119,6 +119,7 @@ hw_ostc_device_clock
hw_ostc_device_eeprom_read
hw_ostc_device_eeprom_write
hw_ostc_device_reset
hw_ostc_device_screenshot
hw_ostc_extract_dives
zeagle_n2ition3_device_open
atomics_cobalt_device_open