28 #include "serialize.h"
31 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
37 # define __attribute__(x)
41 #if defined _WIN32 || defined __CYGWIN__
42 #define AM7XXX_PUBLIC __declspec(dllexport)
46 #define AM7XXX_PUBLIC __attribute__ ((visibility ("default")))
47 #define AM7XXX_LOCAL __attribute__ ((visibility ("hidden")))
59 ...) __attribute__ ((format (printf, 5, 6)));
61 #define fatal(...) log_message(NULL, AM7XXX_LOG_FATAL, __func__, __LINE__, __VA_ARGS__)
62 #define error(ctx, ...) log_message(ctx, AM7XXX_LOG_ERROR, __func__, __LINE__, __VA_ARGS__)
63 #define warning(ctx, ...) log_message(ctx, AM7XXX_LOG_WARNING, __func__, 0, __VA_ARGS__)
64 #define info(ctx, ...) log_message(ctx, AM7XXX_LOG_INFO, __func__, 0, __VA_ARGS__)
65 #define debug(ctx, ...) log_message(ctx, AM7XXX_LOG_DEBUG, __func__, 0, __VA_ARGS__)
66 #define trace(ctx, ...) log_message(ctx, AM7XXX_LOG_TRACE, NULL, 0, __VA_ARGS__)
73 struct am7xxx_usb_device_descriptor {
77 uint8_t configuration;
78 uint8_t interface_number;
79 struct am7xxx_ops ops;
87 #define DEFAULT_OPS { \
88 .set_power_mode = default_set_power_mode, \
89 .set_zoom_mode = default_set_zoom_mode, \
92 static const struct am7xxx_usb_device_descriptor supported_devices[] = {
98 .interface_number = 0,
104 .product_id = 0x5501,
106 .interface_number = 0,
110 .name =
"Aiptek PocketCinema T25",
112 .product_id = 0x2144,
114 .interface_number = 0,
118 .name =
"Philips/Sagemcom PicoPix 1020",
120 .product_id = 0x000e,
122 .interface_number = 0,
126 .name =
"Philips/Sagemcom PicoPix 2055",
128 .product_id = 0x0016,
130 .interface_number = 0,
132 .set_power_mode = picopix_set_power_mode,
133 .set_zoom_mode = picopix_set_zoom_mode,
137 .name =
"Philips/Sagemcom PicoPix 2330",
139 .product_id = 0x0019,
141 .interface_number = 0,
149 #define AM7XXX_HEADER_WIRE_SIZE 24
151 struct _am7xxx_device {
152 libusb_device_handle *usb_device;
153 struct libusb_transfer *transfer;
154 int transfer_completed;
155 uint8_t buffer[AM7XXX_HEADER_WIRE_SIZE];
158 const struct am7xxx_usb_device_descriptor *desc;
162 struct _am7xxx_context {
163 libusb_context *usb_context;
169 AM7XXX_PACKET_TYPE_DEVINFO = 0x01,
170 AM7XXX_PACKET_TYPE_IMAGE = 0x02,
171 AM7XXX_PACKET_TYPE_POWER = 0x04,
172 AM7XXX_PACKET_TYPE_ZOOM = 0x05,
173 AM7XXX_PACKET_TYPE_PICOPIX_POWER_LOW = 0x15,
174 AM7XXX_PACKET_TYPE_PICOPIX_POWER_MEDIUM = 0x16,
175 AM7XXX_PACKET_TYPE_PICOPIX_POWER_HIGH = 0x17,
176 AM7XXX_PACKET_TYPE_PICOPIX_ENABLE_TI = 0x18,
177 AM7XXX_PACKET_TYPE_PICOPIX_DISABLE_TI = 0x19,
178 } am7xxx_packet_type;
180 struct am7xxx_generic_header {
187 struct am7xxx_devinfo_header {
188 uint32_t native_width;
189 uint32_t native_height;
194 struct am7xxx_image_header {
201 struct am7xxx_power_header {
207 struct am7xxx_zoom_header {
223 #define AM7XXX_DIRECTION_OUT 0
224 #define AM7XXX_DIRECTION_IN 1
226 struct am7xxx_header {
227 uint32_t packet_type;
229 uint8_t header_data_len;
233 struct am7xxx_generic_header data;
234 struct am7xxx_devinfo_header devinfo;
235 struct am7xxx_image_header image;
236 struct am7xxx_power_header power;
237 struct am7xxx_zoom_header zoom;
243 static void debug_dump_generic_header(
am7xxx_context *ctx,
struct am7xxx_generic_header *g)
245 if (ctx == NULL || g == NULL)
248 debug(ctx,
"Generic header:\n");
249 debug(ctx,
"\tfield0: 0x%08x (%u)\n", g->field0, g->field0);
250 debug(ctx,
"\tfield1: 0x%08x (%u)\n", g->field1, g->field1);
251 debug(ctx,
"\tfield2: 0x%08x (%u)\n", g->field2, g->field2);
252 debug(ctx,
"\tfield3: 0x%08x (%u)\n", g->field3, g->field3);
255 static void debug_dump_devinfo_header(
am7xxx_context *ctx,
struct am7xxx_devinfo_header *d)
257 if (ctx == NULL || d == NULL)
260 debug(ctx,
"Info header:\n");
261 debug(ctx,
"\tnative_width: 0x%08x (%u)\n", d->native_width, d->native_width);
262 debug(ctx,
"\tnative_height: 0x%08x (%u)\n", d->native_height, d->native_height);
263 debug(ctx,
"\tunknown0: 0x%08x (%u)\n", d->unknown0, d->unknown0);
264 debug(ctx,
"\tunknown1: 0x%08x (%u)\n", d->unknown1, d->unknown1);
267 static void debug_dump_image_header(
am7xxx_context *ctx,
struct am7xxx_image_header *i)
269 if (ctx == NULL || i == NULL)
272 debug(ctx,
"Image header:\n");
273 debug(ctx,
"\tformat: 0x%08x (%u)\n", i->format, i->format);
274 debug(ctx,
"\twidth: 0x%08x (%u)\n", i->width, i->width);
275 debug(ctx,
"\theight: 0x%08x (%u)\n", i->height, i->height);
276 debug(ctx,
"\timage size: 0x%08x (%u)\n", i->image_size, i->image_size);
279 static void debug_dump_power_header(
am7xxx_context *ctx,
struct am7xxx_power_header *p)
281 if (ctx == NULL || p == NULL)
284 debug(ctx,
"Power header:\n");
285 debug(ctx,
"\tbit2: 0x%08x (%u)\n", p->bit2, p->bit2);
286 debug(ctx,
"\tbit1: 0x%08x (%u)\n", p->bit1, p->bit1);
287 debug(ctx,
"\tbit0: 0x%08x (%u)\n", p->bit0, p->bit0);
290 static void debug_dump_zoom_header(
am7xxx_context *ctx,
struct am7xxx_zoom_header *z)
292 if (ctx == NULL || z == NULL)
295 debug(ctx,
"Zoom header:\n");
296 debug(ctx,
"\tbit1: 0x%08x (%u)\n", z->bit1, z->bit1);
297 debug(ctx,
"\tbit0: 0x%08x (%u)\n", z->bit0, z->bit0);
300 static void debug_dump_header(
am7xxx_context *ctx,
struct am7xxx_header *h)
302 if (ctx == NULL || h == NULL)
305 debug(ctx,
"BEGIN\n");
306 debug(ctx,
"packet_type: 0x%08x (%u)\n", h->packet_type, h->packet_type);
307 debug(ctx,
"direction: 0x%02hhx (%hhu) (%s)\n", h->direction, h->direction,
308 h->direction == AM7XXX_DIRECTION_IN ?
"IN" :
309 h->direction == AM7XXX_DIRECTION_OUT ?
"OUT" :
311 debug(ctx,
"header_data_len: 0x%02hhx (%hhu)\n", h->header_data_len, h->header_data_len);
312 debug(ctx,
"unknown2: 0x%02hhx (%hhu)\n", h->unknown2, h->unknown2);
313 debug(ctx,
"unknown3: 0x%02hhx (%hhu)\n", h->unknown3, h->unknown3);
315 switch(h->packet_type) {
316 case AM7XXX_PACKET_TYPE_DEVINFO:
317 debug_dump_devinfo_header(ctx, &(h->header_data.devinfo));
320 case AM7XXX_PACKET_TYPE_IMAGE:
321 debug_dump_image_header(ctx, &(h->header_data.image));
324 case AM7XXX_PACKET_TYPE_POWER:
325 debug_dump_power_header(ctx, &(h->header_data.power));
328 case AM7XXX_PACKET_TYPE_ZOOM:
329 debug_dump_zoom_header(ctx, &(h->header_data.zoom));
333 debug(ctx,
"Parsing data not supported for this packet type!\n");
334 debug_dump_generic_header(ctx, &(h->header_data.data));
337 debug(ctx,
"END\n\n");
340 static inline unsigned int in_80chars(
unsigned int i)
344 return ((i+1) % (80/3));
347 static void trace_dump_buffer(
am7xxx_context *ctx,
const char *message,
348 uint8_t *buffer,
unsigned int len)
352 if (ctx == NULL || buffer == NULL || len == 0)
357 trace(ctx,
"%s\n", message);
359 for (i = 0; i < len; i++) {
360 trace(ctx,
"%02hhX%c", buffer[i], (in_80chars(i) && (i < len - 1)) ?
' ' :
'\n');
365 static void debug_dump_header(
am7xxx_context *ctx,
struct am7xxx_header *h)
371 static void trace_dump_buffer(
am7xxx_context *ctx,
const char *message,
372 uint8_t *buffer,
unsigned int len)
381 static int read_data(
am7xxx_device *dev, uint8_t *buffer,
unsigned int len)
386 ret = libusb_bulk_transfer(dev->usb_device, 0x81, buffer, len, &transferred, 0);
387 if (ret != 0 || (
unsigned int)transferred != len) {
388 error(dev->ctx,
"ret: %d\ttransferred: %d (expected %u)\n",
389 ret, transferred, len);
393 trace_dump_buffer(dev->ctx,
"<-- received", buffer, len);
398 static int send_data(
am7xxx_device *dev, uint8_t *buffer,
unsigned int len)
403 trace_dump_buffer(dev->ctx,
"sending -->", buffer, len);
405 ret = libusb_bulk_transfer(dev->usb_device, 0x1, buffer, len, &transferred, 0);
406 if (ret != 0 || (
unsigned int)transferred != len) {
407 error(dev->ctx,
"ret: %d\ttransferred: %d (expected %u)\n",
408 ret, transferred, len);
415 static void send_data_async_complete_cb(
struct libusb_transfer *transfer)
418 int *completed = &(dev->transfer_completed);
419 int transferred = transfer->actual_length;
422 if (transferred != transfer->length) {
423 error(dev->ctx,
"transferred: %d (expected %u)\n",
424 transferred, transfer->length);
427 switch (transfer->status) {
428 case LIBUSB_TRANSFER_COMPLETED:
431 case LIBUSB_TRANSFER_TIMED_OUT:
432 ret = LIBUSB_ERROR_TIMEOUT;
434 case LIBUSB_TRANSFER_STALL:
435 ret = LIBUSB_ERROR_PIPE;
437 case LIBUSB_TRANSFER_OVERFLOW:
438 ret = LIBUSB_ERROR_OVERFLOW;
440 case LIBUSB_TRANSFER_NO_DEVICE:
441 ret = LIBUSB_ERROR_NO_DEVICE;
443 case LIBUSB_TRANSFER_ERROR:
444 case LIBUSB_TRANSFER_CANCELLED:
445 ret = LIBUSB_ERROR_IO;
448 error(dev->ctx,
"unrecognised status code %d", transfer->status);
449 ret = LIBUSB_ERROR_OTHER;
453 error(dev->ctx,
"libusb transfer failed: %s",
454 libusb_error_name(ret));
456 libusb_free_transfer(transfer);
462 static inline void wait_for_trasfer_completed(
am7xxx_device *dev)
464 while (!dev->transfer_completed) {
465 int ret = libusb_handle_events_completed(dev->ctx->usb_context,
466 &(dev->transfer_completed));
468 if (ret == LIBUSB_ERROR_INTERRUPTED)
470 error(dev->ctx,
"libusb_handle_events failed: %s, cancelling transfer and retrying",
471 libusb_error_name(ret));
472 libusb_cancel_transfer(dev->transfer);
478 static int send_data_async(
am7xxx_device *dev, uint8_t *buffer,
unsigned int len)
481 uint8_t *transfer_buffer;
483 dev->transfer = libusb_alloc_transfer(0);
484 if (dev->transfer == NULL) {
485 error(dev->ctx,
"cannot allocate transfer (%s)\n",
494 transfer_buffer = malloc(len);
495 if (transfer_buffer == NULL) {
496 error(dev->ctx,
"cannot allocate transfer buffer (%s)\n",
501 memcpy(transfer_buffer, buffer, len);
503 dev->transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
504 libusb_fill_bulk_transfer(dev->transfer, dev->usb_device, 0x1,
505 transfer_buffer, len,
506 send_data_async_complete_cb, dev, 0);
509 wait_for_trasfer_completed(dev);
511 trace_dump_buffer(dev->ctx,
"sending -->", buffer, len);
513 dev->transfer_completed = 0;
514 ret = libusb_submit_transfer(dev->transfer);
521 libusb_free_transfer(dev->transfer);
522 dev->transfer = NULL;
526 static void serialize_header(
struct am7xxx_header *h, uint8_t *buffer)
528 uint8_t **buffer_iterator = &buffer;
530 put_le32(h->packet_type, buffer_iterator);
531 put_8(h->direction, buffer_iterator);
532 put_8(h->header_data_len, buffer_iterator);
533 put_8(h->unknown2, buffer_iterator);
534 put_8(h->unknown3, buffer_iterator);
535 put_le32(h->header_data.data.field0, buffer_iterator);
536 put_le32(h->header_data.data.field1, buffer_iterator);
537 put_le32(h->header_data.data.field2, buffer_iterator);
538 put_le32(h->header_data.data.field3, buffer_iterator);
541 static void unserialize_header(uint8_t *buffer,
struct am7xxx_header *h)
543 uint8_t **buffer_iterator = &buffer;
545 h->packet_type = get_le32(buffer_iterator);
546 h->direction = get_8(buffer_iterator);
547 h->header_data_len = get_8(buffer_iterator);
548 h->unknown2 = get_8(buffer_iterator);
549 h->unknown3 = get_8(buffer_iterator);
550 h->header_data.data.field0 = get_le32(buffer_iterator);
551 h->header_data.data.field1 = get_le32(buffer_iterator);
552 h->header_data.data.field2 = get_le32(buffer_iterator);
553 h->header_data.data.field3 = get_le32(buffer_iterator);
556 static int read_header(
am7xxx_device *dev,
struct am7xxx_header *h)
560 ret = read_data(dev, dev->buffer, AM7XXX_HEADER_WIRE_SIZE);
564 unserialize_header(dev->buffer, h);
566 if (h->direction == AM7XXX_DIRECTION_IN) {
570 "Expected an AM7XXX_DIRECTION_IN packet, got one with direction = %d. Weird!\n",
575 debug_dump_header(dev->ctx, h);
581 static int send_header(
am7xxx_device *dev,
struct am7xxx_header *h)
585 debug_dump_header(dev->ctx, h);
592 serialize_header(h, dev->buffer);
594 ret = send_data(dev, dev->buffer, AM7XXX_HEADER_WIRE_SIZE);
596 error(dev->ctx,
"failed to send data\n");
601 static int send_command(
am7xxx_device *dev, am7xxx_packet_type type)
603 struct am7xxx_header h = {
605 .direction = AM7XXX_DIRECTION_OUT,
606 .header_data_len = 0x00,
619 return send_header(dev, &h);
629 const char *
function,
638 fprintf(stderr,
"%s",
function);
640 fprintf(stderr,
"[%d]", line);
641 fprintf(stderr,
": ");
645 vfprintf(stderr, fmt, ap);
653 const struct am7xxx_usb_device_descriptor *desc)
659 fatal(
"context must not be NULL!\n");
663 new_device = malloc(
sizeof(*new_device));
664 if (new_device == NULL) {
665 fatal(
"cannot allocate a new device (%s)\n", strerror(errno));
668 memset(new_device, 0,
sizeof(*new_device));
670 new_device->ctx = ctx;
671 new_device->desc = desc;
672 new_device->transfer_completed = 1;
674 devices_list = &(ctx->devices_list);
676 if (*devices_list == NULL) {
677 *devices_list = new_device;
682 prev->next = new_device;
688 unsigned int device_index)
694 fatal(
"context must not be NULL!\n");
698 current = ctx->devices_list;
699 while (current && i++ < device_index)
700 current = current->next;
706 SCAN_OP_BUILD_DEVLIST,
731 libusb_device** list;
732 unsigned int current_index;
737 fatal(
"context must not be NULL!\n");
740 if (op == SCAN_OP_BUILD_DEVLIST && ctx->devices_list != NULL) {
741 error(ctx,
"device scan done already? Abort!\n");
745 num_devices = libusb_get_device_list(ctx->usb_context, &list);
746 if (num_devices < 0) {
752 for (i = 0; i < num_devices; i++) {
753 struct libusb_device_descriptor desc;
756 ret = libusb_get_device_descriptor(list[i], &desc);
760 for (j = 0; j < ARRAY_SIZE(supported_devices); j++) {
761 if (desc.idVendor == supported_devices[j].vendor_id &&
762 desc.idProduct == supported_devices[j].product_id) {
764 if (op == SCAN_OP_BUILD_DEVLIST) {
766 info(ctx,
"am7xxx device found, index: %d, name: %s\n",
768 supported_devices[j].name);
769 new_device = add_new_device(ctx, &supported_devices[j]);
770 if (new_device == NULL) {
776 debug(ctx,
"Cannot create a new device\n");
780 }
else if (op == SCAN_OP_OPEN_DEVICE &&
781 current_index == open_device_index) {
783 *dev = find_device(ctx, open_device_index);
790 if ((*dev)->usb_device) {
791 debug(ctx,
"(*dev)->usb_device already set\n");
796 ret = libusb_open(list[i], &((*dev)->usb_device));
798 debug(ctx,
"libusb_open failed\n");
807 ret = libusb_set_configuration((*dev)->usb_device,
808 (*dev)->desc->configuration);
810 debug(ctx,
"libusb_set_configuration failed\n");
811 debug(ctx,
"Cannot set configuration %hhu\n",
812 (*dev)->desc->configuration);
813 goto out_libusb_close;
816 ret = libusb_claim_interface((*dev)->usb_device,
817 (*dev)->desc->interface_number);
819 debug(ctx,
"libusb_claim_interface failed\n");
820 debug(ctx,
"Cannot claim interface %hhu\n",
821 (*dev)->desc->interface_number);
823 libusb_close((*dev)->usb_device);
824 (*dev)->usb_device = NULL;
836 if (op == SCAN_OP_OPEN_DEVICE) {
837 error(ctx,
"Cannot find any device to open\n");
845 libusb_free_device_list(list, 1);
854 struct am7xxx_header h = {
855 .packet_type = AM7XXX_PACKET_TYPE_POWER,
856 .direction = AM7XXX_DIRECTION_OUT,
857 .header_data_len =
sizeof(
struct am7xxx_power_header),
864 h.header_data.power.bit2 = 0;
865 h.header_data.power.bit1 = 0;
866 h.header_data.power.bit0 = 0;
870 h.header_data.power.bit2 = 0;
871 h.header_data.power.bit1 = 0;
872 h.header_data.power.bit0 = 1;
876 h.header_data.power.bit2 = 0;
877 h.header_data.power.bit1 = 1;
878 h.header_data.power.bit0 = 0;
882 h.header_data.power.bit2 = 0;
883 h.header_data.power.bit1 = 1;
884 h.header_data.power.bit0 = 1;
888 h.header_data.power.bit2 = 1;
889 h.header_data.power.bit1 = 0;
890 h.header_data.power.bit0 = 0;
894 error(dev->ctx,
"Unsupported power mode.\n");
898 ret = send_header(dev, &h);
909 return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_LOW);
912 return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_MEDIUM);
915 return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_HIGH);
920 error(dev->ctx,
"Unsupported power mode.\n");
928 struct am7xxx_header h = {
929 .packet_type = AM7XXX_PACKET_TYPE_ZOOM,
930 .direction = AM7XXX_DIRECTION_OUT,
931 .header_data_len =
sizeof(
struct am7xxx_zoom_header),
938 h.header_data.zoom.bit1 = 0;
939 h.header_data.zoom.bit0 = 0;
943 h.header_data.zoom.bit1 = 0;
944 h.header_data.zoom.bit0 = 1;
948 h.header_data.zoom.bit1 = 1;
949 h.header_data.zoom.bit0 = 0;
953 h.header_data.zoom.bit1 = 1;
954 h.header_data.zoom.bit0 = 1;
959 error(dev->ctx,
"Unsupported zoom mode.\n");
963 ret = send_header(dev, &h);
973 am7xxx_packet_type packet_type;
977 packet_type = AM7XXX_PACKET_TYPE_PICOPIX_DISABLE_TI;
981 packet_type = AM7XXX_PACKET_TYPE_PICOPIX_ENABLE_TI;
988 error(dev->ctx,
"Unsupported zoom mode.\n");
992 ret = send_command(dev, packet_type);
1002 return send_command(dev, packet_type);
1011 *ctx = malloc(
sizeof(**ctx));
1013 fatal(
"cannot allocate the context (%s)\n", strerror(errno));
1017 memset(*ctx, 0,
sizeof(**ctx));
1022 ret = libusb_init(&((*ctx)->usb_context));
1024 goto out_free_context;
1026 libusb_set_debug((*ctx)->usb_context, LIBUSB_LOG_LEVEL_INFO);
1028 ret = scan_devices(*ctx, SCAN_OP_BUILD_DEVLIST , 0, NULL);
1030 error(*ctx,
"scan_devices() failed\n");
1051 fatal(
"context must not be NULL!\n");
1055 current = ctx->devices_list;
1059 free(current->device_info);
1064 libusb_exit(ctx->usb_context);
1071 ctx->log_level = log_level;
1075 unsigned int device_index)
1080 fatal(
"context must not be NULL!\n");
1084 ret = scan_devices(ctx, SCAN_OP_OPEN_DEVICE, device_index, dev);
1088 }
else if (ret > 0) {
1089 warning(ctx,
"device %d already open\n", device_index);
1102 if ((*dev)->device_info == NULL) {
1105 error(ctx,
"cannot get device info\n");
1115 fatal(
"dev must not be NULL!\n");
1118 if (dev->usb_device) {
1119 wait_for_trasfer_completed(dev);
1120 libusb_release_interface(dev->usb_device, dev->desc->interface_number);
1121 libusb_close(dev->usb_device);
1122 dev->usb_device = NULL;
1131 struct am7xxx_header h;
1133 if (dev->device_info) {
1134 memcpy(device_info, dev->device_info,
sizeof(*device_info));
1138 ret = send_command(dev, AM7XXX_PACKET_TYPE_DEVINFO);
1142 memset(&h, 0,
sizeof(h));
1143 ret = read_header(dev, &h);
1147 if (h.packet_type != AM7XXX_PACKET_TYPE_DEVINFO) {
1148 error(dev->ctx,
"expected packet type: %d, got %d instead!\n",
1149 AM7XXX_PACKET_TYPE_DEVINFO, h.packet_type);
1154 dev->device_info = malloc(
sizeof(*dev->device_info));
1155 if (dev->device_info == NULL) {
1156 error(dev->ctx,
"cannot allocate a device info (%s)\n",
1160 memset(dev->device_info, 0,
sizeof(*dev->device_info));
1162 dev->device_info->native_width = h.header_data.devinfo.native_width;
1163 dev->device_info->native_height = h.header_data.devinfo.native_height;
1166 dev->device_info->unknown0 = h.header_data.devinfo.unknown0;
1167 dev->device_info->unknown1 = h.header_data.devinfo.unknown1;
1174 unsigned int upscale,
1175 unsigned int original_width,
1176 unsigned int original_height,
1177 unsigned int *scaled_width,
1178 unsigned int *scaled_height)
1188 error(dev->ctx,
"cannot get device info\n");
1199 debug(dev->ctx,
"CASE 0, no rescaling, the original image fits already\n");
1200 *scaled_width = original_width;
1201 *scaled_height = original_height;
1206 width_ratio = (float)original_width / device_info.
native_width;
1207 height_ratio = (
float)original_height / device_info.
native_height;
1209 if (width_ratio > height_ratio) {
1214 debug(dev->ctx,
"CASE 1, original image wider, adjust the scaled height\n");
1216 *scaled_height = (
unsigned int)lroundf(original_height / width_ratio);
1217 }
else if (width_ratio < height_ratio) {
1222 debug(dev->ctx,
"CASE 2 original image taller, adjust the scaled width\n");
1223 *scaled_width = (
unsigned int)lroundf(original_width / height_ratio);
1226 debug(dev->ctx,
"CASE 3, just rescale, same aspect ratio already\n");
1230 debug(dev->ctx,
"scaled dimensions: %dx%d\n", *scaled_width, *scaled_height);
1238 unsigned int height,
1240 unsigned int image_size)
1243 struct am7xxx_header h = {
1244 .packet_type = AM7XXX_PACKET_TYPE_IMAGE,
1245 .direction = AM7XXX_DIRECTION_OUT,
1246 .header_data_len =
sizeof(
struct am7xxx_image_header),
1254 .image_size = image_size,
1259 ret = send_header(dev, &h);
1263 if (image == NULL || image_size == 0) {
1264 warning(dev->ctx,
"Not sending any data, check the 'image' or 'image_size' parameters\n");
1268 return send_data(dev, image, image_size);
1274 unsigned int height,
1276 unsigned int image_size)
1279 struct am7xxx_header h = {
1280 .packet_type = AM7XXX_PACKET_TYPE_IMAGE,
1281 .direction = AM7XXX_DIRECTION_OUT,
1282 .header_data_len =
sizeof(
struct am7xxx_image_header),
1290 .image_size = image_size,
1295 ret = send_header(dev, &h);
1299 if (image == NULL || image_size == 0) {
1300 warning(dev->ctx,
"Not sending any data, check the 'image' or 'image_size' parameters\n");
1304 return send_data_async(dev, image, image_size);
1309 if (dev->desc->ops.set_power_mode == NULL) {
1311 "setting power mode is unsupported on this device\n");
1315 return dev->desc->ops.set_power_mode(dev, power);
1320 if (dev->desc->ops.set_zoom_mode == NULL) {
1322 "setting zoom mode is unsupported on this device\n");
1326 return dev->desc->ops.set_zoom_mode(dev, zoom);
Zoom test screen, the firmware version is shown as well.
Zoom 1: H Scale (changes aspect ratio).
struct _am7xxx_context am7xxx_context
An opaque data type representing a context.
Zoom Tele: available on some PicoPix models.
A struct describing device specific properties.
int am7xxx_init(am7xxx_context **ctx)
Initialize the library context and data structures, and scan for devices.
Original Size, as retrieved via am7xxx_device_info.
Max brightness and power consumption.
Middle level of brightness.
am7xxx_image_format
The image formats accepted by the device.
am7xxx_power_mode
The device power modes.
int am7xxx_open_device(am7xxx_context *ctx, am7xxx_device **dev, unsigned int device_index)
Open an am7xxx_device according to a index.
Zoom 2: H/V Scale (changes aspect ratio).
More brightness, but more power consumption.
Error messages, typically they describe API functions failures.
int am7xxx_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power)
Set the power mode of an am7xxx device.
void am7xxx_set_log_level(am7xxx_context *ctx, am7xxx_log_level log_level)
Set verbosity level of log messages.
int am7xxx_get_device_info(am7xxx_device *dev, am7xxx_device_info *device_info)
Get info about an am7xxx device.
int am7xxx_calc_scaled_image_dimensions(am7xxx_device *dev, unsigned int upscale, unsigned int original_width, unsigned int original_height, unsigned int *scaled_width, unsigned int *scaled_height)
Calculate the dimensions of an image to be shown on an am7xxx device.
unsigned int native_width
The device native width.
int am7xxx_send_image_async(am7xxx_device *dev, am7xxx_image_format format, unsigned int width, unsigned int height, unsigned char *image, unsigned int image_size)
Queue transfer of an image for display on an am7xxx device and return immediately.
am7xxx_zoom_mode
The display zoom modes.
int am7xxx_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom)
Set the zoom mode of an am7xxx device.
Fatal messages, the user application should stop if it gets one of this.
Verbose informations about the communication with the hardware.
Low power consumption but also low brightness.
int am7xxx_send_image(am7xxx_device *dev, am7xxx_image_format format, unsigned int width, unsigned int height, unsigned char *image, unsigned int image_size)
Send an image for display on an am7xxx device.
unsigned int native_height
The device native height.
void am7xxx_shutdown(am7xxx_context *ctx)
Cleanup the library data structures and free the context.
am7xxx_log_level
The verbosity level of logging messages.
int am7xxx_close_device(am7xxx_device *dev)
Close an am7xxx_device.
struct _am7xxx_device am7xxx_device
An opaque data type representing an am7xxx device.
Display is powered off, no image shown.