From: Antonio Ospite Date: Sun, 28 Jul 2013 16:20:15 +0000 (+0200) Subject: Merge tag 'v0.1.4' into debian X-Git-Tag: debian/0.1.4-1~6 X-Git-Url: https://git.ao2.it/libam7xxx.git/commitdiff_plain/6ae8169cb30b198eb747e8c51894c95c9ce56076?hp=6d2d8613958e1f0ef011e9d848426086caafe9db Merge tag 'v0.1.4' into debian Release version 0.1.4 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 89f0437..d643ed9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(PROJECT_DESCRIPTION set(PROJECT_VER_MAJOR 0) set(PROJECT_VER_MINOR 1) -set(PROJECT_VER_PATCH 3) +set(PROJECT_VER_PATCH 4) set(PROJECT_VER_EXTRA "") set(PROJECT_VER "${PROJECT_VER_MAJOR}.${PROJECT_VER_MINOR}.${PROJECT_VER_PATCH}${PROJECT_VER_EXTRA}") @@ -31,7 +31,9 @@ macro(add_flags var) set(${var} "${${var}} ${_flags}") endmacro(add_flags) -if (CMAKE_COMPILER_IS_GNUCC) +string(REGEX MATCH "clang" CMAKE_COMPILER_IS_CLANG "${CMAKE_C_COMPILER}") + +if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG) add_definitions(-Wall) # let CFLAGS env override this @@ -63,13 +65,12 @@ if (CMAKE_COMPILER_IS_GNUCC) -Wswitch-enum -Wundef -Wunreachable-code - -Wunsafe-loop-optimizations -Wwrite-strings - -fstack-protector - --param=ssp-buffer-size=4) + -fstack-protector) add_flags(DEBUG_FLAGS - -ggdb) + -ggdb + -DDEBUG=1) add_flags(RELEASE_FLAGS -Wp,-D_FORTIFY_SOURCE=2) @@ -77,11 +78,30 @@ if (CMAKE_COMPILER_IS_GNUCC) if (STRICT_COMPILATION_CHECKS) add_flags(STRICT_FLAGS -Werror + # sign conversion warnings can be very noisy for a very little gain + #-Wsign-conversion # NOTE: Vanilla libusb-1.0.8 can't live with -pedantic-errors - -pedantic-errors + -pedantic-errors) + + endif() +endif() + +if (CMAKE_COMPILER_IS_GNUCC) + add_flags(CMAKE_C_FLAGS + -Wunsafe-loop-optimizations + --param=ssp-buffer-size=4) + + if (STRICT_COMPILATION_CHECKS) + add_flags(STRICT_FLAGS # NOTE: GCC >= 4.6 is needed for -Wunused-but-set-variable -Wunused-but-set-variable) + endif() +endif() +if (CMAKE_COMPILER_IS_CLANG) + if (STRICT_COMPILATION_CHECKS) + add_flags(STRICT_FLAGS + -Wshorten-64-to-32) endif() endif() diff --git a/ChangeLog b/ChangeLog index 340d105..89d4427 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,190 @@ +2013-07-28 11:15:18 +0200 Antonio Ospite + + * Release version 0.1.4 (HEAD, master) + +2013-07-28 01:11:42 +0200 Antonio Ospite + + * contrib: add some benchmarking data about am7xxx_send_image_async (origin/master) + +2013-07-28 00:50:30 +0200 Antonio Ospite + + * am7xxx-play: fix a crash when a packet cannot be encoded + +2013-07-28 00:38:13 +0200 Antonio Ospite + + * am7xxx-play: don't initialize variables when not needed + +2013-07-28 00:19:04 +0200 Antonio Ospite + + * TODO: mention that atoi() must go away + +2013-07-28 00:10:08 +0200 Antonio Ospite + + * picoproj: get rid of exit(), return more meaningful values to userspace + +2013-07-27 23:47:26 +0200 Antonio Ospite + + * HACKING.asciidoc: add commands to compile with clang + +2013-07-27 23:44:45 +0200 Antonio Ospite + + * HACKING.asciidoc: add an example of testing am7xxx-play with valgrind + +2013-07-27 23:36:08 +0200 Antonio Ospite + + * doc: update Doxyfile.in + +2013-07-27 23:27:01 +0200 Antonio Ospite + + * contrib: add a udev rule to invoke am7xxx-modeswitch + +2013-07-27 23:25:34 +0200 Antonio Ospite + + * Rename am7xxx_mode_switch to am7xxx-modeswitch + +2013-07-27 23:02:34 +0200 Antonio Ospite + + * TODO: mention that data types could be improved in the API + +2013-07-27 23:01:16 +0200 Antonio Ospite + + * picoporj: fix another -Wshorten-64-to-32 warning from clang + +2013-07-27 22:55:53 +0200 Antonio Ospite + + * picoproj: silence a -Wshorten-64-to-32 warning from clang + +2013-07-27 22:53:19 +0200 Antonio Ospite + + * CMakeLists.txt: disable -Wsign-conversion warnings + +2013-07-27 21:33:28 +0200 Antonio Ospite + + * am7xxx: fix a clang warning + +2013-07-27 20:55:48 +0200 Antonio Ospite + + * examples: silence a couple of clang warnings + +2013-07-27 20:26:06 +0200 Antonio Ospite + + * doc: mention the Top-Height/TEC PP700 in the Doxygen documentation + +2013-07-27 20:23:30 +0200 Antonio Ospite + + * doc: add some lsusb dumps for reference + +2013-07-21 00:13:33 +0200 Antonio Ospite + + * am7xxx-play: use am7xxx_send_image_async() (local-ao2) + +2013-07-21 00:10:28 +0200 Antonio Ospite + + * am7xxx: implement am7xxx_send_image_async() + +2013-07-14 13:25:25 +0200 Antonio Ospite + + * am7xxx: fix a typo in a comment s/a am7xxx device/an am7xxx device/ + +2013-07-13 11:05:00 +0200 Antonio Ospite + + * CMakeLists.txt: enable two new compiler warnings + +2013-06-30 00:22:07 +0200 Antonio Ospite + + * am7xxx: add quirks for devices not supporting some operations + +2013-06-30 00:20:51 +0200 Antonio Ospite + + * picoproj: remove an unreachable break statement + +2013-06-30 00:15:30 +0200 Antonio Ospite + + * am7xxx-play: uniform coding style + +2013-06-30 00:12:59 +0200 Antonio Ospite + + * CMakeLists.txt: add support for clang and isolate gcc-only options + +2013-06-29 23:11:57 +0200 Antonio Ospite + + * HACKING.asciidoc: mention the patch needed for older libav/ffmpeg + +2013-06-29 23:02:13 +0200 Antonio Ospite + + * README.asciidoc: mention the TEC PP700 projector as supported + +2013-05-27 00:06:23 +0200 Antonio Ospite + + * picoproj: remove an unneeded blank line + +2013-05-27 00:05:00 +0200 Antonio Ospite + + * examples: print the usage message when a required option is missing + +2013-05-26 23:53:13 +0200 Antonio Ospite + + * CMakeLists.txt: fix enabling verbose debug output + +2013-04-05 23:35:34 +0200 Antonio Ospite + + * am7xxx: use the symbolic constant for libusb log level + +2013-04-05 23:29:58 +0200 Antonio Ospite + + * picoproj: show the image resolution when image does not fit the native one + +2013-04-05 23:28:24 +0200 Antonio Ospite + + * picoproj: remove one of two consecutive blank lines + +2013-03-25 23:04:03 +0100 Antonio Ospite + + * doc, contrib: add PicoPix 2330 to the list of supported devices + +2013-03-25 22:47:21 +0100 Antonio Ospite + + * am7xxx: add support for Philips/Sagemcom PicoPix 2330 + +2013-03-25 22:44:35 +0100 Antonio Ospite + + * Merge branch 'per-device-usb-config' + +2013-03-23 23:30:54 +0100 Antonio Ospite + + * am7xxx: make the supported_device array const + +2013-03-23 22:55:04 +0100 Antonio Ospite + + * am7xxx: improve setting USB configuration and interface_number + +2012-11-14 15:41:48 +0100 Antonio Ospite + + * am7xxx: reference am7xxx_usb_device_descriptor in struct _am7xxx_device + +2013-03-23 22:40:25 +0100 Antonio Ospite + + * am7xxx: fail if USB configuration or interface are not right + +2013-03-23 23:03:48 +0100 Antonio Ospite + + * am7xxx_mode_switch: release interface only if claimed + +2013-03-14 23:04:20 +0100 Antonio Ospite + + * doc: add a man page for am7xxx_mode_switch + +2013-03-15 00:13:21 +0100 Antonio Ospite + + * Add a NEWS file + 2013-03-14 20:23:49 +0100 Antonio Ospite - * Release version 0.1.3 (HEAD, master) + * Release version 0.1.3 (tag: v0.1.3) 2013-03-14 19:48:14 +0100 Antonio Ospite - * am7xxx-play: switch to avcodec_encode_video2() (origin/master) + * am7xxx-play: switch to avcodec_encode_video2() 2013-03-14 19:30:07 +0100 Antonio Ospite @@ -268,7 +448,7 @@ 2012-03-28 13:37:00 +0200 Antonio Ospite - * Release version 0.1.2 (v0.1.2) + * Release version 0.1.2 (tag: v0.1.2) 2012-03-28 13:08:23 +0200 Antonio Ospite @@ -276,7 +456,7 @@ 2012-03-28 10:55:14 +0200 Antonio Ospite - * Release version 0.1.1 (v0.1.1) + * Release version 0.1.1 (tag: v0.1.1) 2012-03-28 10:43:04 +0200 Antonio Ospite @@ -308,7 +488,7 @@ 2012-03-26 13:50:05 +0200 Antonio Ospite - * Increase project number to 0.1.0 (v0.1.0) + * Increase project number to 0.1.0 (tag: v0.1.0) 2012-03-26 13:49:31 +0200 Antonio Ospite diff --git a/HACKING.asciidoc b/HACKING.asciidoc index 3c1bc74..20c4aa2 100644 --- a/HACKING.asciidoc +++ b/HACKING.asciidoc @@ -19,6 +19,9 @@ On a Debian based system, the dependencies can be installed with this command: libavdevice-dev \ libswscale-dev +With libav/ffmpeg version previous than 0.9 this patch is needed: +http://git.ao2.it/libam7xxx.git/blob_plain/refs/heads/debian:/debian/patches/0002-Revert-am7xxx-play-switch-to-avcodec_encode_video2.patch + The library and the example programs can be compiled following these steps: $ git clone git://git.ao2.it/libam7xxx.git @@ -47,6 +50,13 @@ can run: $ cmake -D CMAKE_C_COMPILER=cgcc ../ $ make +And for a pre-release check with a different compiler, which never hurts: + + $ mkdir build + $ cd build + $ cmake -D CMAKE_C_COMPILER=clang -D CMAKE_BUILD_TYPE=debug -D STRICT_COMPILATION_CHECKS=ON ../ + $ make + === Cross Builds If you want to build for MS Windows: @@ -78,3 +88,8 @@ dynamic analyzer by using a command like: $ valgrind --leak-check=full --show-reachable=yes --track-origins=yes \ ./bin/picoproj -W 800 -H 480 -f my_image.jpg + +or, for am7xxx-play: + + $ valgrind --leak-check=full --show-reachable=yes --track-origins=yes \ + ./bin/am7xxx-play -f x11grab -i :0 diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..7f38105 --- /dev/null +++ b/NEWS @@ -0,0 +1,31 @@ +News for v0.1.4: +================ + + * Improved USB device configuration in order to support mode devices + * Added support for Philips/Sagemcom PicoPix 2330 (Thanks to Grégory + Lemesre) + * Fixed verbose debug output + * Confirmed that libam7xxx works with the Top-Height/TEC PP700 projector + * Implemented am7xxx_send_image_async() + * Made am7xxx-play almost twice faster by using am7xxx_send_image_async() + * Improved documentation + * Added support for compiling with clang + * A lot of little fixes for correctness, robustness and portability + * Renamed am7xxx_mode_switch to am7xxx-modeswitch, added an udev rule for it + +News for v0.1.3: +================ + + * Better documentation + * Ported to Windows (compiles with MinGW) + * Added a minimal replacement of usb-modeswitch to use on systems where the + latter is not available + * Added support for Acer C112 (Thanks to Richard Wisenoecker) + * Added support for Aiptek PocketCinema T25 (Thanks to Matti Koskinen) + * Added some contrib scripts + * Added support for setting the projectors zoom mode + * Added multi-device support, now more than one projector can be used at the + same time on the same system (Tested by Konstantin Lohmann) + * Added support for Philips/SagemCom PicoPix PPX 2055 + * Fixed some problems with the supported Philips/SagemCom PicoPix devices, + now these devices are fully working (Thanks to the Certik family) diff --git a/README.asciidoc b/README.asciidoc index 7ad02de..d11a92f 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -44,8 +44,8 @@ manually with the command: --default-product 0x1101 \ --message-content 55534243087052890000000000000cff020000000000000000000000000000 -Alternatively, on systems where libusb works but 'usb_mode_switch' is not -easily available, the switch can be performed using the 'am7xxx_mode_switch' +Alternatively, on systems where libusb works but 'usb-modeswitch' is not +easily available, the switch can be performed using the 'am7xxx-modeswitch' example program from libam7xxx. Examples of devices based on AM7XXX are: @@ -55,13 +55,16 @@ Examples of devices based on AM7XXX are: * http://support.acer.com/product/default.aspx?modelId=3888 - Philips/SagemCom PicoPix projectors (PPX 1020, PPX 1230, PPX 1430, PPX - 1630, PPX 2055): + 1630, PPX 2055, PPX 2330): * http://www.philips.co.uk/c/pocket-projector/179840/cat/ * http://www.sagemcom.com/EN/products/image-sound/pico-video-projectors.html - CEL-TEC MP-01: * http://www.kabelmanie.cz/miniprojektor-cel-tec-mp-01/ + - Top-Height/TEC PP700 + * http://www.ishopiwin.com/en/appliances-electronics/electronics/projectors/pico-projector-pp-700.html + - Royaltek PJU-2100: * http://www.royaltek.com/index.php/pju-2100-pico-projector @@ -88,7 +91,7 @@ All the needed files need to be in the same location: - 'libssp-0.dll' from MinGW; - - 'am7xxx_mode_switch.exe', 'libam7xxx.dll' and 'picoproj.exe' which can all + - 'am7xxx-modeswitch.exe', 'libam7xxx.dll' and 'picoproj.exe' which can all be built by following the instructions in the HACKING.asciidoc document from libam7xxx. @@ -106,7 +109,7 @@ for both the mass storage device and the display device: from now on the virtual CD-ROM can't be accessed anymore until the +USBSTOR+ Driver is restored. - - Run 'am7xxx_mode_switch.exe' + - Run 'am7xxx-modeswitch.exe' - When the new (display) device shows up, run Zadig and install the +WinUSB+ driver for it too. diff --git a/TODO b/TODO index 3db48f2..1ce3068 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,6 @@ +- Get rid of atoi() - Write a GStreamer sink element based on libam7xxx. - Generate language bindings in order to use libam7xxx from other languages (this may not be necessary if the GStreamer sink works well enough). +- If there will ever be an API breakage, consider using more portable types + (e.g. off_t for file sizes, size_t for counters, etc.) diff --git a/contrib/50-am7xxx_mode_switch.rules b/contrib/50-am7xxx_mode_switch.rules new file mode 100644 index 0000000..4210346 --- /dev/null +++ b/contrib/50-am7xxx_mode_switch.rules @@ -0,0 +1,3 @@ +# Rule to call am7xxx_mode_switch, useful when usb-modeswitch is not available. +# Actions Microelectronics Co. Generic Display Device (Mass storage mode) +ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1de1", ATTRS{idProduct}=="1101", MODE="0660", GROUP="plugdev", RUN+="am7xxx-modeswitch" diff --git a/contrib/55-am7xxx.rules b/contrib/55-am7xxx.rules index 53643ac..6dc7ccd 100644 --- a/contrib/55-am7xxx.rules +++ b/contrib/55-am7xxx.rules @@ -8,3 +8,5 @@ ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="08ca", ATTRS{idProduct}=="214 ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="21e7", ATTRS{idProduct}=="000e", MODE="0660", GROUP="plugdev" # Philips/Sagemcom PicoPix 2055 ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="21e7", ATTRS{idProduct}=="0016", MODE="0660", GROUP="plugdev" +# Philips/Sagemcom PicoPix 2330 +ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="21e7", ATTRS{idProduct}=="0019", MODE="0660", GROUP="plugdev" diff --git a/contrib/performance/0001-Instrument-code-with-fps-meter.patch b/contrib/performance/0001-Instrument-code-with-fps-meter.patch new file mode 100644 index 0000000..5c133ee --- /dev/null +++ b/contrib/performance/0001-Instrument-code-with-fps-meter.patch @@ -0,0 +1,65 @@ +From dc6b216ffea1e80fd3f43d6144eb679a193f5666 Mon Sep 17 00:00:00 2001 +From: Antonio Ospite +Date: Sun, 28 Jul 2013 01:06:41 +0200 +Subject: [PATCH] Instrument code with fps-meter +X-Face: z*RaLf`X<@C75u6Ig9}{oW$H;1_\2t5)({*|jhM/Vb;]yA5\I~93>J<_`<4)A{':UrE + +Instrument code with fps-meter: +http://git.ao2.it/experiments/fps-meter.git/ +--- + examples/CMakeLists.txt | 2 +- + examples/am7xxx-play.c | 4 ++++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt +index c77a812..23af8a9 100644 +--- a/examples/CMakeLists.txt ++++ b/examples/CMakeLists.txt +@@ -1,5 +1,5 @@ + include(CheckSymbolExists) +-add_definitions("-D_POSIX_C_SOURCE=2") # for getopt() ++add_definitions("-D_POSIX_C_SOURCE=200112L") # for getopt() + add_definitions("-D_POSIX_SOURCE") # for sigaction + add_definitions("-D_BSD_SOURCE") # for strdup + +diff --git a/examples/am7xxx-play.c b/examples/am7xxx-play.c +index 3230e67..17228bf 100644 +--- a/examples/am7xxx-play.c ++++ b/examples/am7xxx-play.c +@@ -34,6 +34,7 @@ + #include + + #include ++#include "fps-meter.h" + + /* On some systems ENOTSUP is not defined, fallback to its value on + * linux which is equal to EOPNOTSUPP which is 95 +@@ -292,6 +293,7 @@ static int am7xxx_play(const char *input_format_string, + int got_picture; + int got_packet; + int ret; ++ struct fps_meter_stats stats; + + ret = video_input_init(&input_ctx, input_format_string, input_path, input_options); + if (ret < 0) { +@@ -354,6 +356,7 @@ static int am7xxx_play(const char *input_format_string, + goto cleanup_out_buf; + } + ++ fps_meter_init(&stats); + while (run) { + /* read packet */ + ret = av_read_frame(input_ctx.format_ctx, &in_packet); +@@ -438,6 +441,7 @@ static int am7xxx_play(const char *input_format_string, + run = 0; + goto end_while; + } ++ fps_meter_update(&stats); + } + end_while: + if (!output_ctx.raw_output && got_packet) +-- +1.8.3.2 + diff --git a/contrib/performance/1024x768_am7xxx_send_image.log b/contrib/performance/1024x768_am7xxx_send_image.log new file mode 100644 index 0000000..e47ce9e --- /dev/null +++ b/contrib/performance/1024x768_am7xxx_send_image.log @@ -0,0 +1,51 @@ +14.95 +27.28 +26.73 +23.77 +25.37 +25.30 +25.36 +27.28 +27.73 +27.28 +27.28 +27.28 +27.28 +26.74 +28.26 +26.66 +27.83 +28.26 +27.73 +28.72 +27.71 +28.27 +28.22 +28.31 +28.72 +28.26 +27.81 +26.75 +28.74 +27.73 +27.73 +28.72 +28.72 +28.72 +29.71 +28.26 +29.23 +29.23 +28.27 +27.73 +26.30 +25.91 +23.39 +21.78 +22.77 +27.37 +29.24 +24.38 +27.73 +28.72 +29.23 diff --git a/contrib/performance/1024x768_am7xxx_send_image_async.log b/contrib/performance/1024x768_am7xxx_send_image_async.log new file mode 100644 index 0000000..a2286cd --- /dev/null +++ b/contrib/performance/1024x768_am7xxx_send_image_async.log @@ -0,0 +1,51 @@ +46.89 +48.35 +48.85 +48.95 +48.78 +49.18 +49.48 +49.61 +49.85 +50.15 +50.24 +49.53 +51.15 +48.98 +47.42 +48.27 +49.07 +49.97 +49.38 +47.96 +49.70 +49.00 +42.21 +45.65 +49.18 +50.22 +49.65 +49.12 +50.50 +53.49 +53.22 +52.99 +53.95 +53.62 +53.98 +53.60 +54.64 +53.96 +54.92 +54.42 +53.65 +54.68 +52.16 +52.81 +53.74 +55.24 +55.50 +56.83 +56.43 +56.39 +57.70 diff --git a/contrib/performance/README b/contrib/performance/README new file mode 100644 index 0000000..c00b8db --- /dev/null +++ b/contrib/performance/README @@ -0,0 +1,7 @@ +Menchmark methodology + + - Code instrumented with fps-meter + - Data acquired with this commdn line: + am7xxx-play -f x11grab -i :0 -o video_size=1024x768 + - Sampling repeated with either am7xxx_send_image or am7xx_send_mage_async + - Results compared with ministat diff --git a/contrib/performance/ministat_report_1024x768.log b/contrib/performance/ministat_report_1024x768.log new file mode 100644 index 0000000..f3ab0a0 --- /dev/null +++ b/contrib/performance/ministat_report_1024x768.log @@ -0,0 +1,21 @@ +x 1024x768_am7xxx_send_image.log ++ 1024x768_am7xxx_send_image_async.log ++--------------------------------------------------------------------------+ +| x x + | +| xxx + | +| xxxx + | +| xxxx ++ | +| xxxx +++ + | +| xxxxx +++ ++ | +| x xxxxx +++ ++++ | +| xxxxxxx + ++++ +++++ + | +|x xxxxx xxxxxxxx + + ++++++++ ++++++ +++| +| |___AM__| |__M_A____| | ++--------------------------------------------------------------------------+ + N Min Max Median Avg Stddev +x 51 14.95 29.71 27.73 27.073529 2.4377185 ++ 51 42.21 57.7 50.22 51.278627 3.1996344 +Difference at 95.0% confidence + 24.2051 +/- 1.1175 + 89.405% +/- 4.12765% + (Student's t, pooled s = 2.8443) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index fface99..e44ed39 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.1.2 +# Doxyfile 1.8.4 #--------------------------------------------------------------------------- # Project related configuration options @@ -34,6 +34,7 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +AUTOLINK_SUPPORT = YES BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO @@ -43,7 +44,6 @@ SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO -SYMBOL_CACHE_SIZE = 0 LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options @@ -116,6 +116,7 @@ INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- @@ -142,6 +143,7 @@ HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 @@ -179,10 +181,17 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES USE_MATHJAX = NO +MATHJAX_FORMAT = HTML-CSS MATHJAX_RELPATH = http://www.mathjax.org/mathjax MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = SEARCHENGINE = YES SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- @@ -195,6 +204,7 @@ PAPER_TYPE = a4 EXTRA_PACKAGES = LATEX_HEADER = LATEX_FOOTER = +LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO @@ -226,6 +236,11 @@ XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- +# configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +#--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO @@ -255,6 +270,7 @@ TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool diff --git a/doc/DoxygenMainpage.dox b/doc/DoxygenMainpage.dox index 1754ea9..407cf1d 100644 --- a/doc/DoxygenMainpage.dox +++ b/doc/DoxygenMainpage.dox @@ -25,6 +25,8 @@ Check @link am7xxx.h @endlink for the public API documentation. - Aiptek PocketCinema T25 - Philips/SagemCom PicoPix 1020 - Philips/SagemCom PicoPix 2055 +- Philips/SagemCom PicoPix 2330 +- Top-Height/TEC PP700 @section libam7xxxDesignOverview Design Overview diff --git a/doc/lsusb_dumps/lsusb_Acer-C110.log b/doc/lsusb_dumps/lsusb_Acer-C110.log new file mode 100644 index 0000000..53f74e2 --- /dev/null +++ b/doc/lsusb_dumps/lsusb_Acer-C110.log @@ -0,0 +1,68 @@ + +Bus 004 Device 012: ID 1de1:c101 Actions Microelectronics Co. Generic Display Device +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 255 Vendor Specific Class + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x1de1 Actions Microelectronics Co. + idProduct 0xc101 Generic Display Device + bcdDevice 1.00 + iManufacturer 1 actions + iProduct 2 Usb Device + iSerial 3 00000000000000000000000000000000 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 32 + bNumInterfaces 1 + bConfigurationValue 2 + iConfiguration 6 PICO PROJECTOR + bmAttributes 0xc0 + Self Powered + MaxPower 2mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 8 + bInterfaceProtocol 8 + iInterface 7 USB PICO + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0001 + Self Powered diff --git a/doc/lsusb_dumps/lsusb_Philips-PicoPix-2330.log b/doc/lsusb_dumps/lsusb_Philips-PicoPix-2330.log new file mode 100644 index 0000000..fc57c0d --- /dev/null +++ b/doc/lsusb_dumps/lsusb_Philips-PicoPix-2330.log @@ -0,0 +1,68 @@ + +Bus 002 Device 004: ID 21e7:0019 +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 255 Vendor Specific Class + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x21e7 + idProduct 0x0019 + bcdDevice 0.00 + iManufacturer 1 actions-micro + iProduct 2 actions-subdisplay + iSerial 3 00000000000000000000000000000000 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 32 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 4 Self-powered + bmAttributes 0xc0 + Self Powered + MaxPower 2mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 5 vendor subdisp + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0200 1x 512 bytes + bInterval 1 +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0001 + Self Powered diff --git a/doc/man/CMakeLists.txt b/doc/man/CMakeLists.txt index ed46999..c7ce4bb 100644 --- a/doc/man/CMakeLists.txt +++ b/doc/man/CMakeLists.txt @@ -3,6 +3,7 @@ find_package(Asciidoc) if(ASCIIDOC_FOUND) add_custom_target(manpages ${ASCIIDOC_A2X_EXECUTABLE} -f manpage ${CMAKE_CURRENT_SOURCE_DIR}/am7xxx-play.1.txt -D ${DOC_OUTPUT_PATH}/man + COMMAND ${ASCIIDOC_A2X_EXECUTABLE} -f manpage ${CMAKE_CURRENT_SOURCE_DIR}/am7xxx-modeswitch.1.txt -D ${DOC_OUTPUT_PATH}/man COMMAND ${ASCIIDOC_A2X_EXECUTABLE} -f manpage ${CMAKE_CURRENT_SOURCE_DIR}/picoproj.1.txt -D ${DOC_OUTPUT_PATH}/man WORKING_DIRECTORY ${DOC_OUTPUT_PATH}/man COMMENT "Generating man pages with Asciidoc" VERBATIM @@ -17,6 +18,7 @@ if(ASCIIDOC_FOUND) install(FILES ${DOC_OUTPUT_PATH}/man/am7xxx-play.1 + ${DOC_OUTPUT_PATH}/man/am7xxx-modeswitch.1 ${DOC_OUTPUT_PATH}/man/picoproj.1 DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man1/" COMPONENT manpages) diff --git a/doc/man/am7xxx-modeswitch.1.txt b/doc/man/am7xxx-modeswitch.1.txt new file mode 100644 index 0000000..20dfd29 --- /dev/null +++ b/doc/man/am7xxx-modeswitch.1.txt @@ -0,0 +1,57 @@ +AM7XXX-MODESWITCH(1) +===================== +:doctype: manpage + + +NAME +---- +am7xxx-modeswitch - change the operational mode of am7xxx based devices + + +SYNOPSIS +-------- +*am7xxx-modeswitch* + + +DESCRIPTION +----------- +am7xxx-modeswitch(1) is a minimal replacement of usb-modeswitch to use with +am7xxx devices (e.g. Acer C110 or Philips PPX projectors) to switch from the +mass storage device mode to the generic display mode. + +It is handy on systems where usb-modeswitch is not available, like Windows. + + +EXAMPLE OF USE +-------------- + +am7xxx-modeswitch + + +EXIT STATUS +----------- +*0*:: + Success + +*!0*:: + Failure (libusb error) + + +AUTHORS +------- +Antonio Ospite + + +RESOURCES +--------- +Main web site: + + +COPYING +------- +Copyright \(C) 2012 Antonio Ospite + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 64f15c0..c77a812 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -62,16 +62,16 @@ if(BUILD_AM7XXX-PLAY) DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") endif() -# Build a simple usb_mode_switch clone for am7xxx devices -option(BUILD_AM7XXX_MODE_SWITCH "Build a simple usb_mode_switch clone for am7xxx devices" TRUE) -if(BUILD_AM7XXX_MODE_SWITCH) +# Build a simple usb-modeswitch clone for am7xxx devices +option(BUILD_am7xxx-modeswitch "Build a simple usbmode-switch clone for am7xxx devices" TRUE) +if(BUILD_am7xxx-modeswitch) find_package(libusb-1.0 REQUIRED) include_directories(${LIBUSB_1_INCLUDE_DIRS}) - add_executable(am7xxx_mode_switch am7xxx_mode_switch.c) - target_link_libraries(am7xxx_mode_switch ${LIBUSB_1_LIBRARIES}) - install(TARGETS am7xxx_mode_switch + add_executable(am7xxx-modeswitch am7xxx-modeswitch.c) + target_link_libraries(am7xxx-modeswitch ${LIBUSB_1_LIBRARIES}) + install(TARGETS am7xxx-modeswitch DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") endif() diff --git a/examples/am7xxx-modeswitch.c b/examples/am7xxx-modeswitch.c new file mode 100644 index 0000000..9942d81 --- /dev/null +++ b/examples/am7xxx-modeswitch.c @@ -0,0 +1,97 @@ +/* am7xxx-modeswitch - a simple usb-modeswitch for am7xxx devices + * + * Copyright (C) 2012 Antonio Ospite + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#define AM7XXX_STORAGE_VID 0x1de1 +#define AM7XXX_STORAGE_PID 0x1101 +#define AM7XXX_STORAGE_CONFIGURATION 1 +#define AM7XXX_STORAGE_INTERFACE 0 +#define AM7XXX_STORAGE_OUT_EP 0x01 + +static unsigned char switch_command[] = + "\x55\x53\x42\x43\x08\x70\x52\x89\x00\x00\x00\x00\x00\x00" + "\x0c\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + +int main(void) +{ + int ret; + int transferred; + libusb_device_handle *usb_device = NULL; + + unsigned int len; + + ret = libusb_init(NULL); + if (ret < 0) + goto out; + + libusb_set_debug(NULL, 3); + + usb_device = libusb_open_device_with_vid_pid(NULL, + AM7XXX_STORAGE_VID, + AM7XXX_STORAGE_PID); + if (usb_device == NULL) { + fprintf(stderr, "cannot open the device: %d.\n", errno); + ret = -errno; + goto out; + } + + if (libusb_kernel_driver_active(usb_device, AM7XXX_STORAGE_INTERFACE)) { + ret = libusb_detach_kernel_driver(usb_device, + AM7XXX_STORAGE_INTERFACE); + if (ret < 0) + fprintf(stderr, "Warning: cannot detach kernel driver.\n"); + } else { + fprintf(stderr, "kernel driver not active.\n"); + } + + ret = libusb_set_configuration(usb_device, AM7XXX_STORAGE_CONFIGURATION); + if (ret < 0) { + fprintf(stderr, "cannot set configuration.\n"); + goto out_libusb_close; + } + + ret = libusb_claim_interface(usb_device, AM7XXX_STORAGE_INTERFACE); + if (ret < 0) { + fprintf(stderr, "cannot claim interface.\n"); + goto out_libusb_close; + } + + len = sizeof(switch_command); + transferred = 0; + ret = libusb_bulk_transfer(usb_device, AM7XXX_STORAGE_OUT_EP, + switch_command, len, &transferred, 0); + if (ret != 0 || (unsigned int)transferred != len) { + fprintf(stderr, "ret: %d\ttransferred: %d (expected %u)\n", + ret, transferred, len); + goto out_libusb_release_interface; + } + + fprintf(stderr, "OK, command sent!\n"); + +out_libusb_release_interface: + libusb_release_interface(usb_device, AM7XXX_STORAGE_INTERFACE); +out_libusb_close: + libusb_close(usb_device); + usb_device = NULL; +out: + libusb_exit(NULL); + return ret; +} diff --git a/examples/am7xxx-play.c b/examples/am7xxx-play.c index 38812a4..3230e67 100644 --- a/examples/am7xxx-play.c +++ b/examples/am7xxx-play.c @@ -291,7 +291,7 @@ static int am7xxx_play(const char *input_format_string, AVPacket out_packet; int got_picture; int got_packet; - int ret = 0; + int ret; ret = video_input_init(&input_ctx, input_format_string, input_path, input_options); if (ret < 0) { @@ -427,7 +427,7 @@ static int am7xxx_play(const char *input_format_string, fclose(file); #endif - ret = am7xxx_send_image(dev, + ret = am7xxx_send_image_async(dev, image_format, (output_ctx.codec_ctx)->width, (output_ctx.codec_ctx)->height, @@ -440,7 +440,7 @@ static int am7xxx_play(const char *input_format_string, } } end_while: - if (!output_ctx.raw_output) + if (!output_ctx.raw_output && got_packet) av_free_packet(&out_packet); av_free_packet(&in_packet); } @@ -555,7 +555,7 @@ static int set_signal_handler(void (*signal_handler)(int)) { struct sigaction new_action; struct sigaction old_action; - int ret = 0; + int ret; new_action.sa_handler = signal_handler; sigemptyset(&new_action.sa_mask); @@ -635,8 +635,8 @@ int main(int argc, char *argv[]) unsigned int quality = 95; int log_level = AM7XXX_LOG_INFO; int device_index = 0; - am7xxx_power_mode power_mode = AM7XXX_POWER_LOW; - am7xxx_zoom_mode zoom = AM7XXX_ZOOM_ORIGINAL; + int power_mode = AM7XXX_POWER_LOW; + int zoom = AM7XXX_ZOOM_ORIGINAL; int format = AM7XXX_IMAGE_FORMAT_JPEG; am7xxx_context *ctx; am7xxx_device *dev; @@ -762,7 +762,8 @@ int main(int argc, char *argv[]) default: fprintf(stderr, "Invalid zoom mode value, must be between %d and %d\n", AM7XXX_ZOOM_ORIGINAL, AM7XXX_ZOOM_TEST); - exit(EXIT_FAILURE); + ret = -EINVAL; + goto out; } break; case 'h': @@ -777,7 +778,8 @@ int main(int argc, char *argv[]) } if (input_path == NULL) { - fprintf(stderr, "The -i option must always be passed\n"); + fprintf(stderr, "The -i option must always be passed\n\n"); + usage(argv[0]); ret = -EINVAL; goto out; } diff --git a/examples/am7xxx_mode_switch.c b/examples/am7xxx_mode_switch.c deleted file mode 100644 index 7509981..0000000 --- a/examples/am7xxx_mode_switch.c +++ /dev/null @@ -1,97 +0,0 @@ -/* am7xxx_mode_switch - a simple usb_mode_switch for am7xxx devices - * - * Copyright (C) 2012 Antonio Ospite - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include - -#define AM7XXX_STORAGE_VID 0x1de1 -#define AM7XXX_STORAGE_PID 0x1101 -#define AM7XXX_STORAGE_CONFIGURATION 1 -#define AM7XXX_STORAGE_INTERFACE 0 -#define AM7XXX_STORAGE_OUT_EP 0x01 - -static unsigned char switch_command[] = - "\x55\x53\x42\x43\x08\x70\x52\x89\x00\x00\x00\x00\x00\x00" - "\x0c\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - -int main(void) -{ - int ret; - int transferred; - libusb_device_handle *usb_device = NULL; - - unsigned int len; - - ret = libusb_init(NULL); - if (ret < 0) - goto out; - - libusb_set_debug(NULL, 3); - - usb_device = libusb_open_device_with_vid_pid(NULL, - AM7XXX_STORAGE_VID, - AM7XXX_STORAGE_PID); - if (usb_device == NULL) { - fprintf(stderr, "cannot open the device: %d.\n", errno); - ret = -errno; - goto out; - } - - if (libusb_kernel_driver_active(usb_device, AM7XXX_STORAGE_INTERFACE)) { - ret = libusb_detach_kernel_driver(usb_device, - AM7XXX_STORAGE_INTERFACE); - if (ret < 0) - fprintf(stderr, "Warning: cannot detach kernel driver.\n"); - } else { - fprintf(stderr, "kernel driver not active.\n"); - } - - ret = libusb_set_configuration(usb_device, AM7XXX_STORAGE_CONFIGURATION); - if (ret < 0) { - fprintf(stderr, "cannot set configuration.\n"); - goto out_libusb_close; - } - - ret = libusb_claim_interface(usb_device, AM7XXX_STORAGE_INTERFACE); - if (ret < 0) { - fprintf(stderr, "cannot claim interface.\n"); - goto out_libusb_close; - } - - len = sizeof(switch_command); - transferred = 0; - ret = libusb_bulk_transfer(usb_device, AM7XXX_STORAGE_OUT_EP, - switch_command, len, &transferred, 0); - if (ret != 0 || (unsigned int)transferred != len) { - fprintf(stderr, "ret: %d\ttransferred: %d (expected %u)\n", - ret, transferred, len); - goto out_libusb_close; - } - - fprintf(stderr, "OK, command sent!\n"); - -out_libusb_close: - libusb_release_interface(usb_device, AM7XXX_STORAGE_INTERFACE); - libusb_close(usb_device); - usb_device = NULL; - -out: - libusb_exit(NULL); - return ret; -} diff --git a/examples/picoproj.c b/examples/picoproj.c index 045f386..9128538 100644 --- a/examples/picoproj.c +++ b/examples/picoproj.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "am7xxx.h" @@ -58,7 +59,6 @@ static void usage(char *name) int main(int argc, char *argv[]) { int ret; - int exit_code = EXIT_SUCCESS; int opt; char filename[FILENAME_MAX] = {0}; @@ -68,13 +68,13 @@ int main(int argc, char *argv[]) am7xxx_device *dev; int log_level = AM7XXX_LOG_INFO; int device_index = 0; - am7xxx_power_mode power_mode = AM7XXX_POWER_LOW; - am7xxx_zoom_mode zoom = AM7XXX_ZOOM_ORIGINAL; + int power_mode = AM7XXX_POWER_LOW; + int zoom = AM7XXX_ZOOM_ORIGINAL; int format = AM7XXX_IMAGE_FORMAT_JPEG; int width = 800; int height = 480; unsigned char *image; - unsigned int size; + off_t size; am7xxx_device_info device_info; while ((opt = getopt(argc, argv, "d:f:F:l:p:z:W:H:h")) != -1) { @@ -83,7 +83,8 @@ int main(int argc, char *argv[]) device_index = atoi(optarg); if (device_index < 0) { fprintf(stderr, "Unsupported device index\n"); - exit(EXIT_FAILURE); + ret = -EINVAL; + goto out; } break; case 'f': @@ -102,7 +103,8 @@ int main(int argc, char *argv[]) break; default: fprintf(stderr, "Unsupported format\n"); - exit(EXIT_FAILURE); + ret = -EINVAL; + goto out; } break; case 'l': @@ -125,7 +127,8 @@ int main(int argc, char *argv[]) default: fprintf(stderr, "Invalid power mode value, must be between %d and %d\n", AM7XXX_POWER_OFF, AM7XXX_POWER_TURBO); - exit(EXIT_FAILURE); + ret = -EINVAL; + goto out; } break; case 'z': @@ -140,48 +143,53 @@ int main(int argc, char *argv[]) default: fprintf(stderr, "Invalid zoom mode value, must be between %d and %d\n", AM7XXX_ZOOM_ORIGINAL, AM7XXX_ZOOM_TEST); - exit(EXIT_FAILURE); + ret = -EINVAL; + goto out; } break; case 'W': width = atoi(optarg); if (width < 0) { fprintf(stderr, "Unsupported width\n"); - exit(EXIT_FAILURE); + ret = -EINVAL; + goto out; } break; case 'H': height = atoi(optarg); if (height < 0) { fprintf(stderr, "Unsupported height\n"); - exit(EXIT_FAILURE); + ret = -EINVAL; + goto out; } break; case 'h': usage(argv[0]); - exit(EXIT_SUCCESS); - break; + ret = 0; + goto out; default: /* '?' */ usage(argv[0]); - exit(EXIT_FAILURE); + ret = -EINVAL; + goto out; } } if (filename[0] == '\0') { - fprintf(stderr, "An image file MUST be specified.\n"); - exit_code = EXIT_FAILURE; + fprintf(stderr, "An image file MUST be specified with the -f option.\n\n"); + usage(argv[0]); + ret = -EINVAL; goto out; } image_fp = fopen(filename, "rb"); if (image_fp == NULL) { perror("fopen"); - exit_code = EXIT_FAILURE; + ret = -EINVAL; goto out; } - if (fstat(fileno(image_fp), &st) < 0) { + ret = fstat(fileno(image_fp), &st); + if (ret < 0) { perror("fstat"); - exit_code = EXIT_FAILURE; goto out_close_image_fp; } size = st.st_size; @@ -189,11 +197,11 @@ int main(int argc, char *argv[]) image = malloc(size * sizeof(unsigned char)); if (image == NULL) { perror("malloc"); - exit_code = EXIT_FAILURE; + ret = -ENOMEM; goto out_close_image_fp; } - ret = fread(image, size, 1, image_fp); + ret = (int)fread(image, size, 1, image_fp); if (ret != 1) { if (feof(image_fp)) fprintf(stderr, "Unexpected end of file.\n"); @@ -202,13 +210,14 @@ int main(int argc, char *argv[]) else fprintf(stderr, "Unexpected error condition.\n"); + if (ret >= 0) + ret = -EINVAL; goto out_free_image; } ret = am7xxx_init(&ctx); if (ret < 0) { perror("am7xxx_init"); - exit_code = EXIT_FAILURE; goto out_free_image; } @@ -217,29 +226,24 @@ int main(int argc, char *argv[]) ret = am7xxx_open_device(ctx, &dev, 0); if (ret < 0) { perror("am7xxx_open_device"); - exit_code = EXIT_FAILURE; goto cleanup; } - ret = am7xxx_close_device(dev); if (ret < 0) { perror("am7xxx_close_device"); - exit_code = EXIT_FAILURE; goto cleanup; } ret = am7xxx_open_device(ctx, &dev, device_index); if (ret < 0) { perror("am7xxx_open_device"); - exit_code = EXIT_FAILURE; goto cleanup; } ret = am7xxx_get_device_info(dev, &device_info); if (ret < 0) { perror("am7xxx_get_device_info"); - exit_code = EXIT_FAILURE; goto cleanup; } printf("Native resolution: %dx%d\n", @@ -248,14 +252,12 @@ int main(int argc, char *argv[]) ret = am7xxx_set_zoom_mode(dev, zoom); if (ret < 0) { perror("am7xxx_set_zoom_mode"); - exit_code = EXIT_FAILURE; goto cleanup; } ret = am7xxx_set_power_mode(dev, power_mode); if (ret < 0) { perror("am7xxx_set_power_mode"); - exit_code = EXIT_FAILURE; goto cleanup; } @@ -265,19 +267,19 @@ int main(int argc, char *argv[]) goto cleanup; } - if ((unsigned int)width > device_info.native_width || (unsigned int)height > device_info.native_height) - fprintf(stderr, "WARNING: image not fitting the native resolution, it may be displayed wrongly!\n"); + fprintf(stderr, + "WARNING: image is %dx%d, not fitting the native resolution, it may be displayed wrongly!\n", + width, height); - ret = am7xxx_send_image(dev, format, width, height, image, size); + ret = am7xxx_send_image(dev, format, width, height, image, (unsigned int)size); if (ret < 0) { perror("am7xxx_send_image"); - exit_code = EXIT_FAILURE; goto cleanup; } - exit_code = EXIT_SUCCESS; + ret = 0; cleanup: am7xxx_shutdown(ctx); @@ -286,10 +288,9 @@ out_free_image: free(image); out_close_image_fp: - ret = fclose(image_fp); - if (ret == EOF) + if (fclose(image_fp) == EOF) perror("fclose"); out: - exit(exit_code); + return ret; } diff --git a/src/am7xxx.c b/src/am7xxx.c index 83d9a91..5b1e35a 100644 --- a/src/am7xxx.c +++ b/src/am7xxx.c @@ -64,37 +64,61 @@ static void log_message(am7xxx_context *ctx, #define debug(ctx, ...) log_message(ctx, AM7XXX_LOG_DEBUG, __func__, 0, __VA_ARGS__) #define trace(ctx, ...) log_message(ctx, AM7XXX_LOG_TRACE, NULL, 0, __VA_ARGS__) +#define AM7XXX_QUIRK_NO_POWER_MODE (1 << 0) +#define AM7XXX_QUIRK_NO_ZOOM_MODE (1 << 1) + struct am7xxx_usb_device_descriptor { const char *name; uint16_t vendor_id; uint16_t product_id; + uint8_t configuration; /* The bConfigurationValue of the device */ + uint8_t interface_number; /* The bInterfaceNumber of the device */ + unsigned long quirks; }; -static struct am7xxx_usb_device_descriptor supported_devices[] = { +static const struct am7xxx_usb_device_descriptor supported_devices[] = { { .name = "Acer C110", .vendor_id = 0x1de1, .product_id = 0xc101, + .configuration = 2, + .interface_number = 0, }, { .name = "Acer C112", .vendor_id = 0x1de1, .product_id = 0x5501, + .configuration = 2, + .interface_number = 0, }, { .name ="Aiptek PocketCinema T25", .vendor_id = 0x08ca, .product_id = 0x2144, + .configuration = 2, + .interface_number = 0, }, { .name = "Philips/Sagemcom PicoPix 1020", .vendor_id = 0x21e7, .product_id = 0x000e, + .configuration = 2, + .interface_number = 0, }, { .name = "Philips/Sagemcom PicoPix 2055", .vendor_id = 0x21e7, .product_id = 0x0016, + .configuration = 2, + .interface_number = 0, + }, + { + .name = "Philips/Sagemcom PicoPix 2330", + .vendor_id = 0x21e7, + .product_id = 0x0019, + .configuration = 1, + .interface_number = 0, + .quirks = AM7XXX_QUIRK_NO_POWER_MODE | AM7XXX_QUIRK_NO_ZOOM_MODE, }, }; @@ -106,9 +130,12 @@ static struct am7xxx_usb_device_descriptor supported_devices[] = { struct _am7xxx_device { libusb_device_handle *usb_device; + struct libusb_transfer *transfer; + int transfer_completed; uint8_t buffer[AM7XXX_HEADER_WIRE_SIZE]; am7xxx_device_info *device_info; am7xxx_context *ctx; + const struct am7xxx_usb_device_descriptor *desc; am7xxx_device *next; }; @@ -347,6 +374,117 @@ static int send_data(am7xxx_device *dev, uint8_t *buffer, unsigned int len) return 0; } +static void send_data_async_complete_cb(struct libusb_transfer *transfer) +{ + am7xxx_device *dev = (am7xxx_device *)(transfer->user_data); + int *completed = &(dev->transfer_completed); + int transferred = transfer->actual_length; + int ret; + + if (transferred != transfer->length) { + error(dev->ctx, "transferred: %d (expected %u)\n", + transferred, transfer->length); + } + + switch (transfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + ret = 0; + break; + case LIBUSB_TRANSFER_TIMED_OUT: + ret = LIBUSB_ERROR_TIMEOUT; + break; + case LIBUSB_TRANSFER_STALL: + ret = LIBUSB_ERROR_PIPE; + break; + case LIBUSB_TRANSFER_OVERFLOW: + ret = LIBUSB_ERROR_OVERFLOW; + break; + case LIBUSB_TRANSFER_NO_DEVICE: + ret = LIBUSB_ERROR_NO_DEVICE; + break; + case LIBUSB_TRANSFER_ERROR: + case LIBUSB_TRANSFER_CANCELLED: + ret = LIBUSB_ERROR_IO; + break; + default: + error(dev->ctx, "unrecognised status code %d", transfer->status); + ret = LIBUSB_ERROR_OTHER; + } + + if (ret < 0) + error(dev->ctx, "libusb transfer failed: %s", + libusb_error_name(ret)); + + libusb_free_transfer(transfer); + transfer = NULL; + + *completed = 1; +} + +static inline void wait_for_trasfer_completed(am7xxx_device *dev) +{ + while (!dev->transfer_completed) { + int ret = libusb_handle_events_completed(dev->ctx->usb_context, + &(dev->transfer_completed)); + if (ret < 0) { + if (ret == LIBUSB_ERROR_INTERRUPTED) + continue; + error(dev->ctx, "libusb_handle_events failed: %s, cancelling transfer and retrying", + libusb_error_name(ret)); + libusb_cancel_transfer(dev->transfer); + continue; + } + } +} + +static int send_data_async(am7xxx_device *dev, uint8_t *buffer, unsigned int len) +{ + int ret; + uint8_t *transfer_buffer; + + dev->transfer = libusb_alloc_transfer(0); + if (dev->transfer == NULL) { + error(dev->ctx, "cannot allocate transfer (%s)\n", + strerror(errno)); + return -ENOMEM; + } + + /* Make a copy of the buffer so the caller can safely reuse it just + * after libusb_submit_transfer() has returned. This technique + * requires more allocations than a proper double-buffering approach + * but it takes a lot less code. */ + transfer_buffer = malloc(len); + if (transfer_buffer == NULL) { + error(dev->ctx, "cannot allocate transfer buffer (%s)\n", + strerror(errno)); + ret = -ENOMEM; + goto err; + } + memcpy(transfer_buffer, buffer, len); + + dev->transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER; + libusb_fill_bulk_transfer(dev->transfer, dev->usb_device, 0x1, + transfer_buffer, len, + send_data_async_complete_cb, dev, 0); + + /* wait for the previous transfer to complete */ + wait_for_trasfer_completed(dev); + + trace_dump_buffer(dev->ctx, "sending -->", buffer, len); + + dev->transfer_completed = 0; + ret = libusb_submit_transfer(dev->transfer); + if (ret < 0) + goto err; + + return 0; + +err: + libusb_free_transfer(dev->transfer); + dev->transfer = NULL; + return ret; +} + static void serialize_header(struct am7xxx_header *h, uint8_t *buffer) { uint8_t **buffer_iterator = &buffer; @@ -451,7 +589,8 @@ static void log_message(am7xxx_context *ctx, return; } -static am7xxx_device *add_new_device(am7xxx_context *ctx) +static am7xxx_device *add_new_device(am7xxx_context *ctx, + const struct am7xxx_usb_device_descriptor *desc) { am7xxx_device **devices_list; am7xxx_device *new_device; @@ -469,6 +608,8 @@ static am7xxx_device *add_new_device(am7xxx_context *ctx) memset(new_device, 0, sizeof(*new_device)); new_device->ctx = ctx; + new_device->desc = desc; + new_device->transfer_completed = 1; devices_list = &(ctx->devices_list); @@ -526,7 +667,7 @@ typedef enum { static int scan_devices(am7xxx_context *ctx, scan_op op, unsigned int open_device_index, am7xxx_device **dev) { - int num_devices; + ssize_t num_devices; libusb_device** list; unsigned int current_index; int i; @@ -565,7 +706,7 @@ static int scan_devices(am7xxx_context *ctx, scan_op op, info(ctx, "am7xxx device found, index: %d, name: %s\n", current_index, supported_devices[j].name); - new_device = add_new_device(ctx); + new_device = add_new_device(ctx, &supported_devices[j]); if (new_device == NULL) { /* XXX, the caller may want * to call am7xxx_shutdown() if @@ -598,8 +739,32 @@ static int scan_devices(am7xxx_context *ctx, scan_op op, goto out; } - libusb_set_configuration((*dev)->usb_device, 2); - libusb_claim_interface((*dev)->usb_device, 0); + /* XXX, the device is now open, if any + * of the calls below fail we need to + * close it again before bailing out. + */ + + ret = libusb_set_configuration((*dev)->usb_device, + (*dev)->desc->configuration); + if (ret < 0) { + debug(ctx, "libusb_set_configuration failed\n"); + debug(ctx, "Cannot set configuration %hhu\n", + (*dev)->desc->configuration); + goto out_libusb_close; + } + + ret = libusb_claim_interface((*dev)->usb_device, + (*dev)->desc->interface_number); + if (ret < 0) { + debug(ctx, "libusb_claim_interface failed\n"); + debug(ctx, "Cannot claim interface %hhu\n", + (*dev)->desc->interface_number); +out_libusb_close: + libusb_close((*dev)->usb_device); + (*dev)->usb_device = NULL; + goto out; + } + goto out; } current_index++; @@ -625,7 +790,7 @@ out: AM7XXX_PUBLIC int am7xxx_init(am7xxx_context **ctx) { - int ret = 0; + int ret; *ctx = malloc(sizeof(**ctx)); if (*ctx == NULL) { @@ -642,7 +807,7 @@ AM7XXX_PUBLIC int am7xxx_init(am7xxx_context **ctx) if (ret < 0) goto out_free_context; - libusb_set_debug((*ctx)->usb_context, 3); + libusb_set_debug((*ctx)->usb_context, LIBUSB_LOG_LEVEL_INFO); ret = scan_devices(*ctx, SCAN_OP_BUILD_DEVLIST , 0, NULL); if (ret < 0) { @@ -735,7 +900,8 @@ AM7XXX_PUBLIC int am7xxx_close_device(am7xxx_device *dev) return -EINVAL; } if (dev->usb_device) { - libusb_release_interface(dev->usb_device, 0); + wait_for_trasfer_completed(dev); + libusb_release_interface(dev->usb_device, dev->desc->interface_number); libusb_close(dev->usb_device); dev->usb_device = NULL; } @@ -899,6 +1065,42 @@ AM7XXX_PUBLIC int am7xxx_send_image(am7xxx_device *dev, return send_data(dev, image, image_size); } +AM7XXX_PUBLIC int am7xxx_send_image_async(am7xxx_device *dev, + am7xxx_image_format format, + unsigned int width, + unsigned int height, + uint8_t *image, + unsigned int image_size) +{ + int ret; + struct am7xxx_header h = { + .packet_type = AM7XXX_PACKET_TYPE_IMAGE, + .direction = AM7XXX_DIRECTION_OUT, + .header_data_len = sizeof(struct am7xxx_image_header), + .unknown2 = 0x3e, + .unknown3 = 0x10, + .header_data = { + .image = { + .format = format, + .width = width, + .height = height, + .image_size = image_size, + }, + }, + }; + + ret = send_header(dev, &h); + if (ret < 0) + return ret; + + if (image == NULL || image_size == 0) { + warning(dev->ctx, "Not sending any data, check the 'image' or 'image_size' parameters\n"); + return 0; + } + + return send_data_async(dev, image, image_size); +} + AM7XXX_PUBLIC int am7xxx_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power) { int ret; @@ -910,6 +1112,12 @@ AM7XXX_PUBLIC int am7xxx_set_power_mode(am7xxx_device *dev, am7xxx_power_mode po .unknown3 = 0x10, }; + if (dev->desc->quirks & AM7XXX_QUIRK_NO_POWER_MODE) { + debug(dev->ctx, + "setting power mode is unsupported on this device\n"); + return 0; + } + switch(power) { case AM7XXX_POWER_OFF: h.header_data.power.bit2 = 0; @@ -964,6 +1172,12 @@ AM7XXX_PUBLIC int am7xxx_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom .unknown3 = 0x10, }; + if (dev->desc->quirks & AM7XXX_QUIRK_NO_ZOOM_MODE) { + debug(dev->ctx, + "setting zoom mode is unsupported on this device\n"); + return 0; + } + switch(zoom) { case AM7XXX_ZOOM_ORIGINAL: h.header_data.zoom.bit1 = 0; diff --git a/src/am7xxx.h b/src/am7xxx.h index 24636c3..ec9869d 100644 --- a/src/am7xxx.h +++ b/src/am7xxx.h @@ -219,7 +219,7 @@ int am7xxx_calc_scaled_image_dimensions(am7xxx_device *dev, unsigned int *scaled_width, unsigned int *scaled_height); /** - * Send an image for display on a am7xxx device. + * Send an image for display on an am7xxx device. * * This is the function that actually makes the device display something. * Static pictures can be sent just once and the device will keep showing them @@ -242,6 +242,32 @@ int am7xxx_send_image(am7xxx_device *dev, unsigned int image_size); /** + * Queue transfer of an image for display on an am7xxx device and return immediately. + * + * This is the function that actually makes the device display something. + * Static pictures can be sent just once and the device will keep showing them + * until another image get sent or some command resets or turns off the display. + * + * @note This _async() variant makes a copy of the image buffer, so the caller + * is free to reuse the buffer just after the function returns. + * + * @param[in] dev A pointer to the structure representing the device to get info of + * @param[in] format The format the image is in (see @link am7xxx_image_format @endlink enum) + * @param[in] width The width of the image + * @param[in] height The height of the image + * @param[in] image A buffer holding data in the format specified by the format parameter + * @param[in] image_size The size in bytes of the image buffer + * + * @return 0 on success, a negative value on error + */ +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); + +/** * Set the power mode of an am7xxx device. * * @note When setting the mode to AM7XXX_POWER_OFF the display can't be turned