X-Git-Url: https://git.ao2.it/libam7xxx.git/blobdiff_plain/7c12ee7bab2847c89104dbec43ea5cec481ed1a1..38c3f5374d3c6305be89b18108fa0bf1de4f4cbd:/src/am7xxx.c diff --git a/src/am7xxx.c b/src/am7xxx.c index a8bcc49..d6615ba 100644 --- a/src/am7xxx.c +++ b/src/am7xxx.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "am7xxx.h" #include "serialize.h" @@ -35,6 +36,20 @@ # define __attribute__(x) /*NOTHING*/ #endif +/* Control shared library symbols visibility */ +#if defined _WIN32 || defined __CYGWIN__ + #define AM7XXX_PUBLIC __declspec(dllexport) + #define AM7XXX_LOCAL +#else + #if __GNUC__ >= 4 + #define AM7XXX_PUBLIC __attribute__ ((visibility ("default"))) + #define AM7XXX_LOCAL __attribute__ ((visibility ("hidden"))) + #else + #define AM7XXX_PUBLIC + #define AM7XXX_LOCAL + #endif +#endif + static void log_message(am7xxx_context *ctx, int level, const char *function, @@ -62,6 +77,16 @@ static struct am7xxx_usb_device_descriptor supported_devices[] = { .product_id = 0xc101, }, { + .name = "Acer C112", + .vendor_id = 0x1de1, + .product_id = 0x5501, + }, + { + .name ="Aiptek PocketCinema T25", + .vendor_id = 0x08ca, + .product_id = 0x2144, + }, + { .name = "Philips/Sagemcom PicoPix 1020", .vendor_id = 0x21e7, .product_id = 0x000e, @@ -69,7 +94,7 @@ static struct am7xxx_usb_device_descriptor supported_devices[] = { }; /* The header size on the wire is known to be always 24 bytes, regardless of - * the memory configuration enforced by different architechtures or compilers + * the memory configuration enforced by different architectures or compilers * for struct am7xxx_header */ #define AM7XXX_HEADER_WIRE_SIZE 24 @@ -91,7 +116,7 @@ typedef enum { AM7XXX_PACKET_TYPE_DEVINFO = 0x01, AM7XXX_PACKET_TYPE_IMAGE = 0x02, AM7XXX_PACKET_TYPE_POWER = 0x04, - AM7XXX_PACKET_TYPE_UNKNOWN = 0x05, + AM7XXX_PACKET_TYPE_ZOOM = 0x05, } am7xxx_packet_type; struct am7xxx_generic_header { @@ -121,6 +146,11 @@ struct am7xxx_power_header { uint32_t bit0; }; +struct am7xxx_zoom_header { + uint32_t bit1; + uint32_t bit0; +}; + /* * Examples of packet headers: * @@ -131,9 +161,13 @@ struct am7xxx_power_header { * 04 00 00 00 00 0c ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ +/* Direction of the communication from the host point of view */ +#define AM7XXX_DIRECTION_OUT 0 /* host -> device */ +#define AM7XXX_DIRECTION_IN 1 /* host <- device */ + struct am7xxx_header { uint32_t packet_type; - uint8_t unknown0; + uint8_t direction; uint8_t header_data_len; uint8_t unknown2; uint8_t unknown3; @@ -142,6 +176,7 @@ struct am7xxx_header { struct am7xxx_devinfo_header devinfo; struct am7xxx_image_header image; struct am7xxx_power_header power; + struct am7xxx_zoom_header zoom; } header_data; }; @@ -182,6 +217,16 @@ static void debug_dump_power_header(am7xxx_context *ctx, struct am7xxx_power_hea debug(ctx, "\tbit0: 0x%08x (%u)\n", p->bit0, p->bit0); } +static void debug_dump_zoom_header(am7xxx_context *ctx, struct am7xxx_zoom_header *z) +{ + if (ctx == NULL || z == NULL) + return; + + debug(ctx, "Zoom header:\n"); + debug(ctx, "\tbit1: 0x%08x (%u)\n", z->bit1, z->bit1); + debug(ctx, "\tbit0: 0x%08x (%u)\n", z->bit0, z->bit0); +} + static void debug_dump_header(am7xxx_context *ctx, struct am7xxx_header *h) { if (ctx == NULL || h == NULL) @@ -189,7 +234,7 @@ static void debug_dump_header(am7xxx_context *ctx, struct am7xxx_header *h) debug(ctx, "BEGIN\n"); debug(ctx, "packet_type: 0x%08x (%u)\n", h->packet_type, h->packet_type); - debug(ctx, "unknown0: 0x%02hhx (%hhu)\n", h->unknown0, h->unknown0); + debug(ctx, "direction: 0x%02hhx (%hhu)\n", h->direction, h->direction); debug(ctx, "header_data_len: 0x%02hhx (%hhu)\n", h->header_data_len, h->header_data_len); debug(ctx, "unknown2: 0x%02hhx (%hhu)\n", h->unknown2, h->unknown2); debug(ctx, "unknown3: 0x%02hhx (%hhu)\n", h->unknown3, h->unknown3); @@ -207,6 +252,10 @@ static void debug_dump_header(am7xxx_context *ctx, struct am7xxx_header *h) debug_dump_power_header(ctx, &(h->header_data.power)); break; + case AM7XXX_PACKET_TYPE_ZOOM: + debug_dump_zoom_header(ctx, &(h->header_data.zoom)); + break; + default: debug(ctx, "Packet type not supported!\n"); break; @@ -244,6 +293,7 @@ static void debug_dump_header(am7xxx_context *ctx, struct am7xxx_header *h) (void)ctx; (void)h; } + static void trace_dump_buffer(am7xxx_context *ctx, const char *message, uint8_t *buffer, unsigned int len) { @@ -260,7 +310,10 @@ static int read_data(am7xxx_device *dev, uint8_t *buffer, unsigned int len) int transferred = 0; ret = libusb_bulk_transfer(dev->usb_device, 0x81, buffer, len, &transferred, 0); - if (ret != 0 || (unsigned int)transferred != len) { + if (ret < 0) { + error(dev->ctx, "USB bulk transfer failed (%s)\n", libusb_error_name(ret)); + return ret; + } else if (ret != 0 || (unsigned int)transferred != len) { error(dev->ctx, "ret: %d\ttransferred: %d (expected %u)\n", ret, transferred, len); return ret; @@ -278,8 +331,11 @@ static int send_data(am7xxx_device *dev, uint8_t *buffer, unsigned int len) trace_dump_buffer(dev->ctx, "sending -->", buffer, len); - ret = libusb_bulk_transfer(dev->usb_device, 1, buffer, len, &transferred, 0); - if (ret != 0 || (unsigned int)transferred != len) { + ret = libusb_bulk_transfer(dev->usb_device, 0x1, buffer, len, &transferred, 0); + if (ret < 0) { + error(dev->ctx, "USB bulk transfer failed (%s)\n", libusb_error_name(ret)); + return ret; + } else if (ret != 0 || (unsigned int)transferred != len) { error(dev->ctx, "ret: %d\ttransferred: %d (expected %u)\n", ret, transferred, len); return ret; @@ -293,7 +349,7 @@ static void serialize_header(struct am7xxx_header *h, uint8_t *buffer) uint8_t **buffer_iterator = &buffer; put_le32(h->packet_type, buffer_iterator); - put_8(h->unknown0, buffer_iterator); + put_8(h->direction, buffer_iterator); put_8(h->header_data_len, buffer_iterator); put_8(h->unknown2, buffer_iterator); put_8(h->unknown3, buffer_iterator); @@ -308,7 +364,7 @@ static void unserialize_header(uint8_t *buffer, struct am7xxx_header *h) uint8_t **buffer_iterator = &buffer; h->packet_type = get_le32(buffer_iterator); - h->unknown0 = get_8(buffer_iterator); + h->direction = get_8(buffer_iterator); h->header_data_len = get_8(buffer_iterator); h->unknown2 = get_8(buffer_iterator); h->unknown3 = get_8(buffer_iterator); @@ -330,7 +386,13 @@ static int read_header(am7xxx_device *dev, struct am7xxx_header *h) debug_dump_header(dev->ctx, h); - ret = 0; + if (h->direction == AM7XXX_DIRECTION_IN) { + ret = 0; + } else { + error(dev->ctx, + "Received a packet with direction AM7XXX_DIRECTION_OUT, weird!\n"); + ret = -EINVAL; + } out: return ret; @@ -471,6 +533,7 @@ static int scan_devices(am7xxx_context *ctx, scan_op op, num_devices = libusb_get_device_list(ctx->usb_context, &list); if (num_devices < 0) { + error(ctx, "USB get device list failed (%s)\n", libusb_error_name(num_devices)); ret = -ENODEV; goto out; } @@ -481,8 +544,10 @@ static int scan_devices(am7xxx_context *ctx, scan_op op, unsigned int j; ret = libusb_get_device_descriptor(list[i], &desc); - if (ret < 0) + if (ret < 0) { + debug(ctx, "USB get device descriptor failed (%s)\n", libusb_error_name(ret)); continue; + } for (j = 0; j < ARRAY_SIZE(supported_devices); j++) { if (desc.idVendor == supported_devices[j].vendor_id @@ -522,11 +587,11 @@ static int scan_devices(am7xxx_context *ctx, scan_op op, ret = libusb_open(list[i], &((*dev)->usb_device)); if (ret < 0) { - debug(ctx, "libusb_open failed\n"); + debug(ctx, "libusb_open failed (%s)\n", libusb_error_name(ret)); goto out; } - libusb_set_configuration((*dev)->usb_device, 1); + libusb_set_configuration((*dev)->usb_device, 2); libusb_claim_interface((*dev)->usb_device, 0); goto out; } @@ -549,7 +614,9 @@ out: return ret; } -int am7xxx_init(am7xxx_context **ctx) +/* Public API */ + +AM7XXX_PUBLIC int am7xxx_init(am7xxx_context **ctx) { int ret = 0; @@ -565,8 +632,10 @@ int am7xxx_init(am7xxx_context **ctx) (*ctx)->log_level = AM7XXX_LOG_TRACE; ret = libusb_init(&((*ctx)->usb_context)); - if (ret < 0) + if (ret < 0) { + fatal("USB initialization failed (%s)\n", libusb_error_name(ret)); goto out_free_context; + } libusb_set_debug((*ctx)->usb_context, 3); @@ -588,7 +657,7 @@ out: return ret; } -void am7xxx_shutdown(am7xxx_context *ctx) +AM7XXX_PUBLIC void am7xxx_shutdown(am7xxx_context *ctx) { am7xxx_device *current; @@ -610,12 +679,12 @@ void am7xxx_shutdown(am7xxx_context *ctx) ctx = NULL; } -void am7xxx_set_log_level(am7xxx_context *ctx, am7xxx_log_level log_level) +AM7XXX_PUBLIC void am7xxx_set_log_level(am7xxx_context *ctx, am7xxx_log_level log_level) { ctx->log_level = log_level; } -int am7xxx_open_device(am7xxx_context *ctx, am7xxx_device **dev, +AM7XXX_PUBLIC int am7xxx_open_device(am7xxx_context *ctx, am7xxx_device **dev, unsigned int device_index) { int ret; @@ -637,7 +706,7 @@ int am7xxx_open_device(am7xxx_context *ctx, am7xxx_device **dev, return ret; } -int am7xxx_close_device(am7xxx_device *dev) +AM7XXX_PUBLIC int am7xxx_close_device(am7xxx_device *dev) { if (dev == NULL) { fatal("dev must not be NULL!\n"); @@ -651,13 +720,13 @@ int am7xxx_close_device(am7xxx_device *dev) return 0; } -int am7xxx_get_device_info(am7xxx_device *dev, +AM7XXX_PUBLIC int am7xxx_get_device_info(am7xxx_device *dev, am7xxx_device_info *device_info) { int ret; struct am7xxx_header h = { .packet_type = AM7XXX_PACKET_TYPE_DEVINFO, - .unknown0 = 0x00, + .direction = AM7XXX_DIRECTION_OUT, .header_data_len = 0x00, .unknown2 = 0x3e, .unknown3 = 0x10, @@ -690,7 +759,7 @@ int am7xxx_get_device_info(am7xxx_device *dev, return 0; } -int am7xxx_calc_scaled_image_dimensions(am7xxx_device *dev, +AM7XXX_PUBLIC int am7xxx_calc_scaled_image_dimensions(am7xxx_device *dev, unsigned int upscale, unsigned int original_width, unsigned int original_height, @@ -733,14 +802,14 @@ int am7xxx_calc_scaled_image_dimensions(am7xxx_device *dev, */ debug(dev->ctx, "CASE 1, original image wider, adjust the scaled height\n"); *scaled_width = device_info.native_width; - *scaled_height = (unsigned int)(original_height / width_ratio); + *scaled_height = (unsigned int)lroundf(original_height / width_ratio); } else if (width_ratio < height_ratio) { /* * The input is proportionally "taller" than the device viewport * so its width needs to be adjusted */ debug(dev->ctx, "CASE 2 original image taller, adjust the scaled width\n"); - *scaled_width = (unsigned int)(original_width / height_ratio); + *scaled_width = (unsigned int)lroundf(original_width / height_ratio); *scaled_height = device_info.native_height; } else { debug(dev->ctx, "CASE 3, just rescale, same aspect ratio already\n"); @@ -752,7 +821,7 @@ int am7xxx_calc_scaled_image_dimensions(am7xxx_device *dev, return 0; } -int am7xxx_send_image(am7xxx_device *dev, +AM7XXX_PUBLIC int am7xxx_send_image(am7xxx_device *dev, am7xxx_image_format format, unsigned int width, unsigned int height, @@ -762,7 +831,7 @@ int am7xxx_send_image(am7xxx_device *dev, int ret; struct am7xxx_header h = { .packet_type = AM7XXX_PACKET_TYPE_IMAGE, - .unknown0 = 0x00, + .direction = AM7XXX_DIRECTION_OUT, .header_data_len = sizeof(struct am7xxx_image_header), .unknown2 = 0x3e, .unknown3 = 0x10, @@ -788,18 +857,18 @@ int am7xxx_send_image(am7xxx_device *dev, return send_data(dev, image, image_size); } -int am7xxx_set_power_mode(am7xxx_device *dev, am7xxx_power_mode mode) +AM7XXX_PUBLIC int am7xxx_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power) { int ret; struct am7xxx_header h = { .packet_type = AM7XXX_PACKET_TYPE_POWER, - .unknown0 = 0x00, + .direction = AM7XXX_DIRECTION_OUT, .header_data_len = sizeof(struct am7xxx_power_header), .unknown2 = 0x3e, .unknown3 = 0x10, }; - switch(mode) { + switch(power) { case AM7XXX_POWER_OFF: h.header_data.power.bit2 = 0; h.header_data.power.bit1 = 0; @@ -810,6 +879,7 @@ int am7xxx_set_power_mode(am7xxx_device *dev, am7xxx_power_mode mode) h.header_data.power.bit2 = 0; h.header_data.power.bit1 = 0; h.header_data.power.bit0 = 1; + break; case AM7XXX_POWER_MIDDLE: h.header_data.power.bit2 = 0; @@ -830,7 +900,51 @@ int am7xxx_set_power_mode(am7xxx_device *dev, am7xxx_power_mode mode) break; default: - error(dev->ctx, "Power mode not supported!\n"); + error(dev->ctx, "Unsupported power mode.\n"); + return -EINVAL; + }; + + ret = send_header(dev, &h); + if (ret < 0) + return ret; + + return 0; +} + +AM7XXX_PUBLIC int am7xxx_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom) +{ + int ret; + struct am7xxx_header h = { + .packet_type = AM7XXX_PACKET_TYPE_ZOOM, + .direction = AM7XXX_DIRECTION_OUT, + .header_data_len = sizeof(struct am7xxx_zoom_header), + .unknown2 = 0x3e, + .unknown3 = 0x10, + }; + + switch(zoom) { + case AM7XXX_ZOOM_ORIGINAL: + h.header_data.zoom.bit1 = 0; + h.header_data.zoom.bit0 = 0; + break; + + case AM7XXX_ZOOM_H: + h.header_data.zoom.bit1 = 0; + h.header_data.zoom.bit0 = 1; + break; + + case AM7XXX_ZOOM_H_V: + h.header_data.zoom.bit1 = 1; + h.header_data.zoom.bit0 = 0; + break; + + case AM7XXX_ZOOM_TEST: + h.header_data.zoom.bit1 = 1; + h.header_data.zoom.bit0 = 1; + break; + + default: + error(dev->ctx, "Unsupported zoom mode.\n"); return -EINVAL; };