28 #include "serialize.h" 31 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 38 #define __attribute__(x) 45 #ifdef __MINGW_PRINTF_FORMAT 46 #define AM7XXX_PRINTF_FORMAT __MINGW_PRINTF_FORMAT 48 #define AM7XXX_PRINTF_FORMAT printf 52 #if defined _WIN32 || defined __CYGWIN__ 53 #define AM7XXX_PUBLIC __declspec(dllexport) 57 #define AM7XXX_PUBLIC __attribute__ ((visibility ("default"))) 58 #define AM7XXX_LOCAL __attribute__ ((visibility ("hidden"))) 67 const char *function_name,
70 ...) __attribute__ ((format (AM7XXX_PRINTF_FORMAT, 5, 6)));
72 #define fatal(...) log_message(NULL, AM7XXX_LOG_FATAL, __func__, __LINE__, __VA_ARGS__) 73 #define error(ctx, ...) log_message(ctx, AM7XXX_LOG_ERROR, __func__, __LINE__, __VA_ARGS__) 74 #define warning(ctx, ...) log_message(ctx, AM7XXX_LOG_WARNING, __func__, 0, __VA_ARGS__) 75 #define info(ctx, ...) log_message(ctx, AM7XXX_LOG_INFO, __func__, 0, __VA_ARGS__) 76 #define debug(ctx, ...) log_message(ctx, AM7XXX_LOG_DEBUG, __func__, 0, __VA_ARGS__) 77 #define trace(ctx, ...) log_message(ctx, AM7XXX_LOG_TRACE, NULL, 0, __VA_ARGS__) 84 struct am7xxx_usb_device_descriptor {
88 uint8_t configuration;
89 uint8_t interface_number;
90 struct am7xxx_ops ops;
98 #define DEFAULT_OPS { \ 99 .set_power_mode = default_set_power_mode, \ 100 .set_zoom_mode = default_set_zoom_mode, \ 103 static const struct am7xxx_usb_device_descriptor supported_devices[] = {
107 .product_id = 0xc101,
109 .interface_number = 0,
115 .product_id = 0x5501,
117 .interface_number = 0,
121 .name =
"Aiptek PocketCinema T25",
123 .product_id = 0x2144,
125 .interface_number = 0,
129 .name =
"Philips/Sagemcom PicoPix 1020",
131 .product_id = 0x000e,
133 .interface_number = 0,
137 .name =
"Philips/Sagemcom PicoPix 2055",
139 .product_id = 0x0016,
141 .interface_number = 0,
143 .set_power_mode = picopix_set_power_mode,
144 .set_zoom_mode = picopix_set_zoom_mode,
148 .name =
"Philips/Sagemcom PicoPix 2330",
150 .product_id = 0x0019,
152 .interface_number = 0,
160 #define AM7XXX_HEADER_WIRE_SIZE 24 162 struct _am7xxx_device {
163 libusb_device_handle *usb_device;
164 struct libusb_transfer *transfer;
165 int transfer_completed;
166 uint8_t buffer[AM7XXX_HEADER_WIRE_SIZE];
169 const struct am7xxx_usb_device_descriptor *desc;
173 struct _am7xxx_context {
174 libusb_context *usb_context;
180 AM7XXX_PACKET_TYPE_DEVINFO = 0x01,
181 AM7XXX_PACKET_TYPE_IMAGE = 0x02,
182 AM7XXX_PACKET_TYPE_POWER = 0x04,
183 AM7XXX_PACKET_TYPE_ZOOM = 0x05,
184 AM7XXX_PACKET_TYPE_PICOPIX_POWER_LOW = 0x15,
185 AM7XXX_PACKET_TYPE_PICOPIX_POWER_MEDIUM = 0x16,
186 AM7XXX_PACKET_TYPE_PICOPIX_POWER_HIGH = 0x17,
187 AM7XXX_PACKET_TYPE_PICOPIX_ENABLE_TI = 0x18,
188 AM7XXX_PACKET_TYPE_PICOPIX_DISABLE_TI = 0x19,
189 } am7xxx_packet_type;
191 struct am7xxx_generic_header {
198 struct am7xxx_devinfo_header {
199 uint32_t native_width;
200 uint32_t native_height;
205 struct am7xxx_image_header {
212 struct am7xxx_power_header {
218 struct am7xxx_zoom_header {
234 #define AM7XXX_DIRECTION_OUT 0 235 #define AM7XXX_DIRECTION_IN 1 237 struct am7xxx_header {
238 uint32_t packet_type;
240 uint8_t header_data_len;
244 struct am7xxx_generic_header data;
245 struct am7xxx_devinfo_header devinfo;
246 struct am7xxx_image_header image;
247 struct am7xxx_power_header power;
248 struct am7xxx_zoom_header zoom;
254 static void debug_dump_generic_header(
am7xxx_context *ctx,
struct am7xxx_generic_header *g)
256 if (ctx == NULL || g == NULL)
259 debug(ctx,
"Generic header:\n");
260 debug(ctx,
"\tfield0: 0x%08x (%u)\n", g->field0, g->field0);
261 debug(ctx,
"\tfield1: 0x%08x (%u)\n", g->field1, g->field1);
262 debug(ctx,
"\tfield2: 0x%08x (%u)\n", g->field2, g->field2);
263 debug(ctx,
"\tfield3: 0x%08x (%u)\n", g->field3, g->field3);
266 static void debug_dump_devinfo_header(
am7xxx_context *ctx,
struct am7xxx_devinfo_header *d)
268 if (ctx == NULL || d == NULL)
271 debug(ctx,
"Info header:\n");
272 debug(ctx,
"\tnative_width: 0x%08x (%u)\n", d->native_width, d->native_width);
273 debug(ctx,
"\tnative_height: 0x%08x (%u)\n", d->native_height, d->native_height);
274 debug(ctx,
"\tunknown0: 0x%08x (%u)\n", d->unknown0, d->unknown0);
275 debug(ctx,
"\tunknown1: 0x%08x (%u)\n", d->unknown1, d->unknown1);
278 static void debug_dump_image_header(
am7xxx_context *ctx,
struct am7xxx_image_header *i)
280 if (ctx == NULL || i == NULL)
283 debug(ctx,
"Image header:\n");
284 debug(ctx,
"\tformat: 0x%08x (%u)\n", i->format, i->format);
285 debug(ctx,
"\twidth: 0x%08x (%u)\n", i->width, i->width);
286 debug(ctx,
"\theight: 0x%08x (%u)\n", i->height, i->height);
287 debug(ctx,
"\timage size: 0x%08x (%u)\n", i->image_size, i->image_size);
290 static void debug_dump_power_header(
am7xxx_context *ctx,
struct am7xxx_power_header *p)
292 if (ctx == NULL || p == NULL)
295 debug(ctx,
"Power header:\n");
296 debug(ctx,
"\tbit2: 0x%08x (%u)\n", p->bit2, p->bit2);
297 debug(ctx,
"\tbit1: 0x%08x (%u)\n", p->bit1, p->bit1);
298 debug(ctx,
"\tbit0: 0x%08x (%u)\n", p->bit0, p->bit0);
301 static void debug_dump_zoom_header(
am7xxx_context *ctx,
struct am7xxx_zoom_header *z)
303 if (ctx == NULL || z == NULL)
306 debug(ctx,
"Zoom header:\n");
307 debug(ctx,
"\tbit1: 0x%08x (%u)\n", z->bit1, z->bit1);
308 debug(ctx,
"\tbit0: 0x%08x (%u)\n", z->bit0, z->bit0);
311 static void debug_dump_header(
am7xxx_context *ctx,
struct am7xxx_header *h)
313 if (ctx == NULL || h == NULL)
316 debug(ctx,
"BEGIN\n");
317 debug(ctx,
"packet_type: 0x%08x (%u)\n", h->packet_type, h->packet_type);
318 debug(ctx,
"direction: 0x%02hhx (%hhu) (%s)\n", h->direction, h->direction,
319 h->direction == AM7XXX_DIRECTION_IN ?
"IN" :
320 h->direction == AM7XXX_DIRECTION_OUT ?
"OUT" :
322 debug(ctx,
"header_data_len: 0x%02hhx (%hhu)\n", h->header_data_len, h->header_data_len);
323 debug(ctx,
"unknown2: 0x%02hhx (%hhu)\n", h->unknown2, h->unknown2);
324 debug(ctx,
"unknown3: 0x%02hhx (%hhu)\n", h->unknown3, h->unknown3);
326 switch(h->packet_type) {
327 case AM7XXX_PACKET_TYPE_DEVINFO:
328 debug_dump_devinfo_header(ctx, &(h->header_data.devinfo));
331 case AM7XXX_PACKET_TYPE_IMAGE:
332 debug_dump_image_header(ctx, &(h->header_data.image));
335 case AM7XXX_PACKET_TYPE_POWER:
336 debug_dump_power_header(ctx, &(h->header_data.power));
339 case AM7XXX_PACKET_TYPE_ZOOM:
340 debug_dump_zoom_header(ctx, &(h->header_data.zoom));
344 debug(ctx,
"Parsing data not supported for this packet type!\n");
345 debug_dump_generic_header(ctx, &(h->header_data.data));
348 debug(ctx,
"END\n\n");
351 static inline unsigned int in_80chars(
unsigned int i)
355 return ((i + 1) % (80 / 3));
358 static void trace_dump_buffer(
am7xxx_context *ctx,
const char *message,
359 uint8_t *buffer,
unsigned int len)
363 if (ctx == NULL || buffer == NULL || len == 0)
368 trace(ctx,
"%s\n", message);
370 for (i = 0; i < len; i++) {
371 trace(ctx,
"%02hhX%c", buffer[i], (in_80chars(i) && (i < len - 1)) ?
' ' :
'\n');
376 static void debug_dump_header(
am7xxx_context *ctx,
struct am7xxx_header *h)
382 static void trace_dump_buffer(
am7xxx_context *ctx,
const char *message,
383 uint8_t *buffer,
unsigned int len)
392 static int read_data(
am7xxx_device *dev, uint8_t *buffer,
unsigned int len)
398 ret = libusb_bulk_transfer(dev->usb_device, 0x81, buffer, len, &transferred, 0);
399 if (ret != 0 || (
unsigned int)transferred != len) {
400 error(dev->ctx,
"%s. Transferred: %d (expected %u)\n",
401 libusb_error_name(ret), transferred, len);
405 trace_dump_buffer(dev->ctx,
"<-- received", buffer, len);
410 static int send_data(
am7xxx_device *dev, uint8_t *buffer,
unsigned int len)
415 trace_dump_buffer(dev->ctx,
"sending -->", buffer, len);
418 ret = libusb_bulk_transfer(dev->usb_device, 0x1, buffer, len, &transferred, 0);
419 if (ret != 0 || (
unsigned int)transferred != len) {
420 error(dev->ctx,
"%s. Transferred: %d (expected %u)\n",
421 libusb_error_name(ret), transferred, len);
428 static void LIBUSB_CALL send_data_async_complete_cb(
struct libusb_transfer *transfer)
431 int *completed = &(dev->transfer_completed);
432 int transferred = transfer->actual_length;
435 if (transferred != transfer->length) {
436 error(dev->ctx,
"transferred: %d (expected %u)\n",
437 transferred, transfer->length);
440 switch (transfer->status) {
441 case LIBUSB_TRANSFER_COMPLETED:
444 case LIBUSB_TRANSFER_TIMED_OUT:
445 ret = LIBUSB_ERROR_TIMEOUT;
447 case LIBUSB_TRANSFER_STALL:
448 ret = LIBUSB_ERROR_PIPE;
450 case LIBUSB_TRANSFER_OVERFLOW:
451 ret = LIBUSB_ERROR_OVERFLOW;
453 case LIBUSB_TRANSFER_NO_DEVICE:
454 ret = LIBUSB_ERROR_NO_DEVICE;
456 case LIBUSB_TRANSFER_ERROR:
457 case LIBUSB_TRANSFER_CANCELLED:
458 ret = LIBUSB_ERROR_IO;
461 error(dev->ctx,
"unrecognised status code %d", transfer->status);
462 ret = LIBUSB_ERROR_OTHER;
466 error(dev->ctx,
"libusb transfer failed: %s",
467 libusb_error_name(ret));
469 libusb_free_transfer(transfer);
475 static inline void wait_for_trasfer_completed(
am7xxx_device *dev)
477 while (!dev->transfer_completed) {
478 int ret = libusb_handle_events_completed(dev->ctx->usb_context,
479 &(dev->transfer_completed));
481 if (ret == LIBUSB_ERROR_INTERRUPTED)
483 error(dev->ctx,
"libusb_handle_events failed: %s, cancelling transfer and retrying",
484 libusb_error_name(ret));
485 libusb_cancel_transfer(dev->transfer);
491 static int send_data_async(
am7xxx_device *dev, uint8_t *buffer,
unsigned int len)
494 uint8_t *transfer_buffer;
496 dev->transfer = libusb_alloc_transfer(0);
497 if (dev->transfer == NULL) {
498 error(dev->ctx,
"cannot allocate transfer (%s)\n",
507 transfer_buffer = malloc(len);
508 if (transfer_buffer == NULL) {
509 error(dev->ctx,
"cannot allocate transfer buffer (%s)\n",
514 memcpy(transfer_buffer, buffer, len);
516 dev->transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
517 libusb_fill_bulk_transfer(dev->transfer, dev->usb_device, 0x1,
518 transfer_buffer, len,
519 send_data_async_complete_cb, dev, 0);
522 wait_for_trasfer_completed(dev);
524 trace_dump_buffer(dev->ctx,
"sending -->", buffer, len);
526 dev->transfer_completed = 0;
527 ret = libusb_submit_transfer(dev->transfer);
534 libusb_free_transfer(dev->transfer);
535 dev->transfer = NULL;
539 static void serialize_header(
struct am7xxx_header *h, uint8_t *buffer)
541 uint8_t **buffer_iterator = &buffer;
543 put_le32(h->packet_type, buffer_iterator);
544 put_8(h->direction, buffer_iterator);
545 put_8(h->header_data_len, buffer_iterator);
546 put_8(h->unknown2, buffer_iterator);
547 put_8(h->unknown3, buffer_iterator);
548 put_le32(h->header_data.data.field0, buffer_iterator);
549 put_le32(h->header_data.data.field1, buffer_iterator);
550 put_le32(h->header_data.data.field2, buffer_iterator);
551 put_le32(h->header_data.data.field3, buffer_iterator);
554 static void unserialize_header(uint8_t *buffer,
struct am7xxx_header *h)
556 uint8_t **buffer_iterator = &buffer;
558 h->packet_type = get_le32(buffer_iterator);
559 h->direction = get_8(buffer_iterator);
560 h->header_data_len = get_8(buffer_iterator);
561 h->unknown2 = get_8(buffer_iterator);
562 h->unknown3 = get_8(buffer_iterator);
563 h->header_data.data.field0 = get_le32(buffer_iterator);
564 h->header_data.data.field1 = get_le32(buffer_iterator);
565 h->header_data.data.field2 = get_le32(buffer_iterator);
566 h->header_data.data.field3 = get_le32(buffer_iterator);
569 static int read_header(
am7xxx_device *dev,
struct am7xxx_header *h)
573 ret = read_data(dev, dev->buffer, AM7XXX_HEADER_WIRE_SIZE);
577 unserialize_header(dev->buffer, h);
579 if (h->direction == AM7XXX_DIRECTION_IN) {
583 "Expected an AM7XXX_DIRECTION_IN packet, got one with direction = %d. Weird!\n",
588 debug_dump_header(dev->ctx, h);
594 static int send_header(
am7xxx_device *dev,
struct am7xxx_header *h)
598 debug_dump_header(dev->ctx, h);
605 serialize_header(h, dev->buffer);
607 ret = send_data(dev, dev->buffer, AM7XXX_HEADER_WIRE_SIZE);
609 error(dev->ctx,
"failed to send data\n");
614 static int send_command(
am7xxx_device *dev, am7xxx_packet_type type)
616 struct am7xxx_header h = {
618 .direction = AM7XXX_DIRECTION_OUT,
619 .header_data_len = 0x00,
632 return send_header(dev, &h);
642 const char *function_name,
651 fprintf(stderr,
"%s", function_name);
653 fprintf(stderr,
"[%d]", line);
654 fprintf(stderr,
": ");
658 vfprintf(stderr, fmt, ap);
666 const struct am7xxx_usb_device_descriptor *desc)
672 fatal(
"context must not be NULL!\n");
676 new_device = malloc(
sizeof(*new_device));
677 if (new_device == NULL) {
678 debug(ctx,
"cannot allocate a new device (%s)\n", strerror(errno));
681 memset(new_device, 0,
sizeof(*new_device));
683 new_device->ctx = ctx;
684 new_device->desc = desc;
685 new_device->transfer_completed = 1;
687 devices_list = &(ctx->devices_list);
689 if (*devices_list == NULL) {
690 *devices_list = new_device;
695 prev->next = new_device;
701 unsigned int device_index)
707 fatal(
"context must not be NULL!\n");
711 current = ctx->devices_list;
712 while (current && i++ < device_index)
713 current = current->next;
719 unsigned int device_index,
720 libusb_device *usb_dev,
724 int current_configuration;
726 *dev = find_device(ctx, device_index);
733 if ((*dev)->usb_device) {
738 ret = libusb_open(usb_dev, &((*dev)->usb_device));
740 debug(ctx,
"libusb_open failed: %s\n", libusb_error_name(ret));
748 current_configuration = -1;
749 ret = libusb_get_configuration((*dev)->usb_device,
750 ¤t_configuration);
752 debug(ctx,
"libusb_get_configuration failed: %s\n",
753 libusb_error_name(ret));
754 goto out_libusb_close;
757 if (current_configuration != (*dev)->desc->configuration) {
778 ret = libusb_set_configuration((*dev)->usb_device,
779 (*dev)->desc->configuration);
781 debug(ctx,
"libusb_set_configuration failed: %s\n",
782 libusb_error_name(ret));
783 debug(ctx,
"Cannot set configuration %hhu\n",
784 (*dev)->desc->configuration);
785 goto out_libusb_close;
789 libusb_set_auto_detach_kernel_driver((*dev)->usb_device, 1);
791 ret = libusb_claim_interface((*dev)->usb_device,
792 (*dev)->desc->interface_number);
794 debug(ctx,
"libusb_claim_interface failed: %s\n",
795 libusb_error_name(ret));
796 debug(ctx,
"Cannot claim interface %hhu\n",
797 (*dev)->desc->interface_number);
798 goto out_libusb_close;
804 current_configuration = -1;
805 ret = libusb_get_configuration((*dev)->usb_device,
806 ¤t_configuration);
808 debug(ctx,
"libusb_get_configuration after claim failed: %s\n",
809 libusb_error_name(ret));
810 goto out_libusb_release_interface;
813 if (current_configuration != (*dev)->desc->configuration) {
814 debug(ctx,
"libusb configuration changed (expected: %hhu, current: %d)\n",
815 (*dev)->desc->configuration, current_configuration);
817 goto out_libusb_release_interface;
822 out_libusb_release_interface:
823 libusb_release_interface((*dev)->usb_device,
824 (*dev)->desc->interface_number);
826 libusb_close((*dev)->usb_device);
827 (*dev)->usb_device = NULL;
832 SCAN_OP_BUILD_DEVLIST,
858 libusb_device **list;
859 unsigned int current_index;
864 fatal(
"context must not be NULL!\n");
867 if (op == SCAN_OP_BUILD_DEVLIST && ctx->devices_list != NULL) {
868 error(ctx,
"device scan done already? Abort!\n");
872 num_devices = libusb_get_device_list(ctx->usb_context, &list);
873 if (num_devices < 0) {
879 for (i = 0; i < num_devices; i++) {
880 struct libusb_device_descriptor desc;
883 ret = libusb_get_device_descriptor(list[i], &desc);
887 for (j = 0; j < ARRAY_SIZE(supported_devices); j++) {
888 if (desc.idVendor == supported_devices[j].vendor_id &&
889 desc.idProduct == supported_devices[j].product_id) {
891 if (op == SCAN_OP_BUILD_DEVLIST) {
893 info(ctx,
"am7xxx device found, index: %d, name: %s\n",
895 supported_devices[j].name);
896 new_device = add_new_device(ctx, &supported_devices[j]);
897 if (new_device == NULL) {
903 debug(ctx,
"Cannot create a new device\n");
907 }
else if (op == SCAN_OP_OPEN_DEVICE &&
908 current_index == open_device_index) {
910 ret = open_device(ctx,
915 debug(ctx,
"open_device failed\n");
929 if (op == SCAN_OP_OPEN_DEVICE) {
930 error(ctx,
"Cannot find any device to open\n");
938 libusb_free_device_list(list, 1);
947 struct am7xxx_header h = {
948 .packet_type = AM7XXX_PACKET_TYPE_POWER,
949 .direction = AM7XXX_DIRECTION_OUT,
950 .header_data_len =
sizeof(
struct am7xxx_power_header),
957 h.header_data.power.bit2 = 0;
958 h.header_data.power.bit1 = 0;
959 h.header_data.power.bit0 = 0;
963 h.header_data.power.bit2 = 0;
964 h.header_data.power.bit1 = 0;
965 h.header_data.power.bit0 = 1;
969 h.header_data.power.bit2 = 0;
970 h.header_data.power.bit1 = 1;
971 h.header_data.power.bit0 = 0;
975 h.header_data.power.bit2 = 0;
976 h.header_data.power.bit1 = 1;
977 h.header_data.power.bit0 = 1;
981 h.header_data.power.bit2 = 1;
982 h.header_data.power.bit1 = 0;
983 h.header_data.power.bit0 = 0;
987 error(dev->ctx,
"Unsupported power mode.\n");
991 ret = send_header(dev, &h);
1002 return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_LOW);
1005 return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_MEDIUM);
1008 return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_HIGH);
1013 error(dev->ctx,
"Unsupported power mode.\n");
1021 struct am7xxx_header h = {
1022 .packet_type = AM7XXX_PACKET_TYPE_ZOOM,
1023 .direction = AM7XXX_DIRECTION_OUT,
1024 .header_data_len =
sizeof(
struct am7xxx_zoom_header),
1031 h.header_data.zoom.bit1 = 0;
1032 h.header_data.zoom.bit0 = 0;
1036 h.header_data.zoom.bit1 = 0;
1037 h.header_data.zoom.bit0 = 1;
1041 h.header_data.zoom.bit1 = 1;
1042 h.header_data.zoom.bit0 = 0;
1046 h.header_data.zoom.bit1 = 1;
1047 h.header_data.zoom.bit0 = 1;
1052 error(dev->ctx,
"Unsupported zoom mode.\n");
1056 ret = send_header(dev, &h);
1066 am7xxx_packet_type packet_type;
1070 packet_type = AM7XXX_PACKET_TYPE_PICOPIX_DISABLE_TI;
1074 packet_type = AM7XXX_PACKET_TYPE_PICOPIX_ENABLE_TI;
1081 error(dev->ctx,
"Unsupported zoom mode.\n");
1085 ret = send_command(dev, packet_type);
1095 return send_command(dev, packet_type);
1104 *ctx = malloc(
sizeof(**ctx));
1106 fatal(
"cannot allocate the context (%s)\n", strerror(errno));
1109 memset(*ctx, 0,
sizeof(**ctx));
1114 ret = libusb_init(&((*ctx)->usb_context));
1116 error(*ctx,
"libusb_init failed: %s\n", libusb_error_name(ret));
1117 goto out_free_context;
1120 libusb_set_debug((*ctx)->usb_context, LIBUSB_LOG_LEVEL_INFO);
1122 ret = scan_devices(*ctx, SCAN_OP_BUILD_DEVLIST , 0, NULL);
1124 error(*ctx,
"scan_devices() failed\n");
1145 fatal(
"context must not be NULL!\n");
1149 current = ctx->devices_list;
1153 free(current->device_info);
1158 libusb_exit(ctx->usb_context);
1165 ctx->log_level = log_level;
1169 unsigned int device_index)
1174 fatal(
"context must not be NULL!\n");
1178 ret = scan_devices(ctx, SCAN_OP_OPEN_DEVICE, device_index, dev);
1182 }
else if (ret > 0) {
1183 warning(ctx,
"device %d already open\n", device_index);
1200 error(ctx,
"cannot get device info\n");
1209 fatal(
"dev must not be NULL!\n");
1212 if (dev->usb_device) {
1213 wait_for_trasfer_completed(dev);
1214 libusb_release_interface(dev->usb_device, dev->desc->interface_number);
1215 libusb_close(dev->usb_device);
1216 dev->usb_device = NULL;
1225 struct am7xxx_header h;
1228 if (dev->device_info)
1231 ret = send_command(dev, AM7XXX_PACKET_TYPE_DEVINFO);
1235 memset(&h, 0,
sizeof(h));
1236 ret = read_header(dev, &h);
1240 if (h.packet_type != AM7XXX_PACKET_TYPE_DEVINFO) {
1241 error(dev->ctx,
"expected packet type: %d, got %d instead!\n",
1242 AM7XXX_PACKET_TYPE_DEVINFO, h.packet_type);
1247 dev->device_info = malloc(
sizeof(*dev->device_info));
1248 if (dev->device_info == NULL) {
1249 error(dev->ctx,
"cannot allocate a device info (%s)\n",
1253 memset(dev->device_info, 0,
sizeof(*dev->device_info));
1255 dev->device_info->native_width = h.header_data.devinfo.native_width;
1256 dev->device_info->native_height = h.header_data.devinfo.native_height;
1259 dev->device_info->unknown0 = h.header_data.devinfo.unknown0;
1260 dev->device_info->unknown1 = h.header_data.devinfo.unknown1;
1265 memcpy(device_info, dev->device_info,
sizeof(*device_info));
1270 unsigned int upscale,
1271 unsigned int original_width,
1272 unsigned int original_height,
1273 unsigned int *scaled_width,
1274 unsigned int *scaled_height)
1283 error(dev->ctx,
"cannot get device info\n");
1294 debug(dev->ctx,
"CASE 0, no rescaling, the original image fits already\n");
1295 *scaled_width = original_width;
1296 *scaled_height = original_height;
1301 width_ratio = (float)original_width / device_info.
native_width;
1302 height_ratio = (
float)original_height / device_info.
native_height;
1304 if (width_ratio > height_ratio) {
1309 debug(dev->ctx,
"CASE 1, original image wider, adjust the scaled height\n");
1311 *scaled_height = (
unsigned int)lroundf(original_height / width_ratio);
1312 }
else if (width_ratio < height_ratio) {
1317 debug(dev->ctx,
"CASE 2 original image taller, adjust the scaled width\n");
1318 *scaled_width = (
unsigned int)lroundf(original_width / height_ratio);
1321 debug(dev->ctx,
"CASE 3, just rescale, same aspect ratio already\n");
1325 debug(dev->ctx,
"scaled dimensions: %dx%d\n", *scaled_width, *scaled_height);
1333 unsigned int height,
1335 unsigned int image_size)
1338 struct am7xxx_header h = {
1339 .packet_type = AM7XXX_PACKET_TYPE_IMAGE,
1340 .direction = AM7XXX_DIRECTION_OUT,
1341 .header_data_len =
sizeof(
struct am7xxx_image_header),
1349 .image_size = image_size,
1354 ret = send_header(dev, &h);
1358 if (image == NULL || image_size == 0) {
1359 warning(dev->ctx,
"Not sending any data, check the 'image' or 'image_size' parameters\n");
1363 return send_data(dev, image, image_size);
1369 unsigned int height,
1371 unsigned int image_size)
1374 struct am7xxx_header h = {
1375 .packet_type = AM7XXX_PACKET_TYPE_IMAGE,
1376 .direction = AM7XXX_DIRECTION_OUT,
1377 .header_data_len =
sizeof(
struct am7xxx_image_header),
1385 .image_size = image_size,
1390 ret = send_header(dev, &h);
1394 if (image == NULL || image_size == 0) {
1395 warning(dev->ctx,
"Not sending any data, check the 'image' or 'image_size' parameters\n");
1399 return send_data_async(dev, image, image_size);
1404 if (dev->desc->ops.set_power_mode == NULL) {
1406 "setting power mode is unsupported on this device\n");
1410 return dev->desc->ops.set_power_mode(dev, power);
1415 if (dev->desc->ops.set_zoom_mode == NULL) {
1417 "setting zoom mode is unsupported on this device\n");
1421 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.