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}")
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
-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)
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()
+2013-07-28 11:15:18 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * Release version 0.1.4 (HEAD, master)
+
+2013-07-28 01:11:42 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * contrib: add some benchmarking data about am7xxx_send_image_async (origin/master)
+
+2013-07-28 00:50:30 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx-play: fix a crash when a packet cannot be encoded
+
+2013-07-28 00:38:13 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx-play: don't initialize variables when not needed
+
+2013-07-28 00:19:04 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * TODO: mention that atoi() must go away
+
+2013-07-28 00:10:08 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * picoproj: get rid of exit(), return more meaningful values to userspace
+
+2013-07-27 23:47:26 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * HACKING.asciidoc: add commands to compile with clang
+
+2013-07-27 23:44:45 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * HACKING.asciidoc: add an example of testing am7xxx-play with valgrind
+
+2013-07-27 23:36:08 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * doc: update Doxyfile.in
+
+2013-07-27 23:27:01 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * contrib: add a udev rule to invoke am7xxx-modeswitch
+
+2013-07-27 23:25:34 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * Rename am7xxx_mode_switch to am7xxx-modeswitch
+
+2013-07-27 23:02:34 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * TODO: mention that data types could be improved in the API
+
+2013-07-27 23:01:16 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * picoporj: fix another -Wshorten-64-to-32 warning from clang
+
+2013-07-27 22:55:53 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * picoproj: silence a -Wshorten-64-to-32 warning from clang
+
+2013-07-27 22:53:19 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * CMakeLists.txt: disable -Wsign-conversion warnings
+
+2013-07-27 21:33:28 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: fix a clang warning
+
+2013-07-27 20:55:48 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * examples: silence a couple of clang warnings
+
+2013-07-27 20:26:06 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * doc: mention the Top-Height/TEC PP700 in the Doxygen documentation
+
+2013-07-27 20:23:30 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * doc: add some lsusb dumps for reference
+
+2013-07-21 00:13:33 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx-play: use am7xxx_send_image_async() (local-ao2)
+
+2013-07-21 00:10:28 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: implement am7xxx_send_image_async()
+
+2013-07-14 13:25:25 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: fix a typo in a comment s/a am7xxx device/an am7xxx device/
+
+2013-07-13 11:05:00 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * CMakeLists.txt: enable two new compiler warnings
+
+2013-06-30 00:22:07 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: add quirks for devices not supporting some operations
+
+2013-06-30 00:20:51 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * picoproj: remove an unreachable break statement
+
+2013-06-30 00:15:30 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx-play: uniform coding style
+
+2013-06-30 00:12:59 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * CMakeLists.txt: add support for clang and isolate gcc-only options
+
+2013-06-29 23:11:57 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * HACKING.asciidoc: mention the patch needed for older libav/ffmpeg
+
+2013-06-29 23:02:13 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * README.asciidoc: mention the TEC PP700 projector as supported
+
+2013-05-27 00:06:23 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * picoproj: remove an unneeded blank line
+
+2013-05-27 00:05:00 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * examples: print the usage message when a required option is missing
+
+2013-05-26 23:53:13 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * CMakeLists.txt: fix enabling verbose debug output
+
+2013-04-05 23:35:34 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: use the symbolic constant for libusb log level
+
+2013-04-05 23:29:58 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * picoproj: show the image resolution when image does not fit the native one
+
+2013-04-05 23:28:24 +0200 Antonio Ospite <ospite@studenti.unina.it>
+
+ * picoproj: remove one of two consecutive blank lines
+
+2013-03-25 23:04:03 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * doc, contrib: add PicoPix 2330 to the list of supported devices
+
+2013-03-25 22:47:21 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: add support for Philips/Sagemcom PicoPix 2330
+
+2013-03-25 22:44:35 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * Merge branch 'per-device-usb-config'
+
+2013-03-23 23:30:54 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: make the supported_device array const
+
+2013-03-23 22:55:04 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: improve setting USB configuration and interface_number
+
+2012-11-14 15:41:48 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: reference am7xxx_usb_device_descriptor in struct _am7xxx_device
+
+2013-03-23 22:40:25 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx: fail if USB configuration or interface are not right
+
+2013-03-23 23:03:48 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * am7xxx_mode_switch: release interface only if claimed
+
+2013-03-14 23:04:20 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * doc: add a man page for am7xxx_mode_switch
+
+2013-03-15 00:13:21 +0100 Antonio Ospite <ospite@studenti.unina.it>
+
+ * Add a NEWS file
+
2013-03-14 20:23:49 +0100 Antonio Ospite <ospite@studenti.unina.it>
- * 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 <ospite@studenti.unina.it>
- * 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 <ospite@studenti.unina.it>
2012-03-28 13:37:00 +0200 Antonio Ospite <ospite@studenti.unina.it>
- * 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 <ospite@studenti.unina.it>
2012-03-28 10:55:14 +0200 Antonio Ospite <ospite@studenti.unina.it>
- * 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 <ospite@studenti.unina.it>
2012-03-26 13:50:05 +0200 Antonio Ospite <ospite@studenti.unina.it>
- * 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 <ospite@studenti.unina.it>
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
$ 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:
$ 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
--- /dev/null
+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)
--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:
* 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
- '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.
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.
+- 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.)
--- /dev/null
+# 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"
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"
--- /dev/null
+From dc6b216ffea1e80fd3f43d6144eb679a193f5666 Mon Sep 17 00:00:00 2001
+From: Antonio Ospite <ospite@studenti.unina.it>
+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<pyWR#k60!#=#>/Vb;]yA5<GWI5`6u&+
+ ;6b'@y|8w"wB;4/e!7wYYrcqdJFY,~%Gk_4]cq$Ei/7<j&N3ah(m`ku?pX.&+~:_/wC~dwn^)MizBG
+ !pE^+iDQQ1yC6^,)YDKkxDd!T>\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 <libswscale/swscale.h>
+
+ #include <am7xxx.h>
++#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
+
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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)
-# Doxyfile 1.8.1.2
+# Doxyfile 1.8.4
#---------------------------------------------------------------------------
# Project related configuration options
OPTIMIZE_OUTPUT_VHDL = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
+AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
-SYMBOL_CACHE_SIZE = 0
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
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
#---------------------------------------------------------------------------
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
+LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
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
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
+EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
- Aiptek PocketCinema T25
- Philips/SagemCom PicoPix 1020
- Philips/SagemCom PicoPix 2055
+- Philips/SagemCom PicoPix 2330
+- Top-Height/TEC PP700
@section libam7xxxDesignOverview Design Overview
--- /dev/null
+
+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
--- /dev/null
+
+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
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
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)
--- /dev/null
+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: <http://git.ao2.it/libam7xxx.git>
+
+
+COPYING
+-------
+Copyright \(C) 2012 Antonio Ospite <ospite@studenti.unina.it>
+
+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.
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()
--- /dev/null
+/* am7xxx-modeswitch - a simple usb-modeswitch for am7xxx devices
+ *
+ * Copyright (C) 2012 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <libusb.h>
+
+#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;
+}
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) {
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,
}
}
end_while:
- if (!output_ctx.raw_output)
+ if (!output_ctx.raw_output && got_packet)
av_free_packet(&out_packet);
av_free_packet(&in_packet);
}
{
struct sigaction new_action;
struct sigaction old_action;
- int ret = 0;
+ int ret;
new_action.sa_handler = signal_handler;
sigemptyset(&new_action.sa_mask);
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;
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':
}
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;
}
+++ /dev/null
-/* am7xxx_mode_switch - a simple usb_mode_switch for am7xxx devices
- *
- * Copyright (C) 2012 Antonio Ospite <ospite@studenti.unina.it>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <errno.h>
-#include <libusb.h>
-
-#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;
-}
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <errno.h>
#include "am7xxx.h"
int main(int argc, char *argv[])
{
int ret;
- int exit_code = EXIT_SUCCESS;
int opt;
char filename[FILENAME_MAX] = {0};
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) {
device_index = atoi(optarg);
if (device_index < 0) {
fprintf(stderr, "Unsupported device index\n");
- exit(EXIT_FAILURE);
+ ret = -EINVAL;
+ goto out;
}
break;
case 'f':
break;
default:
fprintf(stderr, "Unsupported format\n");
- exit(EXIT_FAILURE);
+ ret = -EINVAL;
+ goto out;
}
break;
case 'l':
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':
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;
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");
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;
}
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",
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;
}
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);
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;
}
#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,
},
};
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;
};
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;
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;
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);
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;
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
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++;
AM7XXX_PUBLIC int am7xxx_init(am7xxx_context **ctx)
{
- int ret = 0;
+ int ret;
*ctx = malloc(sizeof(**ctx));
if (*ctx == NULL) {
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) {
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;
}
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;
.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;
.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;
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
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