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"))) 56 const char *function_name,
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)
387 ret = libusb_bulk_transfer(dev->usb_device, 0x81, buffer, len, &transferred, 0);
388 if (ret != 0 || (
unsigned int)transferred != len) {
389 error(dev->ctx,
"%s. Transferred: %d (expected %u)\n",
390 libusb_error_name(ret), transferred, len);
394 trace_dump_buffer(dev->ctx,
"<-- received", buffer, len);
399 static int send_data(
am7xxx_device *dev, uint8_t *buffer,
unsigned int len)
404 trace_dump_buffer(dev->ctx,
"sending -->", buffer, len);
407 ret = libusb_bulk_transfer(dev->usb_device, 0x1, buffer, len, &transferred, 0);
408 if (ret != 0 || (
unsigned int)transferred != len) {
409 error(dev->ctx,
"%s. Transferred: %d (expected %u)\n",
410 libusb_error_name(ret), transferred, len);
417 static void send_data_async_complete_cb(
struct libusb_transfer *transfer)
420 int *completed = &(dev->transfer_completed);
421 int transferred = transfer->actual_length;
424 if (transferred != transfer->length) {
425 error(dev->ctx,
"transferred: %d (expected %u)\n",
426 transferred, transfer->length);
429 switch (transfer->status) {
430 case LIBUSB_TRANSFER_COMPLETED:
433 case LIBUSB_TRANSFER_TIMED_OUT:
434 ret = LIBUSB_ERROR_TIMEOUT;
436 case LIBUSB_TRANSFER_STALL:
437 ret = LIBUSB_ERROR_PIPE;
439 case LIBUSB_TRANSFER_OVERFLOW:
440 ret = LIBUSB_ERROR_OVERFLOW;
442 case LIBUSB_TRANSFER_NO_DEVICE:
443 ret = LIBUSB_ERROR_NO_DEVICE;
445 case LIBUSB_TRANSFER_ERROR:
446 case LIBUSB_TRANSFER_CANCELLED:
447 ret = LIBUSB_ERROR_IO;
450 error(dev->ctx,
"unrecognised status code %d", transfer->status);
451 ret = LIBUSB_ERROR_OTHER;
455 error(dev->ctx,
"libusb transfer failed: %s",
456 libusb_error_name(ret));
458 libusb_free_transfer(transfer);
464 static inline void wait_for_trasfer_completed(
am7xxx_device *dev)
466 while (!dev->transfer_completed) {
467 int ret = libusb_handle_events_completed(dev->ctx->usb_context,
468 &(dev->transfer_completed));
470 if (ret == LIBUSB_ERROR_INTERRUPTED)
472 error(dev->ctx,
"libusb_handle_events failed: %s, cancelling transfer and retrying",
473 libusb_error_name(ret));
474 libusb_cancel_transfer(dev->transfer);
480 static int send_data_async(
am7xxx_device *dev, uint8_t *buffer,
unsigned int len)
483 uint8_t *transfer_buffer;
485 dev->transfer = libusb_alloc_transfer(0);
486 if (dev->transfer == NULL) {
487 error(dev->ctx,
"cannot allocate transfer (%s)\n",
496 transfer_buffer = malloc(len);
497 if (transfer_buffer == NULL) {
498 error(dev->ctx,
"cannot allocate transfer buffer (%s)\n",
503 memcpy(transfer_buffer, buffer, len);
505 dev->transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
506 libusb_fill_bulk_transfer(dev->transfer, dev->usb_device, 0x1,
507 transfer_buffer, len,
508 send_data_async_complete_cb, dev, 0);
511 wait_for_trasfer_completed(dev);
513 trace_dump_buffer(dev->ctx,
"sending -->", buffer, len);
515 dev->transfer_completed = 0;
516 ret = libusb_submit_transfer(dev->transfer);
523 libusb_free_transfer(dev->transfer);
524 dev->transfer = NULL;
528 static void serialize_header(
struct am7xxx_header *h, uint8_t *buffer)
530 uint8_t **buffer_iterator = &buffer;
532 put_le32(h->packet_type, buffer_iterator);
533 put_8(h->direction, buffer_iterator);
534 put_8(h->header_data_len, buffer_iterator);
535 put_8(h->unknown2, buffer_iterator);
536 put_8(h->unknown3, buffer_iterator);
537 put_le32(h->header_data.data.field0, buffer_iterator);
538 put_le32(h->header_data.data.field1, buffer_iterator);
539 put_le32(h->header_data.data.field2, buffer_iterator);
540 put_le32(h->header_data.data.field3, buffer_iterator);
543 static void unserialize_header(uint8_t *buffer,
struct am7xxx_header *h)
545 uint8_t **buffer_iterator = &buffer;
547 h->packet_type = get_le32(buffer_iterator);
548 h->direction = get_8(buffer_iterator);
549 h->header_data_len = get_8(buffer_iterator);
550 h->unknown2 = get_8(buffer_iterator);
551 h->unknown3 = get_8(buffer_iterator);
552 h->header_data.data.field0 = get_le32(buffer_iterator);
553 h->header_data.data.field1 = get_le32(buffer_iterator);
554 h->header_data.data.field2 = get_le32(buffer_iterator);
555 h->header_data.data.field3 = get_le32(buffer_iterator);
558 static int read_header(
am7xxx_device *dev,
struct am7xxx_header *h)
562 ret = read_data(dev, dev->buffer, AM7XXX_HEADER_WIRE_SIZE);
566 unserialize_header(dev->buffer, h);
568 if (h->direction == AM7XXX_DIRECTION_IN) {
572 "Expected an AM7XXX_DIRECTION_IN packet, got one with direction = %d. Weird!\n",
577 debug_dump_header(dev->ctx, h);
583 static int send_header(
am7xxx_device *dev,
struct am7xxx_header *h)
587 debug_dump_header(dev->ctx, h);
594 serialize_header(h, dev->buffer);
596 ret = send_data(dev, dev->buffer, AM7XXX_HEADER_WIRE_SIZE);
598 error(dev->ctx,
"failed to send data\n");
603 static int send_command(
am7xxx_device *dev, am7xxx_packet_type type)
605 struct am7xxx_header h = {
607 .direction = AM7XXX_DIRECTION_OUT,
608 .header_data_len = 0x00,
621 return send_header(dev, &h);
631 const char *function_name,
640 fprintf(stderr,
"%s", function_name);
642 fprintf(stderr,
"[%d]", line);
643 fprintf(stderr,
": ");
647 vfprintf(stderr, fmt, ap);
655 const struct am7xxx_usb_device_descriptor *desc)
661 fatal(
"context must not be NULL!\n");
665 new_device = malloc(
sizeof(*new_device));
666 if (new_device == NULL) {
667 debug(ctx,
"cannot allocate a new device (%s)\n", strerror(errno));
670 memset(new_device, 0,
sizeof(*new_device));
672 new_device->ctx = ctx;
673 new_device->desc = desc;
674 new_device->transfer_completed = 1;
676 devices_list = &(ctx->devices_list);
678 if (*devices_list == NULL) {
679 *devices_list = new_device;
684 prev->next = new_device;
690 unsigned int device_index)
696 fatal(
"context must not be NULL!\n");
700 current = ctx->devices_list;
701 while (current && i++ < device_index)
702 current = current->next;
708 unsigned int device_index,
709 libusb_device *usb_dev,
713 int current_configuration;
715 *dev = find_device(ctx, device_index);
722 if ((*dev)->usb_device) {
727 ret = libusb_open(usb_dev, &((*dev)->usb_device));
729 debug(ctx,
"libusb_open failed: %s\n", libusb_error_name(ret));
737 current_configuration = -1;
738 ret = libusb_get_configuration((*dev)->usb_device,
739 ¤t_configuration);
741 debug(ctx,
"libusb_get_configuration failed: %s\n",
742 libusb_error_name(ret));
743 goto out_libusb_close;
746 if (current_configuration != (*dev)->desc->configuration) {
767 ret = libusb_set_configuration((*dev)->usb_device,
768 (*dev)->desc->configuration);
770 debug(ctx,
"libusb_set_configuration failed: %s\n",
771 libusb_error_name(ret));
772 debug(ctx,
"Cannot set configuration %hhu\n",
773 (*dev)->desc->configuration);
774 goto out_libusb_close;
778 libusb_set_auto_detach_kernel_driver((*dev)->usb_device, 1);
780 ret = libusb_claim_interface((*dev)->usb_device,
781 (*dev)->desc->interface_number);
783 debug(ctx,
"libusb_claim_interface failed: %s\n",
784 libusb_error_name(ret));
785 debug(ctx,
"Cannot claim interface %hhu\n",
786 (*dev)->desc->interface_number);
787 goto out_libusb_close;
793 current_configuration = -1;
794 ret = libusb_get_configuration((*dev)->usb_device,
795 ¤t_configuration);
797 debug(ctx,
"libusb_get_configuration after claim failed: %s\n",
798 libusb_error_name(ret));
799 goto out_libusb_release_interface;
802 if (current_configuration != (*dev)->desc->configuration) {
803 debug(ctx,
"libusb configuration changed (expected: %hhu, current: %d\n",
804 (*dev)->desc->configuration, current_configuration);
806 goto out_libusb_release_interface;
811 out_libusb_release_interface:
812 libusb_release_interface((*dev)->usb_device,
813 (*dev)->desc->interface_number);
815 libusb_close((*dev)->usb_device);
816 (*dev)->usb_device = NULL;
821 SCAN_OP_BUILD_DEVLIST,
847 libusb_device **list;
848 unsigned int current_index;
853 fatal(
"context must not be NULL!\n");
856 if (op == SCAN_OP_BUILD_DEVLIST && ctx->devices_list != NULL) {
857 error(ctx,
"device scan done already? Abort!\n");
861 num_devices = libusb_get_device_list(ctx->usb_context, &list);
862 if (num_devices < 0) {
868 for (i = 0; i < num_devices; i++) {
869 struct libusb_device_descriptor desc;
872 ret = libusb_get_device_descriptor(list[i], &desc);
876 for (j = 0; j < ARRAY_SIZE(supported_devices); j++) {
877 if (desc.idVendor == supported_devices[j].vendor_id &&
878 desc.idProduct == supported_devices[j].product_id) {
880 if (op == SCAN_OP_BUILD_DEVLIST) {
882 info(ctx,
"am7xxx device found, index: %d, name: %s\n",
884 supported_devices[j].name);
885 new_device = add_new_device(ctx, &supported_devices[j]);
886 if (new_device == NULL) {
892 debug(ctx,
"Cannot create a new device\n");
896 }
else if (op == SCAN_OP_OPEN_DEVICE &&
897 current_index == open_device_index) {
899 ret = open_device(ctx,
904 debug(ctx,
"open_device failed\n");
918 if (op == SCAN_OP_OPEN_DEVICE) {
919 error(ctx,
"Cannot find any device to open\n");
927 libusb_free_device_list(list, 1);
936 struct am7xxx_header h = {
937 .packet_type = AM7XXX_PACKET_TYPE_POWER,
938 .direction = AM7XXX_DIRECTION_OUT,
939 .header_data_len =
sizeof(
struct am7xxx_power_header),
946 h.header_data.power.bit2 = 0;
947 h.header_data.power.bit1 = 0;
948 h.header_data.power.bit0 = 0;
952 h.header_data.power.bit2 = 0;
953 h.header_data.power.bit1 = 0;
954 h.header_data.power.bit0 = 1;
958 h.header_data.power.bit2 = 0;
959 h.header_data.power.bit1 = 1;
960 h.header_data.power.bit0 = 0;
964 h.header_data.power.bit2 = 0;
965 h.header_data.power.bit1 = 1;
966 h.header_data.power.bit0 = 1;
970 h.header_data.power.bit2 = 1;
971 h.header_data.power.bit1 = 0;
972 h.header_data.power.bit0 = 0;
976 error(dev->ctx,
"Unsupported power mode.\n");
980 ret = send_header(dev, &h);
991 return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_LOW);
994 return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_MEDIUM);
997 return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_HIGH);
1002 error(dev->ctx,
"Unsupported power mode.\n");
1010 struct am7xxx_header h = {
1011 .packet_type = AM7XXX_PACKET_TYPE_ZOOM,
1012 .direction = AM7XXX_DIRECTION_OUT,
1013 .header_data_len =
sizeof(
struct am7xxx_zoom_header),
1020 h.header_data.zoom.bit1 = 0;
1021 h.header_data.zoom.bit0 = 0;
1025 h.header_data.zoom.bit1 = 0;
1026 h.header_data.zoom.bit0 = 1;
1030 h.header_data.zoom.bit1 = 1;
1031 h.header_data.zoom.bit0 = 0;
1035 h.header_data.zoom.bit1 = 1;
1036 h.header_data.zoom.bit0 = 1;
1041 error(dev->ctx,
"Unsupported zoom mode.\n");
1045 ret = send_header(dev, &h);
1055 am7xxx_packet_type packet_type;
1059 packet_type = AM7XXX_PACKET_TYPE_PICOPIX_DISABLE_TI;
1063 packet_type = AM7XXX_PACKET_TYPE_PICOPIX_ENABLE_TI;
1070 error(dev->ctx,
"Unsupported zoom mode.\n");
1074 ret = send_command(dev, packet_type);
1084 return send_command(dev, packet_type);
1093 *ctx = malloc(
sizeof(**ctx));
1095 fatal(
"cannot allocate the context (%s)\n", strerror(errno));
1099 memset(*ctx, 0,
sizeof(**ctx));
1104 ret = libusb_init(&((*ctx)->usb_context));
1106 error(*ctx,
"libusb_init failed: %s\n", libusb_error_name(ret));
1107 goto out_free_context;
1110 libusb_set_debug((*ctx)->usb_context, LIBUSB_LOG_LEVEL_INFO);
1112 ret = scan_devices(*ctx, SCAN_OP_BUILD_DEVLIST , 0, NULL);
1114 error(*ctx,
"scan_devices() failed\n");
1135 fatal(
"context must not be NULL!\n");
1139 current = ctx->devices_list;
1143 free(current->device_info);
1148 libusb_exit(ctx->usb_context);
1155 ctx->log_level = log_level;
1159 unsigned int device_index)
1164 fatal(
"context must not be NULL!\n");
1168 ret = scan_devices(ctx, SCAN_OP_OPEN_DEVICE, device_index, dev);
1172 }
else if (ret > 0) {
1173 warning(ctx,
"device %d already open\n", device_index);
1186 if ((*dev)->device_info == NULL) {
1189 error(ctx,
"cannot get device info\n");
1199 fatal(
"dev must not be NULL!\n");
1202 if (dev->usb_device) {
1203 wait_for_trasfer_completed(dev);
1204 libusb_release_interface(dev->usb_device, dev->desc->interface_number);
1205 libusb_close(dev->usb_device);
1206 dev->usb_device = NULL;
1215 struct am7xxx_header h;
1217 if (dev->device_info) {
1218 memcpy(device_info, dev->device_info,
sizeof(*device_info));
1222 ret = send_command(dev, AM7XXX_PACKET_TYPE_DEVINFO);
1226 memset(&h, 0,
sizeof(h));
1227 ret = read_header(dev, &h);
1231 if (h.packet_type != AM7XXX_PACKET_TYPE_DEVINFO) {
1232 error(dev->ctx,
"expected packet type: %d, got %d instead!\n",
1233 AM7XXX_PACKET_TYPE_DEVINFO, h.packet_type);
1238 dev->device_info = malloc(
sizeof(*dev->device_info));
1239 if (dev->device_info == NULL) {
1240 error(dev->ctx,
"cannot allocate a device info (%s)\n",
1244 memset(dev->device_info, 0,
sizeof(*dev->device_info));
1246 dev->device_info->native_width = h.header_data.devinfo.native_width;
1247 dev->device_info->native_height = h.header_data.devinfo.native_height;
1250 dev->device_info->unknown0 = h.header_data.devinfo.unknown0;
1251 dev->device_info->unknown1 = h.header_data.devinfo.unknown1;
1258 unsigned int upscale,
1259 unsigned int original_width,
1260 unsigned int original_height,
1261 unsigned int *scaled_width,
1262 unsigned int *scaled_height)
1272 error(dev->ctx,
"cannot get device info\n");
1283 debug(dev->ctx,
"CASE 0, no rescaling, the original image fits already\n");
1284 *scaled_width = original_width;
1285 *scaled_height = original_height;
1290 width_ratio = (float)original_width / device_info.
native_width;
1291 height_ratio = (
float)original_height / device_info.
native_height;
1293 if (width_ratio > height_ratio) {
1298 debug(dev->ctx,
"CASE 1, original image wider, adjust the scaled height\n");
1300 *scaled_height = (
unsigned int)lroundf(original_height / width_ratio);
1301 }
else if (width_ratio < height_ratio) {
1306 debug(dev->ctx,
"CASE 2 original image taller, adjust the scaled width\n");
1307 *scaled_width = (
unsigned int)lroundf(original_width / height_ratio);
1310 debug(dev->ctx,
"CASE 3, just rescale, same aspect ratio already\n");
1314 debug(dev->ctx,
"scaled dimensions: %dx%d\n", *scaled_width, *scaled_height);
1322 unsigned int height,
1324 unsigned int image_size)
1327 struct am7xxx_header h = {
1328 .packet_type = AM7XXX_PACKET_TYPE_IMAGE,
1329 .direction = AM7XXX_DIRECTION_OUT,
1330 .header_data_len =
sizeof(
struct am7xxx_image_header),
1338 .image_size = image_size,
1343 ret = send_header(dev, &h);
1347 if (image == NULL || image_size == 0) {
1348 warning(dev->ctx,
"Not sending any data, check the 'image' or 'image_size' parameters\n");
1352 return send_data(dev, image, image_size);
1358 unsigned int height,
1360 unsigned int image_size)
1363 struct am7xxx_header h = {
1364 .packet_type = AM7XXX_PACKET_TYPE_IMAGE,
1365 .direction = AM7XXX_DIRECTION_OUT,
1366 .header_data_len =
sizeof(
struct am7xxx_image_header),
1374 .image_size = image_size,
1379 ret = send_header(dev, &h);
1383 if (image == NULL || image_size == 0) {
1384 warning(dev->ctx,
"Not sending any data, check the 'image' or 'image_size' parameters\n");
1388 return send_data_async(dev, image, image_size);
1393 if (dev->desc->ops.set_power_mode == NULL) {
1395 "setting power mode is unsupported on this device\n");
1399 return dev->desc->ops.set_power_mode(dev, power);
1404 if (dev->desc->ops.set_zoom_mode == NULL) {
1406 "setting zoom mode is unsupported on this device\n");
1410 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.