pax_global_header00006660000000000000000000000064132460267060014520gustar00rootroot0000000000000052 comment=d99323d05c42e148a8f1748504e4abd4694359e6 libam7xxx-0.1.7/000077500000000000000000000000001324602670600134505ustar00rootroot00000000000000libam7xxx-0.1.7/.gitignore000066400000000000000000000000261324602670600154360ustar00rootroot00000000000000*~ *.swp *.o picoproj libam7xxx-0.1.7/CMakeLists.txt000066400000000000000000000056321324602670600162160ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.6) project(libam7xxx C) set(PROJECT_DESCRIPTION "Communication library for Actions Micro AM7XXX based USB projectors and DPFs") set(PROJECT_VER_MAJOR 0) set(PROJECT_VER_MINOR 1) set(PROJECT_VER_PATCH 5) set(PROJECT_VER_EXTRA "") set(PROJECT_VER "${PROJECT_VER_MAJOR}.${PROJECT_VER_MINOR}.${PROJECT_VER_PATCH}${PROJECT_VER_EXTRA}") set(PROJECT_APIVER "${PROJECT_VER_MAJOR}.${PROJECT_VER_MINOR}") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/") OPTION(STRICT_COMPILATION_CHECKS "Enable stricter compilation checks" OFF) include (MaintenanceTools) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) set(DOC_OUTPUT_PATH ${CMAKE_BINARY_DIR}/doc) # Because cmake cannot deal sanely with multiline strings. SRSLY? # See http://www.vtkedge.org/Bug/view.php?id=8362&nbn=8 macro(add_flags var) string(REPLACE ";" " " _flags "${ARGN}") set(${var} "${${var}} ${_flags}") endmacro(add_flags) 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 if(CMAKE_C_FLAGS STREQUAL "") set(CMAKE_C_FLAGS "-std=c99 -pedantic -Wall -Wextra") endif() add_flags(CMAKE_C_FLAGS -fvisibility=hidden -fno-common -Wall -Wextra -Wformat=2 -Winit-self -Winline -Wpacked -Wpointer-arith -Wlarger-than-65500 -Wmissing-declarations -Wmissing-format-attribute -Wmissing-noreturn -Wmissing-prototypes -Wnested-externs -Wold-style-definition -Wredundant-decls -Wsign-compare -Wstrict-aliasing=2 -Wstrict-prototypes -Wswitch-enum -Wundef -Wunreachable-code -Wwrite-strings -fstack-protector) add_flags(DEBUG_FLAGS -ggdb) 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) 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() set(CMAKE_C_FLAGS_DEBUG "-O0 -DDEBUG=1 ${DEBUG_FLAGS} ${STRICT_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "-O2 ${RELEASE_FLAGS} ${STRICT_FLAGS}") set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 ${RELEASE_FLAGS} ${DEBUG_FLAGS} ${STRICT_FLAGS}") # Add library project add_subdirectory(src) add_subdirectory(examples) add_subdirectory(doc) libam7xxx-0.1.7/GPL-2000066400000000000000000000432541324602670600141640ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. libam7xxx-0.1.7/HACKING.asciidoc000066400000000000000000000056441324602670600162250ustar00rootroot00000000000000== Hacking libam7xxx === Coding style libam7xxx uses the linux kernel coding style: http://kernel.org/doc/Documentation/CodingStyle === Getting and compiling libam7xxx libam7xxx depends on 'libusb-1.0' and optionally on 'libav' or 'ffmpeg' (3.1+) for its example programs, the build system used is 'cmake'. On a Debian based system, the dependencies can be installed with this command: $ sudo aptitude install cmake \ libusb-1.0-0-dev \ libavformat-dev \ libavcodec-dev \ libavdevice-dev \ libswscale-dev \ libxcb1-dev With libav/ffmpeg version previous than 0.9 this patch is needed: https://git.ao2.it/libam7xxx.git/blob/6d2d8613958e1f0ef011e9d848426086caafe9db:/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 $ cd libam7xxx $ mkdir build $ cd build $ cmake ../ $ make After that the example programs can be found in the +bin/+ subdirectory. === Debug builds The suggested way to hack on the project is: $ mkdir build $ cd build $ cmake -D CMAKE_BUILD_TYPE=debug -D STRICT_COMPILATION_CHECKS=ON ../ $ make If you want to check the code with the ''sparse'' static analysis tool you can run: $ mkdir build $ cd build $ 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: $ sudo aptitude install mingw-w64 $ mkdir build $ cd build $ wget -nv https://github.com/libusb/libusb/releases/download/v1.0.21/libusb-1.0.21.7z $ 7z -olibusb-1.0.21 x libusb-1.0.21.7z $ wget -nv https://ffmpeg.zeranoe.com/builds/win32/dev/ffmpeg-3.4.2-win32-dev.zip $ unzip ffmpeg-3.4.2-win32-dev.zip $ cmake \ -D GNU_HOST=i686-w64-mingw32 \ -D CMAKE_TOOLCHAIN_FILE=../cmake_modules/mingw_cross_toolchain.cmake \ -D CMAKE_INSTALL_PREFIX=libam7xxx-win/ \ -D LIBUSB_1_INCLUDE_DIR=libusb-1.0.21/include/libusb-1.0 \ -D LIBUSB_1_LIBRARY=libusb-1.0.21/MinGW32/dll/libusb-1.0.dll \ -D FFMPEG_ROOT=$(pwd)/ffmpeg-3.4.2-win32-dev \ ../ $ make After that you will find libam7xxx.dll in lib/ and picoproj.exe in the bin/ directory. === Valgrind You can run the test program under the http://valgrind.org/[valgrind] 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 libam7xxx-0.1.7/NEWS000066400000000000000000000061761324602670600141610ustar00rootroot00000000000000News for v0.1.7: ================ * Fix FFMpeg deprecation warnings, the code now depends on FFMpeg 3.1+ * Fix compilation on Windows * Update the Windows build instructions in HACKING.asciidoc * Add a HOWTO for new users in contrib/howto-picopix.asciidoc * Add a patch to contrib/ to allow compiling libam7xxx on Ubuntu 14.04 LTS * Make sure am7xxx_get_device_info() always returns sensible values * Fix warnings about _BSD_SOURCE deprecation * Misc code and build system cleanups News for v0.1.6: ================ * Fix some ffmpeg compile time deprecation warnings in am7xxx-play * Fix some fmmpeg runtime warnings * Don't dump the last frame unconditionally in am7xxx-play when in DEBUG mode, add an option to enable the frame dump, but this is only active in DEBUG mode * Fix some compilation warnings from clang * Replace deprecated FFmpeg API symbol PIX_FMT_NV12 in am7xxx-play (Thanks to Andreas Cadhalpun) * Fix the Length field in the switch command in am7xxx-modeswitch (Thanks to Balasubramanian S) * More robust handling of USB configurations * More robust handling of kernel driver detachment (Thanks to Andrea Console) * Minor documentation cleanups * Minor build system improvements (am7xxx-play can now build without XCB, but some functionalities will not be available) * Misc code cleanups * Relicense the example under GPL-3+ News for v0.1.5: ================ * Add support for setting the power mode (i.e. brightness) on the Philips PicoPix 2055 (Thanks to Luca Bompani) * Add support for the "Tele" zoom mode available on the PicoPix 2055 (Thanks to Luca Bompani) * Fix compilation on Mac OSX * Port am7xxx-play to libav10 * Update instructions about compiling on Windows News for v0.1.4: ================ * Improved USB device configuration in order to support more 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) libam7xxx-0.1.7/README.asciidoc000066400000000000000000000113011324602670600161010ustar00rootroot00000000000000= libam7xxx libam7xxx is an Open Source library to communicate via USB with projectors and Digital Picture Frames based on the Actions Micro AM7XXX family if ICs. libam7xxx makes it possible to use these devices as USB displays on non-Windows Operating Systems like GNU/Linux or Android/Linux just to name a few, and on non-PC platforms like for instance mobile phones, tablets or game consoles. The first driver supporting these devices was _acerc11xdrv_ from Reto Schneider: https://github.com/rettichschnidi/acerc11xdrv Another project with the same purpose is _acerc110_ from Thomas Baquet: https://github.com/lordblackfox/acerc110 == AM7XXX An overview of some AM7XXX chips (AM7211A AM7212 AM7212P AM7318 AM7213D AM7213V) can be found in http://www.actions-micro.com/dpf_psg.pdf An example of datasheet illustrating the functionalities of such ICs (AM7531) is at: http://wenku.baidu.com/view/543c8b4d852458fb770b56ee.html == Supported devices The devices supported by libam7xxx use USB bulk transfers and a simple packet based protocol to exchange data and commands to and from a host system and the AM7XXX chip. Devices based on Actions Micro/Action Media designs generally use the USB VendorID +1de1+, and they can have two operational modes: - USB Mass Storage mode (e.g. ProductID: +1101+) - Generic bulk data transfer mode, or Display mode (e.g. ProductID: +c101+) On recent GNU/Linux systems the switch from Mass Storage mode to Display mode is performed automatically by http://www.draisberghof.de/usb_modeswitch/[USB_ModeSwitch], or can be done manually with the command: $ sudo usb_modeswitch \ --default-vendor 0x1de1 \ --default-product 0x1101 \ --message-content 55534243087052890000000000000cff020000000000000000000000000000 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: - Acer Series C pico projectors (C20, C110, C112): * http://www.acer.it/ac/it/IT/content/models/projector-c * http://support.acer.com/product/default.aspx?modelId=3888 - Philips/SagemCom PicoPix projectors (PPX 1020, PPX 1230, PPX 1430, PPX 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 - Aiptek PocketCinema T25: * http://www.aiptek.eu/index.php/en/products/pico-projectors/pocketcinema-t25 - Other unbranded projectors: * http://www.dealextreme.com/p/portable-home-office-mini-usb-2-0-lcos-projector-16-9-45019 - HannSpree digital picture frames (but it has not been verified yet if those can be actually used as USB displays): * http://europe.hannspree.net/onweb.jsp?prod_no=3333333621&webno=3333333317 * http://europe.hannspree.net/onweb.jsp?prod_no=33333337:4&webno=3333333317 Maybe other devices reported as supporting "Display over USB (DoUSB)" like Acer K330 or some Optoma projectors could be used with this library, but this needs still needs to be verified. == Testing libam7xxx on MS Windows All the needed files below must be in the same location: - 'MinGW32/dll/libusb-1.0.dll' from https://github.com/libusb/libusb/releases/download/v1.0.21/libusb-1.0.21.7z - 'libssp-0.dll' from MinGW; - all the '*.dll' files in the 'bin/' directory from https://ffmpeg.zeranoe.com/builds/win32/shared/ffmpeg-3.4.2-win32-shared.zip - 'am7xxx-modeswitch.exe', 'am7xxx-play.exe', 'libam7xxx.dll' and 'picoproj.exe' which can all be built by following the instructions in the HACKING.asciidoc document from libam7xxx. In order to use the device on MS Windows the WinUSB drivers must be installed for both the mass storage device and the display device: - Download http://sourceforge.net/projects/libwdi/files/zadig/[Zadig], it is a tool to install and replace USB devices filter drivers on MS Windows. - From Zadig, select the USB Mass Storage Device relative to the projector and replace the +USBSTOR+ driver with the +WinUSB+ one; keep in mind that from now on the virtual CD-ROM can't be accessed anymore until the +USBSTOR+ Driver is restored. - Run 'am7xxx-modeswitch.exe' - When the new (display) device shows up, run Zadig and install the +WinUSB+ driver for it too. Now it is possible to run 'picoproj.exe' or 'am7xxx-play.exe' on Windows. libam7xxx-0.1.7/TODO000066400000000000000000000011661324602670600141440ustar00rootroot00000000000000- 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.) - uniform the style of if() checks in cmake files - evaluate the use of error() instead of debug() for error paths - make the switch_command in am7xxx-modeswitch more readable using the explicit bulk_cb_wrap structure from include/linux/usb/storage.h in the linux kernel. libam7xxx-0.1.7/cmake_modules/000077500000000000000000000000001324602670600162605ustar00rootroot00000000000000libam7xxx-0.1.7/cmake_modules/FindAsciidoc.cmake000066400000000000000000000016221324602670600216020ustar00rootroot00000000000000# - Find Asciidoc # this module looks for asciidoc # # ASCIIDOC_EXECUTABLE - the full path to asciidoc # ASCIIDOC_A2X_EXECUTABLE - the full path to asciidoc's a2x # ASCIIDOC_FOUND - If false, don't attempt to use asciidoc. # # Taken from: # http://lissyx.dyndns.org/redmine/projects/qpdfpresenterconsole/repository/revisions/master/raw/cmake/FindAsciidoc.cmake FIND_PROGRAM(ASCIIDOC_EXECUTABLE asciidoc) FIND_PROGRAM(ASCIIDOC_A2X_EXECUTABLE a2x) MARK_AS_ADVANCED( ASCIIDOC_EXECUTABLE ASCIIDOC_A2X_EXECUTABLE ) IF ((NOT ASCIIDOC_EXECUTABLE) OR (NOT ASCIIDOC_A2X_EXECUTABLE)) SET(ASCIIDOC_FOUND "NO") ELSE ((NOT ASCIIDOC_EXECUTABLE) OR (NOT ASCIIDOC_A2X_EXECUTABLE)) SET(ASCIIDOC_FOUND "YES") ENDIF ((NOT ASCIIDOC_EXECUTABLE) OR (NOT ASCIIDOC_A2X_EXECUTABLE)) IF (NOT ASCIIDOC_FOUND AND Asciidoc_FIND_REQUIRED) MESSAGE(FATAL_ERROR "Could not find asciidoc") ENDIF (NOT ASCIIDOC_FOUND AND Asciidoc_FIND_REQUIRED) libam7xxx-0.1.7/cmake_modules/FindFFmpeg.cmake000066400000000000000000000110461324602670600212310ustar00rootroot00000000000000# Locate ffmpeg # This module defines # FFMPEG_LIBRARIES # FFMPEG_FOUND, if false, do not try to link to ffmpeg # FFMPEG_INCLUDE_DIR, where to find the headers # # $FFMPEG_DIR is an environment variable that would # correspond to the ./configure --prefix=$FFMPEG_DIR # # Created by Robert Osfield. #In ffmpeg code, old version use "#include " and newer use "#include " #In OSG ffmpeg plugin, we use "#include " for compatibility with old version of ffmpeg #We have to search the path which contain the header.h (usefull for old version) #and search the path which contain the libname/header.h (usefull for new version) #Then we need to include ${FFMPEG_libname_INCLUDE_DIRS} (in old version case, use by ffmpeg header and osg plugin code) # (in new version case, use by ffmpeg header) #and ${FFMPEG_libname_INCLUDE_DIRS/libname} (in new version case, use by osg plugin code) # Macro to find header and lib directories # example: FFMPEG_FIND(AVFORMAT avformat avformat.h) MACRO(FFMPEG_FIND varname shortname headername) # old version of ffmpeg put header in $prefix/include/[ffmpeg] # so try to find header in include directory FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS ${headername} HINTS ${FFMPEG_ROOT}/include $ENV{FFMPEG_DIR}/include $ENV{OSGDIR}/include $ENV{OSG_ROOT}/include PATHS ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include PATH_SUFFIXES ffmpeg DOC "Location of FFMPEG Headers" ) # newer version of ffmpeg put header in $prefix/include/[ffmpeg/]lib${shortname} # so try to find lib${shortname}/header in include directory IF(NOT FFMPEG_${varname}_INCLUDE_DIRS) FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS lib${shortname}/${headername} HINTS ${FFMPEG_ROOT}/include $ENV{FFMPEG_DIR}/include $ENV{OSGDIR}/include $ENV{OSG_ROOT}/include PATHS ~/Library/Frameworks /Library/Frameworks /usr/local/include /usr/include/ /sw/include # Fink /opt/local/include # DarwinPorts /opt/csw/include # Blastwave /opt/include /usr/freeware/include PATH_SUFFIXES ffmpeg DOC "Location of FFMPEG Headers" ) ENDIF(NOT FFMPEG_${varname}_INCLUDE_DIRS) FIND_LIBRARY(FFMPEG_${varname}_LIBRARIES NAMES ${shortname} HINTS ${FFMPEG_ROOT}/lib $ENV{FFMPEG_DIR}/lib $ENV{OSGDIR}/lib $ENV{OSG_ROOT}/lib PATHS ~/Library/Frameworks /Library/Frameworks /usr/local/lib /usr/local/lib64 /usr/lib /usr/lib64 /sw/lib /opt/local/lib /opt/csw/lib /opt/lib /usr/freeware/lib64 DOC "Location of FFMPEG Libraries" ) IF (FFMPEG_${varname}_LIBRARIES AND FFMPEG_${varname}_INCLUDE_DIRS) SET(FFMPEG_${varname}_FOUND 1) ENDIF(FFMPEG_${varname}_LIBRARIES AND FFMPEG_${varname}_INCLUDE_DIRS) ENDMACRO(FFMPEG_FIND) SET(FFMPEG_ROOT "$ENV{FFMPEG_DIR}" CACHE PATH "Location of FFMPEG") FFMPEG_FIND(LIBAVFORMAT avformat avformat.h) FFMPEG_FIND(LIBAVDEVICE avdevice avdevice.h) FFMPEG_FIND(LIBAVCODEC avcodec avcodec.h) FFMPEG_FIND(LIBAVUTIL avutil avutil.h) FFMPEG_FIND(LIBSWSCALE swscale swscale.h) # not sure about the header to look for here. SET(FFMPEG_FOUND "NO") # Note we don't check FFMPEG_LIBSWSCALE_FOUND here, it's optional. IF (FFMPEG_LIBAVFORMAT_FOUND AND FFMPEG_LIBAVDEVICE_FOUND AND FFMPEG_LIBAVCODEC_FOUND AND FFMPEG_LIBAVUTIL_FOUND) SET(FFMPEG_FOUND "YES") SET(FFMPEG_INCLUDE_DIRS ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}) SET(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBAVFORMAT_LIBRARY_DIRS}) # Note we don't add FFMPEG_LIBSWSCALE_LIBRARIES here, it will be added if found later. SET(FFMPEG_LIBRARIES ${FFMPEG_LIBAVFORMAT_LIBRARIES} ${FFMPEG_LIBAVDEVICE_LIBRARIES} ${FFMPEG_LIBAVCODEC_LIBRARIES} ${FFMPEG_LIBAVUTIL_LIBRARIES}) ELSE (FFMPEG_LIBAVFORMAT_FOUND AND FFMPEG_LIBAVDEVICE_FOUND AND FFMPEG_LIBAVCODEC_FOUND AND FFMPEG_LIBAVUTIL_FOUND) # MESSAGE(STATUS "Could not find FFMPEG") ENDIF(FFMPEG_LIBAVFORMAT_FOUND AND FFMPEG_LIBAVDEVICE_FOUND AND FFMPEG_LIBAVCODEC_FOUND AND FFMPEG_LIBAVUTIL_FOUND) libam7xxx-0.1.7/cmake_modules/FindXCB.cmake000066400000000000000000000024241324602670600205010ustar00rootroot00000000000000# - Try to find libxcb # Once done this will define # # LIBXCB_FOUND - system has libxcb # LIBXCB_LIBRARIES - Link these to use libxcb # LIBXCB_INCLUDE_DIR - the libxcb include dir # LIBXCB_DEFINITIONS - compiler switches required for using libxcb # Copyright (c) 2008 Helio Chissini de Castro, # Copyright (c) 2007, Matthias Kretz, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF (NOT WIN32) IF (LIBXCB_INCLUDE_DIR AND LIBXCB_LIBRARIES) # in cache already SET(XCB_FIND_QUIETLY TRUE) ENDIF (LIBXCB_INCLUDE_DIR AND LIBXCB_LIBRARIES) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls FIND_PACKAGE(PkgConfig) PKG_CHECK_MODULES(PKG_XCB xcb) SET(LIBXCB_DEFINITIONS ${PKG_XCB_CFLAGS}) FIND_PATH(LIBXCB_INCLUDE_DIR xcb/xcb.h ${PKG_XCB_INCLUDE_DIRS} ) FIND_LIBRARY(LIBXCB_LIBRARIES NAMES xcb libxcb PATHS ${PKG_XCB_LIBRARY_DIRS} ) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(XCB DEFAULT_MSG LIBXCB_INCLUDE_DIR LIBXCB_LIBRARIES ) MARK_AS_ADVANCED(LIBXCB_INCLUDE_DIR LIBXCB_LIBRARIES XCBPROC_EXECUTABLE) ENDIF (NOT WIN32) libam7xxx-0.1.7/cmake_modules/Findlibusb-1.0.cmake000066400000000000000000000065641324602670600216520ustar00rootroot00000000000000# - Try to find libusb-1.0 # Once done this will define # # LIBUSB_1_FOUND - system has libusb # LIBUSB_1_INCLUDE_DIRS - the libusb include directory # LIBUSB_1_LIBRARIES - Link these to use libusb # LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb # # Adapted from cmake-modules Google Code project # # Copyright (c) 2006 Andreas Schneider # # (Changes for libusb) Copyright (c) 2008 Kyle Machulis # # Redistribution and use is allowed according to the terms of the New BSD license. # # CMake-Modules Project New BSD License # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the name of the CMake-Modules Project nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) # in cache already set(LIBUSB_FOUND TRUE) else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) find_path(LIBUSB_1_INCLUDE_DIR NAMES libusb.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include PATH_SUFFIXES libusb-1.0 ) find_library(LIBUSB_1_LIBRARY NAMES usb-1.0 usb PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) set(LIBUSB_1_INCLUDE_DIRS ${LIBUSB_1_INCLUDE_DIR} ) set(LIBUSB_1_LIBRARIES ${LIBUSB_1_LIBRARY} ) if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) set(LIBUSB_1_FOUND TRUE) endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) if (LIBUSB_1_FOUND) if (NOT libusb_1_FIND_QUIETLY) message(STATUS "Found libusb-1.0:") message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") endif (NOT libusb_1_FIND_QUIETLY) else (LIBUSB_1_FOUND) if (libusb_1_FIND_REQUIRED) message(FATAL_ERROR "Could not find libusb") endif (libusb_1_FIND_REQUIRED) endif (LIBUSB_1_FOUND) # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) libam7xxx-0.1.7/cmake_modules/MaintenanceTools.cmake000066400000000000000000000023511324602670600225260ustar00rootroot00000000000000# Use git for some maintenance tasks find_package(Git) if(GIT_FOUND) # Add an 'archive' target to generate a compressed archive from the git source code set(ARCHIVE_PREFIX ${CMAKE_PROJECT_NAME}-${PROJECT_VER}) find_program(DATE_EXECUTABLE date DOC "date command line program") if (DATE_EXECUTABLE) message(STATUS "Found date: " ${DATE_EXECUTABLE}) message(STATUS "Generator is: " ${CMAKE_GENERATOR}) # XXX: using $(shell CMD) works only with Unix Makefile if (CMAKE_GENERATOR STREQUAL "Unix Makefiles") message(STATUS " - \"git archive\" will use the date too!") set(ARCHIVE_PREFIX ${ARCHIVE_PREFIX}-$\(shell ${DATE_EXECUTABLE} +%Y%m%d%H%M\)) endif() endif() add_custom_target(archive COMMAND ${GIT_EXECUTABLE} archive -o \"${CMAKE_BINARY_DIR}/${ARCHIVE_PREFIX}.tar.gz\" --prefix=\"${ARCHIVE_PREFIX}/\" HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) # Add a 'changelog' target to generate a qausi-GNU-style changelog, it may # be used by distributors to ship when building their packages. add_custom_target(changelog COMMAND ${GIT_EXECUTABLE} log --pretty=\"format:%ai %aN <%aE>%n%n%x09* %s%d%n\" > \"${CMAKE_BINARY_DIR}/ChangeLog\" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) endif(GIT_FOUND) libam7xxx-0.1.7/cmake_modules/mingw_cross_toolchain.cmake000066400000000000000000000007301324602670600236540ustar00rootroot00000000000000SET(CMAKE_SYSTEM_NAME Windows) include(CMakeForceCompiler) IF("${GNU_HOST}" STREQUAL "") SET(GNU_HOST i586-mingw32msvc) ENDIF() SET(CMAKE_C_COMPILER ${GNU_HOST}-gcc) # CMake doesn't automatically look for prefixed 'windres', do it manually: SET(CMAKE_RC_COMPILER ${GNU_HOST}-windres) # The following is important to let cmake set some variables such as # CMAKE_FIND_LIBRARY_PREFIXES and CMAKE_FIND_LIBRARY_SUFFIXES from # Platform/Windows-GNU.cmake SET(MINGW True) libam7xxx-0.1.7/contrib/000077500000000000000000000000001324602670600151105ustar00rootroot00000000000000libam7xxx-0.1.7/contrib/50-am7xxx_mode_switch.rules000066400000000000000000000004451324602670600222320ustar00rootroot00000000000000# 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" libam7xxx-0.1.7/contrib/55-am7xxx.rules000066400000000000000000000014701324602670600176510ustar00rootroot00000000000000# Acer C110 ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1de1", ATTRS{idProduct}=="c101", MODE="0660", GROUP="plugdev" # Acer C112 ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1de1", ATTRS{idProduct}=="5501", MODE="0660", GROUP="plugdev" # Aiptek PocketCinema T25 ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="08ca", ATTRS{idProduct}=="2144", MODE="0660", GROUP="plugdev" # Philips/Sagemcom PicoPix 1020 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" libam7xxx-0.1.7/contrib/99-am7xxx-autodisplay.rules000066400000000000000000000005421324602670600222140ustar00rootroot00000000000000# Example rules to show how to run a program when the device is plugged in or out ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1de1", ATTRS{idProduct}=="c101", MODE="0660", GROUP="plugdev", RUN+="am7xxx-autodisplay.sh start" ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_VENDOR_ID}=="1de1", ENV{ID_MODEL_ID}=="c101", RUN+="am7xxx-autodisplay.sh stop" libam7xxx-0.1.7/contrib/am7xxx-autodisplay.sh000077500000000000000000000027261324602670600212460ustar00rootroot00000000000000#!/bin/sh # # am7xxx-autodisplay - resize the screen and run am7xxx-play # # Copyright (C) 2012-2014 Antonio Ospite # # This program is free software. It comes without any warranty, to # the extent permitted by applicable law. You can redistribute it # and/or modify it under the terms of the Do What The Fuck You Want # To Public License, Version 2, as published by Sam Hocevar. See # http://sam.zoy.org/wtfpl/COPYING for more details. # This is just an example script to show how to resize the screen before # running am7xxx-play, this can be called also from a udev script. # # Resizing the screen may be needed if the am7xxx device has problems # displaying a certain resolution. # # For example on some devices the firmware fails to display images of # resolution 800x469 resulting from scaled down 1024x600 screens, in # cases like this, resizing the screen can be a viable workaround. USER=ao2 RESOLUTION_PROJECTOR=800x600 RESOLUTION_ORIGINAL=1024x600 AM7XXX_PLAY=am7xxx-play # needed when running xrandr as root from udev rules, # see https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel/+bug/660901 export XAUTHORITY=$(find /var/run/gdm3/ -type f -path "*${USER}*" 2> /dev/null) export DISPLAY=:0.0 case $1 in start) xrandr --size $RESOLUTION_PROJECTOR && \ $AM7XXX_PLAY -f x11grab -i $DISPLAY ;; stop) xrandr --size $RESOLUTION_ORIGINAL ;; *) { echo "usage: $(basename $0) " 1>&2; exit 1; } ;; esac libam7xxx-0.1.7/contrib/am7xxx-play-window.sh000077500000000000000000000016501324602670600211550ustar00rootroot00000000000000#!/bin/sh # # am7xxx-play-window - show only a given window with am7xxx-play # # Copyright (C) 2013-2014 Antonio Ospite # # This program is free software. It comes without any warranty, to # the extent permitted by applicable law. You can redistribute it # and/or modify it under the terms of the Do What The Fuck You Want # To Public License, Version 2, as published by Sam Hocevar. See # http://sam.zoy.org/wtfpl/COPYING for more details. set -e DISPLAY=":0" WIN_INFO="$(xwininfo)" X=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Absolute upper-left X:[[:space:]]*/s///p") Y=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Absolute upper-left Y:[[:space:]]*/s///p") WIDTH=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Width:[[:space:]]*/s///p") HEIGHT=$(echo "$WIN_INFO" | sed -n -e "/^[[:space:]]*Height:[[:space:]]*/s///p") set -x am7xxx-play -f x11grab -i "${DISPLAY}+${X},${Y}" -o video_size="${WIDTH}x${HEIGHT}" libam7xxx-0.1.7/contrib/howto-picopix.asciidoc000066400000000000000000000072231324602670600214250ustar00rootroot00000000000000HOW-TO use a PicoPix on GNU/Linux ================================= Philips/SagemCom pico projectors, like for instance the PicoPix 2055, usually have a WVGA (854 x 480 pixels) native resolution, however they can be used to project other resolutions if the software rescales the image. First, update your system and download the free libam7xxx library and the related programs. On Debian and Ubuntu systems this can be done with the following commands: sudo apt-get update sudo apt-get install libam7xxx0.1-bin Plug your PicoPix into one or two USB slots of your personal computer (sometimes the second USB port is needed to ensure that the PicoPix has enough power). Wait for Philips logo to appear. After the logo has disappeared, execute the following command in a terminal: am7xxx-play -f x11grab -i :0.0 The video projection is on. You can have two simple scripts to execute and terminate the program from a graphical interface. PicoPix-START.sh: #!/bin/sh am7xxx-play -f x11grab -i :0.0 -p 1 -z 0 PicoPix-STOP.sh: #!/bin/sh killall am7xxx-play am7xxx-play -f x11grab -i :0.0 -p 0 -z 1 & sleep 1 killall am7xxx-play Save the shell scripts from above in files, and give the execute permissions to the owner (or user group) via the command line or via the graphical interface (http://sourcedigit.com/20111-how-to-run-a-shell-file-in-ubuntu-run-sh-file-in-ubuntu/). You will then be able to execute the file by double-clicking on it. If you want to specify a particular resolution you can pass it as a command line option: am7xxx-play -f x11grab -i :0.0 -o video_size=1280x768 When doing so you may notice that your PicoPix does not fully displays the content of your desktop screen, which can be truncated at the bottom and at the right. This is because of the WXGA (1280 x 768 pixels) resolution may be different from your personal computer screen resolution. It is therefore necessary to modify —temporarily— your personal computer screen resolution to wanted resolution. Take the following script: #!/bin/sh WIDTH=1280 HEIGHT=768 OUTPUT="LVDS-1" # See 'xrandr --listmonitors' xrandr --newmode $(gtf ${WIDTH} ${HEIGHT} 60 | sed -ne 's/"//g;s/ Modeline //p') xrandr --addmode ${OUTPUT} ${WIDTH}x${HEIGHT}_60.00 xrandr --output ${OUTPUT} --mode ${WIDTH}x${HEIGHT}_60.00 sleep 1 am7xxx-play -f x11grab -i :0.0 -p 1 -z 0 -o video_size=${WIDTH}x${HEIGHT} Note: In the example above, the personal computer screen is identified as "LVDS-1". Maybe your computer screen has a different identifier. In this case, you will have to replace "LVDS-1" with the correct identifier: open your terminal, type "xrandr" and the terminal will list and describe your different screen devices (more about xrandr utility here: http://pkg-xorg.alioth.debian.org/howto/use-xrandr.html). Also, in order to give back your computer screen its original resolution, you should create a PicoPix-STOP.sh script like the following: #!/bin/sh ORIGINAL_WIDTH=1600 ORIGINAL_HEIGHT=900 OUTPUT="LVDS-1" # See 'xrandr --listmonitors' killall am7xxx-play am7xxx-play -f x11grab -i :0.0 -p 0 -z 1 & sleep 1 killall am7xxx-play xrandr --output ${OUTPUT} --mode ${ORIGINAL_WIDTH}x${ORIGINAL_HEIGHT} Note: In the example above, the original screen resolution is 1600x900 pixels. You have to change this value and put your screen resolution value which you can know via xrandr. Same for LVDS-1. Once your video projection is over, you can execute the PicoPix-STOP.sh script so that your computer screen returns to its original state. You can then unplug the projector. That's all folks! This text is licensed under WTFPL. See http://www.wtfpl.net/ for more informations. libam7xxx-0.1.7/contrib/libam7xxx-compile-on-Ubuntu-14.04-LTS.diff000066400000000000000000000301721324602670600243140ustar00rootroot00000000000000diff --git a/examples/am7xxx-modeswitch.c b/examples/am7xxx-modeswitch.c index c304515..4f132d6 100644 --- a/examples/am7xxx-modeswitch.c +++ b/examples/am7xxx-modeswitch.c @@ -46,7 +46,7 @@ int main(void) goto out; } - libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_INFO); + libusb_set_debug(NULL, 3); usb_device = libusb_open_device_with_vid_pid(NULL, AM7XXX_STORAGE_VID, diff --git a/examples/am7xxx-play.c b/examples/am7xxx-play.c index 81aff84..1ee42e0 100644 --- a/examples/am7xxx-play.c +++ b/examples/am7xxx-play.c @@ -31,7 +31,6 @@ #include #include -#include #include #include @@ -51,10 +50,10 @@ static int video_input_init(struct video_input_ctx *input_ctx, { AVInputFormat *input_format = NULL; AVFormatContext *input_format_ctx; - AVCodecParameters *input_codec_params; AVCodecContext *input_codec_ctx; AVCodec *input_codec; int video_index; + unsigned int i; int ret; avdevice_register_all(); @@ -99,32 +98,34 @@ static int video_input_init(struct video_input_ctx *input_ctx, av_dump_format(input_format_ctx, 0, input_path, 0); /* look for the first video_stream */ - video_index = av_find_best_stream(input_format_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &input_codec, 0); - if (video_index < 0) { + video_index = -1; + for (i = 0; i < input_format_ctx->nb_streams; i++) + if (input_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + video_index = i; + break; + } + if (video_index == -1) { fprintf(stderr, "cannot find any video streams\n"); ret = -EINVAL; goto cleanup; } - input_codec_ctx = avcodec_alloc_context3(input_codec); - if (input_codec_ctx == NULL) { - fprintf(stderr, "failed to allocate the input codec context\n"); - ret = -ENOMEM; - goto cleanup; - } + /* get a pointer to the codec context for the video stream */ + input_codec_ctx = input_format_ctx->streams[video_index]->codec; - input_codec_params = input_format_ctx->streams[video_index]->codecpar; - ret = avcodec_parameters_to_context(input_codec_ctx, input_codec_params); - if (ret < 0) { - fprintf(stderr, "cannot copy parameters to input codec context\n"); - goto cleanup_ctx; + /* find the decoder for the video stream */ + input_codec = avcodec_find_decoder(input_codec_ctx->codec_id); + if (input_codec == NULL) { + fprintf(stderr, "input_codec is NULL!\n"); + ret = -EINVAL; + goto cleanup; } /* open the decoder */ ret = avcodec_open2(input_codec_ctx, input_codec, NULL); if (ret < 0) { fprintf(stderr, "cannot open input codec\n"); - goto cleanup_ctx; + goto cleanup; } input_ctx->format_ctx = input_format_ctx; @@ -134,8 +135,6 @@ static int video_input_init(struct video_input_ctx *input_ctx, ret = 0; goto out; -cleanup_ctx: - avcodec_free_context(&input_codec_ctx); cleanup: avformat_close_input(&input_format_ctx); out: @@ -177,7 +176,7 @@ static int video_output_init(struct video_output_ctx *output_ctx, goto out; } - /* Calculate the new output dimension so the original frame is shown + /* Calculate the new output dimension so the original picture is shown * in its entirety */ ret = am7xxx_calc_scaled_image_dimensions(dev, upscale, @@ -226,7 +225,7 @@ static int video_output_init(struct video_output_ctx *output_ctx, output_codec_ctx->qmin = output_codec_ctx->qmax = ((100 - (quality - 1)) * FF_QUALITY_SCALE) / 100; output_codec_ctx->mb_lmin = output_codec_ctx->qmin * FF_QP2LAMBDA; output_codec_ctx->mb_lmax = output_codec_ctx->qmax * FF_QP2LAMBDA; - output_codec_ctx->flags |= AV_CODEC_FLAG_QSCALE; + output_codec_ctx->flags |= CODEC_FLAG_QSCALE; output_codec_ctx->global_quality = output_codec_ctx->qmin * FF_QP2LAMBDA; /* find the encoder */ @@ -257,67 +256,6 @@ out: } -/* - * Wrap the new avcodec API from FFMpeg 3.1 to minimize the changes in the - * user code. - * - * If the use of the wrappers were to be made conditional, a check like the - * following could be used: - * - * #if (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)) - * - * As derived from the APIchanges document: - * https://github.com/FFmpeg/FFmpeg/blob/master/doc/APIchanges - * - * The wrapper implementation has been taken from: - * https://blogs.gentoo.org/lu_zero/2016/03/29/new-avcodec-api/ - */ -static int decode(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *pkt) -{ - int ret; - - *got_frame = 0; - - if (pkt) { - ret = avcodec_send_packet(avctx, pkt); - /* - * In particular, we don't expect AVERROR(EAGAIN), because we - * read all decoded frames with avcodec_receive_frame() until - * done. - */ - if (ret < 0) - return ret == AVERROR_EOF ? 0 : ret; - } - - ret = avcodec_receive_frame(avctx, frame); - if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) - return ret; - if (ret >= 0) - *got_frame = 1; - - return 0; -} - -static int encode(AVCodecContext *avctx, AVPacket *pkt, int *got_packet, AVFrame *frame) -{ - int ret; - - *got_packet = 0; - - ret = avcodec_send_frame(avctx, frame); - if (ret < 0) - return ret; - - ret = avcodec_receive_packet(avctx, pkt); - if (!ret) - *got_packet = 1; - if (ret == AVERROR(EAGAIN)) - return 0; - - return ret; -} - - static int am7xxx_play(const char *input_format_string, AVDictionary **input_options, const char *input_path, @@ -330,16 +268,16 @@ static int am7xxx_play(const char *input_format_string, { struct video_input_ctx input_ctx; struct video_output_ctx output_ctx; - AVFrame *frame_raw; - AVFrame *frame_scaled; + AVFrame *picture_raw; + AVFrame *picture_scaled; int out_buf_size; uint8_t *out_buf; - int out_frame_size; - uint8_t *out_frame; + int out_picture_size; + uint8_t *out_picture; struct SwsContext *sw_scale_ctx; AVPacket in_packet; AVPacket out_packet; - int got_frame; + int got_picture; int got_packet; int ret; @@ -356,44 +294,41 @@ static int am7xxx_play(const char *input_format_string, } /* allocate an input frame */ - frame_raw = av_frame_alloc(); - if (frame_raw == NULL) { - fprintf(stderr, "cannot allocate the raw frame!\n"); + picture_raw = avcodec_alloc_frame(); + if (picture_raw == NULL) { + fprintf(stderr, "cannot allocate the raw picture frame!\n"); ret = -ENOMEM; goto cleanup_output; } /* allocate output frame */ - frame_scaled = av_frame_alloc(); - if (frame_scaled == NULL) { - fprintf(stderr, "cannot allocate the scaled frame!\n"); + picture_scaled = avcodec_alloc_frame(); + if (picture_scaled == NULL) { + fprintf(stderr, "cannot allocate the scaled picture!\n"); ret = -ENOMEM; - goto cleanup_frame_raw; + goto cleanup_picture_raw; } - frame_scaled->format = (output_ctx.codec_ctx)->pix_fmt; - frame_scaled->width = (output_ctx.codec_ctx)->width; - frame_scaled->height = (output_ctx.codec_ctx)->height; + picture_scaled->format = (output_ctx.codec_ctx)->pix_fmt; + picture_scaled->width = (output_ctx.codec_ctx)->width; + picture_scaled->height = (output_ctx.codec_ctx)->height; /* calculate the bytes needed for the output image and create buffer for the output image */ - out_buf_size = av_image_get_buffer_size((output_ctx.codec_ctx)->pix_fmt, - (output_ctx.codec_ctx)->width, - (output_ctx.codec_ctx)->height, - 1); + out_buf_size = avpicture_get_size((output_ctx.codec_ctx)->pix_fmt, + (output_ctx.codec_ctx)->width, + (output_ctx.codec_ctx)->height); out_buf = av_malloc(out_buf_size * sizeof(uint8_t)); if (out_buf == NULL) { fprintf(stderr, "cannot allocate output data buffer!\n"); ret = -ENOMEM; - goto cleanup_frame_scaled; + goto cleanup_picture_scaled; } - /* assign appropriate parts of buffer to image planes in frame_scaled */ - av_image_fill_arrays(frame_scaled->data, - frame_scaled->linesize, - out_buf, - (output_ctx.codec_ctx)->pix_fmt, - (output_ctx.codec_ctx)->width, - (output_ctx.codec_ctx)->height, - 1); + /* assign appropriate parts of buffer to image planes in picture_scaled */ + avpicture_fill((AVPicture *)picture_scaled, + out_buf, + (output_ctx.codec_ctx)->pix_fmt, + (output_ctx.codec_ctx)->width, + (output_ctx.codec_ctx)->height); sw_scale_ctx = sws_getCachedContext(NULL, (input_ctx.codec_ctx)->width, @@ -430,8 +365,8 @@ static int am7xxx_play(const char *input_format_string, } /* decode */ - got_frame = 0; - ret = decode(input_ctx.codec_ctx, frame_raw, &got_frame, &in_packet); + got_picture = 0; + ret = avcodec_decode_video2(input_ctx.codec_ctx, picture_raw, &got_picture, &in_packet); if (ret < 0) { fprintf(stderr, "cannot decode video\n"); run = 0; @@ -439,41 +374,41 @@ static int am7xxx_play(const char *input_format_string, } /* if we got the complete frame */ - if (got_frame) { + if (got_picture) { /* - * Rescaling the frame also changes its pixel format + * Rescaling the picture also changes its pixel format * to the raw format supported by the projector if * this was set in video_output_init() */ sws_scale(sw_scale_ctx, - (const uint8_t * const *)frame_raw->data, - frame_raw->linesize, + (const uint8_t * const *)picture_raw->data, + picture_raw->linesize, 0, (input_ctx.codec_ctx)->height, - frame_scaled->data, - frame_scaled->linesize); + picture_scaled->data, + picture_scaled->linesize); if (output_ctx.raw_output) { - out_frame = out_buf; - out_frame_size = out_buf_size; + out_picture = out_buf; + out_picture_size = out_buf_size; } else { - frame_scaled->quality = (output_ctx.codec_ctx)->global_quality; + picture_scaled->quality = (output_ctx.codec_ctx)->global_quality; av_init_packet(&out_packet); out_packet.data = NULL; out_packet.size = 0; got_packet = 0; - ret = encode(output_ctx.codec_ctx, - &out_packet, - &got_packet, - frame_scaled); + ret = avcodec_encode_video2(output_ctx.codec_ctx, + &out_packet, + picture_scaled, + &got_packet); if (ret < 0 || !got_packet) { fprintf(stderr, "cannot encode video\n"); run = 0; goto end_while; } - out_frame = out_packet.data; - out_frame_size = out_packet.size; + out_picture = out_packet.data; + out_picture_size = out_packet.size; } #ifdef DEBUG @@ -485,7 +420,7 @@ static int am7xxx_play(const char *input_format_string, else snprintf(filename, NAME_MAX, "out.raw"); file = fopen(filename, "wb"); - fwrite(out_frame, 1, out_frame_size, file); + fwrite(out_picture, 1, out_picture_size, file); fclose(file); } #else @@ -496,8 +431,8 @@ static int am7xxx_play(const char *input_format_string, image_format, (output_ctx.codec_ctx)->width, (output_ctx.codec_ctx)->height, - out_frame, - out_frame_size); + out_picture, + out_picture_size); if (ret < 0) { perror("am7xxx_send_image_async"); run = 0; @@ -506,17 +441,17 @@ static int am7xxx_play(const char *input_format_string, } end_while: if (!output_ctx.raw_output && got_packet) - av_packet_unref(&out_packet); - av_packet_unref(&in_packet); + av_free_packet(&out_packet); + av_free_packet(&in_packet); } sws_freeContext(sw_scale_ctx); cleanup_out_buf: av_free(out_buf); -cleanup_frame_scaled: - av_frame_free(&frame_scaled); -cleanup_frame_raw: - av_frame_free(&frame_raw); +cleanup_picture_scaled: + avcodec_free_frame(&picture_scaled); +cleanup_picture_raw: + avcodec_free_frame(&picture_raw); cleanup_output: /* Freeing the codec context is needed as well, @@ -527,7 +462,6 @@ cleanup_output: cleanup_input: avcodec_close(input_ctx.codec_ctx); - avcodec_free_context(&(input_ctx.codec_ctx)); avformat_close_input(&(input_ctx.format_ctx)); out: diff --git a/src/am7xxx.c b/src/am7xxx.c index 8573a59..fd726af 100644 --- a/src/am7xxx.c +++ b/src/am7xxx.c @@ -1117,7 +1117,7 @@ AM7XXX_PUBLIC int am7xxx_init(am7xxx_context **ctx) goto out_free_context; } - libusb_set_debug((*ctx)->usb_context, LIBUSB_LOG_LEVEL_INFO); + libusb_set_debug((*ctx)->usb_context, 3); ret = scan_devices(*ctx, SCAN_OP_BUILD_DEVLIST , 0, NULL); if (ret < 0) { libam7xxx-0.1.7/contrib/libam7xxx_test_image_800x480.svg000066400000000000000000000146341324602670600230000ustar00rootroot00000000000000 image/svg+xml libam7xxx test screen Original Size: 800x480 (aspect ratio 5:3) Zoom 1 (H scale): 590x480 Zoom 2 (H/V Scale): 800x460 libam7xxx-0.1.7/contrib/performance/000077500000000000000000000000001324602670600174115ustar00rootroot00000000000000libam7xxx-0.1.7/contrib/performance/0001-Instrument-code-with-fps-meter.patch000066400000000000000000000027341324602670600267470ustar00rootroot00000000000000From bf1163a19667377a1861b38fa64a8cf7ee2d0e40 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Tue, 17 Nov 2015 16:28:03 +0100 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/am7xxx-play.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/am7xxx-play.c b/examples/am7xxx-play.c index 81aff84..4828a9d 100644 --- a/examples/am7xxx-play.c +++ b/examples/am7xxx-play.c @@ -35,6 +35,7 @@ #include #include +#include "fps-meter.h" static unsigned int run = 1; @@ -342,6 +343,7 @@ static int am7xxx_play(const char *input_format_string, int got_frame; 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) { @@ -410,6 +412,8 @@ static int am7xxx_play(const char *input_format_string, goto cleanup_out_buf; } + fps_meter_init(&stats); + got_packet = 0; while (run) { /* read packet */ @@ -503,6 +507,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) -- 2.16.2 libam7xxx-0.1.7/contrib/performance/1024x768_am7xxx_send_image.log000066400000000000000000000004621324602670600246300ustar00rootroot0000000000000014.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 libam7xxx-0.1.7/contrib/performance/1024x768_am7xxx_send_image_async.log000066400000000000000000000004621324602670600260250ustar00rootroot0000000000000046.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 libam7xxx-0.1.7/contrib/performance/README000066400000000000000000000004161324602670600202720ustar00rootroot00000000000000Benchmark methodology - Code instrumented with fps-meter - Data acquired with this command 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 libam7xxx-0.1.7/contrib/performance/ministat_report_1024x768.log000066400000000000000000000024631324602670600244470ustar00rootroot00000000000000x 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) libam7xxx-0.1.7/doc/000077500000000000000000000000001324602670600142155ustar00rootroot00000000000000libam7xxx-0.1.7/doc/CMakeLists.txt000066400000000000000000000014471324602670600167630ustar00rootroot00000000000000# add a target to generate API documentation with Doxygen find_package(Doxygen) if(DOXYGEN_FOUND) configure_file("Doxyfile.in" "Doxyfile" @ONLY IMMEDIATE) add_custom_target(doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile WORKING_DIRECTORY ${DOC_OUTPUT_PATH} COMMENT "Generating API documentation with Doxygen" VERBATIM ) add_custom_target(install-doc COMMAND ${CMAKE_COMMAND} -DCOMPONENT=doc -P ${CMAKE_BINARY_DIR}/cmake_install.cmake COMMENT "Installing API documentation") add_dependencies(install-doc doc) install(CODE "execute_process(COMMAND ${CMAKE_BUILD_TOOL} doc)") install(DIRECTORY ${DOC_OUTPUT_PATH}/html DESTINATION "${CMAKE_INSTALL_PREFIX}/share/doc/${CMAKE_PROJECT_NAME}" COMPONENT doc) endif(DOXYGEN_FOUND) add_subdirectory(man) libam7xxx-0.1.7/doc/Doxyfile.in000066400000000000000000000262331324602670600163360ustar00rootroot00000000000000# Doxyfile 1.8.13 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = @PROJECT_NAME@ PROJECT_NUMBER = @PROJECT_APIVER@ PROJECT_BRIEF = "@PROJECT_DESCRIPTION@" PROJECT_LOGO = OUTPUT_DIRECTORY = @DOC_OUTPUT_PATH@ CREATE_SUBDIRS = NO ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@ STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 0 AUTOLINK_SUPPORT = YES BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO GROUP_NESTED_COMPOUNDS = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_PACKAGE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = NO EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO SHOW_INCLUDE_FILES = YES SHOW_GROUPED_MEMB_INC = NO FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_AS_ERROR = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = @CMAKE_CURRENT_SOURCE_DIR@/ \ @CMAKE_SOURCE_DIR@/src/ \ @CMAKE_SOURCE_DIR@/examples/ INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.dox \ *.h \ *.c RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/examples/ EXAMPLE_PATTERNS = *.c EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = YES STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES SOURCE_TOOLTIPS = YES USE_HTAGS = NO VERBATIM_HEADERS = YES CLANG_ASSISTED_PARSING = NO CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES HTML_DYNAMIC_SECTIONS = NO HTML_INDEX_NUM_ENTRIES = 100 GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO GENERATE_TREEVIEW = NO ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 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 #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4 EXTRA_PACKAGES = LATEX_HEADER = LATEX_FOOTER = LATEX_EXTRA_STYLESHEET = LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain LATEX_TIMESTAMP = NO #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_SUBDIR = MAN_LINKS = NO #--------------------------------------------------------------------------- # Configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook DOCBOOK_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration options related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO MSCGEN_PATH = DIA_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_NUM_THREADS = 0 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO UML_LIMIT_NUM_FIELDS = 10 TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png INTERACTIVE_SVG = NO DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DIAFILE_DIRS = PLANTUML_JAR_PATH = PLANTUML_CFG_FILE = PLANTUML_INCLUDE_PATH = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = YES GENERATE_LEGEND = YES DOT_CLEANUP = YES libam7xxx-0.1.7/doc/DoxygenMainpage.dox000066400000000000000000000027631324602670600200200ustar00rootroot00000000000000/** @mainpage libam7xxx @author Antonio Ospite @copyright GNU General Public License version 2. Website: http://git.ao2.it/libam7xxx.git @section libam7xxxIntro Introduction libam7xxx is an Open Source library to communicate via USB with projectors and Digital Picture Frames based on the Actions Micro AM7XXX family if ICs. libam7xxx makes it possible to use these devices as USB displays on non-Windows Operating Systems like GNU/Linux or Android/Linux just to name a few, and on non-PC platforms like for instance mobile phones, tablets or game consoles. Check @link am7xxx.h @endlink for the public API documentation. @section libam7xxxSupportedDevices Supported Devices - Acer C110 - Acer C112 - Aiptek PocketCinema T25 - Philips/SagemCom PicoPix 1020 - Philips/SagemCom PicoPix 2055 - Philips/SagemCom PicoPix 2330 - Top-Height/TEC PP700 @section libam7xxxDesignOverview Design Overview libam7xxx provides access to devices via two structs: - A context, which manages aspects of thread safety when using multiple devices on multiple threads. - A device, which talks to the hardware and manages transfers and configuration. Either or both of these structs are passed to the functions in order to interact with the hardware. The USB access is handled by libusb-1.0, which should work in a mostly non-blocking fashion across all platforms (see function documentation for specifics). The API and the project structure has been inspired by libfreenect. */ libam7xxx-0.1.7/doc/lsusb_dumps/000077500000000000000000000000001324602670600165555ustar00rootroot00000000000000libam7xxx-0.1.7/doc/lsusb_dumps/lsusb_Acer-C110.log000066400000000000000000000044661324602670600217560ustar00rootroot00000000000000 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 libam7xxx-0.1.7/doc/lsusb_dumps/lsusb_Philips-PicoPix-1020.log000066400000000000000000000043151324602670600240340ustar00rootroot00000000000000Bus 002 Device 008: ID 21e7:000e Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 255 Vendor Specific Class bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x21e7 idProduct 0x000e 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 libam7xxx-0.1.7/doc/lsusb_dumps/lsusb_Philips-PicoPix-2055.log000066400000000000000000000043161324602670600240460ustar00rootroot00000000000000 Bus 003 Device 040: ID 21e7:0016 Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 255 Vendor Specific Class bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x21e7 idProduct 0x0016 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 libam7xxx-0.1.7/doc/lsusb_dumps/lsusb_Philips-PicoPix-2330-2340.log000066400000000000000000000043401324602670600244250ustar00rootroot00000000000000 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 libam7xxx-0.1.7/doc/man/000077500000000000000000000000001324602670600147705ustar00rootroot00000000000000libam7xxx-0.1.7/doc/man/CMakeLists.txt000066400000000000000000000021431324602670600175300ustar00rootroot00000000000000# add a target to generate man pages with asciidoc 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 ) add_custom_target(install-manpages COMMAND ${CMAKE_COMMAND} -DCOMPONENT=manpages -P ${CMAKE_BINARY_DIR}/cmake_install.cmake COMMENT "Installing manpages") add_dependencies(install-manpages manpages) install(CODE "execute_process(COMMAND ${CMAKE_BUILD_TOOL} manpages)") 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) endif(ASCIIDOC_FOUND) libam7xxx-0.1.7/doc/man/am7xxx-modeswitch.1.txt000066400000000000000000000020241324602670600212660ustar00rootroot00000000000000AM7XXX-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-2014 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. libam7xxx-0.1.7/doc/man/am7xxx-play.1.txt000066400000000000000000000042341324602670600200720ustar00rootroot00000000000000AM7XXX-PLAY(1) ============== :doctype: manpage NAME ---- am7xxx-play - play stuff on an am7xxx device (e.g. Acer C110, PicoPix 1020) SYNOPSIS -------- *am7xxx-play* ['OPTIONS'] DESCRIPTION ----------- am7xxx-play(1) uses libavdevice, libavformat, libavcodec and libswscale to decode the input, encode it to jpeg and display it with libam7xxx. OPTIONS ------- *-d* '':: the device index (default is 0) *-f* '':: the input device format *-i* '':: the input path *-o* '':: a comma separated list of input format options + EXAMPLE: + -o draw_mouse=1,framerate=100,video_size=800x480 *-s* '':: the rescaling method (see swscale.h) *-u*:: upscale the image if smaller than the display dimensions *-F* '':: the image format to use (default is JPEG) + .SUPPORTED FORMATS: * 1 - JPEG * 2 - NV12 *-q* '':: quality of jpeg sent to the device, between 1 and 100 *-l* '':: the verbosity level of libam7xxx output (0-5) *-p* '':: the power mode of device, between 0 (off) and 4 (turbo) + WARNING: Level 2 and greater require the master AND the slave connector to be plugged in. *-z* '':: the display zoom mode, between 0 (original) and 4 (tele) *-h*:: show the help message EXAMPLES OF USE --------------- am7xxx-play -f x11grab -i :0.0 -o video_size=800x480 am7xxx-play -f fbdev -i /dev/fb0 am7xxx-play -f video4linux2 -i /dev/video0 -o video_size=320x240,frame_rate=100 -u -q 90 am7xxx-play -i http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_640x360.m4v EXIT STATUS ----------- *0*:: Success *!0*:: Failure (libam7xxx error; libav error) AUTHORS ------- Antonio Ospite and Reto Schneider RESOURCES --------- Main web site: COPYING ------- Copyright \(C) 2012-2014 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. libam7xxx-0.1.7/doc/man/picoproj.1.txt000066400000000000000000000032621324602670600175200ustar00rootroot00000000000000PICOPROJ(1) =========== :doctype: manpage NAME ---- picoproj - test program for libam7xxx SYNOPSIS -------- *picoproj* ['OPTIONS'] DESCRIPTION ----------- picoproj(1) is a minimal example to show how to use libam7xxx to display a static image; it will not perform any image rescaling or conversion, images larger than the device native resolution can be wrongly displayed. OPTIONS ------- *-d* '':: the device index (default is 0) *-f* '':: the image file to upload *-F* '':: the image format to use (default is JPEG) + .SUPPORTED FORMATS: * 1 - JPEG * 2 - NV12 *-l* '':: the verbosity level of libam7xxx output (0-5) *-p* '':: the power mode of device, between 0 (off) and 4 (turbo) + WARNING: Level 2 and greater require the master AND the slave connector to be plugged in. *-z* '':: the display zoom mode, between 0 (original) and 4 (tele) *-W* '':: the width of the image to upload *-H* '':: the height of the image to upload *-h*:: show the help message EXAMPLE OF USE -------------- picoproj -f file.jpg -F 1 -l 5 -W 800 -H 480 EXIT STATUS ----------- *0*:: Success *!0*:: Failure (libam7xxx error) AUTHORS ------- Antonio Ospite and Reto Schneider RESOURCES --------- Main web site: COPYING ------- Copyright \(C) 2012-2014 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. libam7xxx-0.1.7/examples/000077500000000000000000000000001324602670600152665ustar00rootroot00000000000000libam7xxx-0.1.7/examples/CMakeLists.txt000066400000000000000000000050001324602670600200210ustar00rootroot00000000000000include(CheckSymbolExists) add_definitions("-D_POSIX_C_SOURCE=200809L") # for getopt(), sigaction(), and strdup() include_directories(${CMAKE_SOURCE_DIR}/src/) # Build a test app that sends a single picture option(BUILD_PICOPROJ "Build a test app that sends a single picture" TRUE) if(BUILD_PICOPROJ) add_executable(picoproj picoproj.c) target_link_libraries(picoproj am7xxx) install(TARGETS picoproj DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") endif() # Build a more complete example option(BUILD_AM7XXX-PLAY "Build a more complete example: am7xxx-play" TRUE) if(BUILD_AM7XXX-PLAY) find_package(FFmpeg REQUIRED) set(CMAKE_REQUIRED_LIBRARIES ${FFMPEG_LIBAVFORMAT_LIBRARIES}) set(CMAKE_REQUIRED_INCLUDES ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}) check_symbol_exists(avformat_open_input "libavformat/avformat.h" HAVE_AVFORMAT_OPEN_INPUT) if(NOT HAVE_AVFORMAT_OPEN_INPUT) message(FATAL_ERROR "Function avformat_open_input missing. Please use a newer FFmpeg release.") endif() include_directories(${FFMPEG_LIBAVDEVICE_INCLUDE_DIRS}) include_directories(${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS}) include_directories(${FFMPEG_LIBSWSCALE_INCLUDE_DIRS}) set(CMAKE_REQUIRED_DEFINITIONS -D_POSIX_SOURCE) check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION) if (HAVE_SIGACTION) add_definitions("-DHAVE_SIGACTION") endif() check_symbol_exists(strtok_r "string.h" HAVE_STRTOK_R) if (HAVE_STRTOK_R) add_definitions("-DHAVE_STRTOK_R") endif() set(CMAKE_REQUIRED_DEFINITIONS) # xcb is used to retrieve the full screen dimensions when using x11grab # as input format find_package(XCB) if (XCB_FOUND) add_definitions("${LIBXCB_DEFINITIONS} -DHAVE_XCB") include_directories(${LIBXCB_INCLUDE_DIRS}) set(OPTIONAL_LIBRARIES ${LIBXCB_LIBRARIES}) endif() add_executable(am7xxx-play am7xxx-play.c) target_link_libraries(am7xxx-play am7xxx ${FFMPEG_LIBRARIES} ${FFMPEG_LIBSWSCALE_LIBRARIES} ${OPTIONAL_LIBRARIES}) install(TARGETS am7xxx-play DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") endif() # 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-modeswitch am7xxx-modeswitch.c) target_link_libraries(am7xxx-modeswitch ${LIBUSB_1_LIBRARIES}) install(TARGETS am7xxx-modeswitch DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") endif() libam7xxx-0.1.7/examples/am7xxx-modeswitch.c000066400000000000000000000075711324602670600210440ustar00rootroot00000000000000/* am7xxx-modeswitch - a simple usb-modeswitch for am7xxx devices * * Copyright (C) 2012-2014 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. * * 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 #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" "\x10\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; int main(void) { int ret; libusb_device_handle *usb_device; int current_configuration; unsigned int len; int transferred; ret = libusb_init(NULL); if (ret < 0) { fprintf(stderr, "libusb_init failed: %s\n", libusb_error_name(ret)); goto out; } libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_INFO); usb_device = libusb_open_device_with_vid_pid(NULL, AM7XXX_STORAGE_VID, AM7XXX_STORAGE_PID); if (usb_device == NULL) { fprintf(stderr, "libusb_open failed: %s\n", strerror(errno)); ret = -errno; goto out; } current_configuration = -1; ret = libusb_get_configuration(usb_device, ¤t_configuration); if (ret < 0) { fprintf(stderr, "libusb_get_configuration failed: %s\n", libusb_error_name(ret)); goto out_libusb_close; } if (current_configuration != AM7XXX_STORAGE_CONFIGURATION) { ret = libusb_set_configuration(usb_device, AM7XXX_STORAGE_CONFIGURATION); if (ret < 0) { fprintf(stderr, "libusb_set_configuration failed: %s\n", libusb_error_name(ret)); fprintf(stderr, "Cannot set configuration %d\n", AM7XXX_STORAGE_CONFIGURATION); goto out_libusb_close; } } libusb_set_auto_detach_kernel_driver(usb_device, 1); ret = libusb_claim_interface(usb_device, AM7XXX_STORAGE_INTERFACE); if (ret < 0) { fprintf(stderr, "libusb_claim_interface failed: %s\n", libusb_error_name(ret)); fprintf(stderr, "Cannot claim interface %d\n", AM7XXX_STORAGE_INTERFACE); goto out_libusb_close; } /* * Checking that the configuration has not changed, as suggested in * http://libusb.sourceforge.net/api-1.0/caveats.html */ current_configuration = -1; ret = libusb_get_configuration(usb_device, ¤t_configuration); if (ret < 0) { fprintf(stderr, "libusb_get_configuration after claim failed: %s\n", libusb_error_name(ret)); goto out_libusb_release_interface; } if (current_configuration != AM7XXX_STORAGE_CONFIGURATION) { fprintf(stderr, "libusb configuration changed (expected: %d, current: %d)\n", AM7XXX_STORAGE_CONFIGURATION, current_configuration); ret = -EINVAL; goto out_libusb_release_interface; } 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; } libam7xxx-0.1.7/examples/am7xxx-play.c000066400000000000000000000603051324602670600176350ustar00rootroot00000000000000/* * am7xxx-play - play stuff on an am7xxx device (e.g. Acer C110, PicoPix 1020) * * Copyright (C) 2012-2014 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. * * 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 . */ /** * @example examples/am7xxx-play.c * am7xxx-play uses libavdevice, libavformat, libavcodec and libswscale to * decode the input, encode it to jpeg and display it with libam7xxx. */ #include #include #include #include #include #include #include #include #include #include static unsigned int run = 1; struct video_input_ctx { AVFormatContext *format_ctx; AVCodecContext *codec_ctx; int video_stream_index; }; static int video_input_init(struct video_input_ctx *input_ctx, const char *input_format_string, const char *input_path, AVDictionary **input_options) { AVInputFormat *input_format = NULL; AVFormatContext *input_format_ctx; AVCodecParameters *input_codec_params; AVCodecContext *input_codec_ctx; AVCodec *input_codec; int video_index; int ret; avdevice_register_all(); avcodec_register_all(); av_register_all(); if (input_format_string) { /* find the desired input format */ input_format = av_find_input_format(input_format_string); if (input_format == NULL) { fprintf(stderr, "cannot find input format\n"); ret = -ENODEV; goto out; } } if (input_path == NULL) { fprintf(stderr, "input_path must not be NULL!\n"); ret = -EINVAL; goto out; } /* open the input format/device */ input_format_ctx = NULL; ret = avformat_open_input(&input_format_ctx, input_path, input_format, input_options); if (ret < 0) { fprintf(stderr, "cannot open input format/device\n"); goto out; } /* get information on the input stream (e.g. format, bitrate, framerate) */ ret = avformat_find_stream_info(input_format_ctx, NULL); if (ret < 0) { fprintf(stderr, "cannot get information on the stream\n"); goto cleanup; } /* dump what was found */ av_dump_format(input_format_ctx, 0, input_path, 0); /* look for the first video_stream */ video_index = av_find_best_stream(input_format_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &input_codec, 0); if (video_index < 0) { fprintf(stderr, "cannot find any video streams\n"); ret = -EINVAL; goto cleanup; } input_codec_ctx = avcodec_alloc_context3(input_codec); if (input_codec_ctx == NULL) { fprintf(stderr, "failed to allocate the input codec context\n"); ret = -ENOMEM; goto cleanup; } input_codec_params = input_format_ctx->streams[video_index]->codecpar; ret = avcodec_parameters_to_context(input_codec_ctx, input_codec_params); if (ret < 0) { fprintf(stderr, "cannot copy parameters to input codec context\n"); goto cleanup_ctx; } /* open the decoder */ ret = avcodec_open2(input_codec_ctx, input_codec, NULL); if (ret < 0) { fprintf(stderr, "cannot open input codec\n"); goto cleanup_ctx; } input_ctx->format_ctx = input_format_ctx; input_ctx->codec_ctx = input_codec_ctx; input_ctx->video_stream_index = video_index; ret = 0; goto out; cleanup_ctx: avcodec_free_context(&input_codec_ctx); cleanup: avformat_close_input(&input_format_ctx); out: av_dict_free(input_options); *input_options = NULL; return ret; } struct video_output_ctx { AVCodecContext *codec_ctx; int raw_output; }; static int video_output_init(struct video_output_ctx *output_ctx, struct video_input_ctx *input_ctx, unsigned int upscale, unsigned int quality, am7xxx_image_format image_format, am7xxx_device *dev) { AVCodecContext *output_codec_ctx; AVCodec *output_codec; unsigned int new_output_width; unsigned int new_output_height; int ret; if (input_ctx == NULL) { fprintf(stderr, "input_ctx must not be NULL!\n"); ret = -EINVAL; goto out; } /* create the encoder context */ output_codec_ctx = avcodec_alloc_context3(NULL); if (output_codec_ctx == NULL) { fprintf(stderr, "cannot allocate output codec context!\n"); ret = -ENOMEM; goto out; } /* Calculate the new output dimension so the original frame is shown * in its entirety */ ret = am7xxx_calc_scaled_image_dimensions(dev, upscale, (input_ctx->codec_ctx)->width, (input_ctx->codec_ctx)->height, &new_output_width, &new_output_height); if (ret < 0) { fprintf(stderr, "cannot calculate output dimension\n"); goto cleanup; } /* put sample parameters */ output_codec_ctx->bit_rate = (input_ctx->codec_ctx)->bit_rate; output_codec_ctx->width = new_output_width; output_codec_ctx->height = new_output_height; output_codec_ctx->time_base.num = (input_ctx->format_ctx)->streams[input_ctx->video_stream_index]->time_base.num; output_codec_ctx->time_base.den = (input_ctx->format_ctx)->streams[input_ctx->video_stream_index]->time_base.den; /* When the raw format is requested we don't actually need to setup * and open a decoder */ if (image_format == AM7XXX_IMAGE_FORMAT_NV12) { fprintf(stdout, "using raw output format\n"); output_codec_ctx->pix_fmt = AV_PIX_FMT_NV12; output_ctx->codec_ctx = output_codec_ctx; output_ctx->raw_output = 1; ret = 0; goto out; } /* YUVJ420P is deprecated in swscaler, but mjpeg still relies on it. */ output_codec_ctx->pix_fmt = AV_PIX_FMT_YUVJ420P; output_codec_ctx->codec_id = AV_CODEC_ID_MJPEG; output_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; /* Set quality and other VBR settings */ /* @note: 'quality' is expected to be between 1 and 100, but a value * between 0 to 99 has to be passed when calculating qmin and qmax. * This way qmin and qmax will cover the range 1-FF_QUALITY_SCALE, and * in particular they won't be 0, this is needed because they are used * as divisor somewhere in the encoding process */ output_codec_ctx->qmin = output_codec_ctx->qmax = ((100 - (quality - 1)) * FF_QUALITY_SCALE) / 100; output_codec_ctx->mb_lmin = output_codec_ctx->qmin * FF_QP2LAMBDA; output_codec_ctx->mb_lmax = output_codec_ctx->qmax * FF_QP2LAMBDA; output_codec_ctx->flags |= AV_CODEC_FLAG_QSCALE; output_codec_ctx->global_quality = output_codec_ctx->qmin * FF_QP2LAMBDA; /* find the encoder */ output_codec = avcodec_find_encoder(output_codec_ctx->codec_id); if (output_codec == NULL) { fprintf(stderr, "cannot find output codec!\n"); ret = -EINVAL; goto cleanup; } /* open the codec */ ret = avcodec_open2(output_codec_ctx, output_codec, NULL); if (ret < 0) { fprintf(stderr, "could not open output codec!\n"); goto cleanup; } output_ctx->codec_ctx = output_codec_ctx; output_ctx->raw_output = 0; ret = 0; goto out; cleanup: avcodec_free_context(&output_codec_ctx); out: return ret; } /* * Wrap the new avcodec API from FFMpeg 3.1 to minimize the changes in the * user code. * * If the use of the wrappers were to be made conditional, a check like the * following could be used: * * #if (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)) * * As derived from the APIchanges document: * https://github.com/FFmpeg/FFmpeg/blob/master/doc/APIchanges * * The wrapper implementation has been taken from: * https://blogs.gentoo.org/lu_zero/2016/03/29/new-avcodec-api/ */ static int decode(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *pkt) { int ret; *got_frame = 0; if (pkt) { ret = avcodec_send_packet(avctx, pkt); /* * In particular, we don't expect AVERROR(EAGAIN), because we * read all decoded frames with avcodec_receive_frame() until * done. */ if (ret < 0) return ret == AVERROR_EOF ? 0 : ret; } ret = avcodec_receive_frame(avctx, frame); if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) return ret; if (ret >= 0) *got_frame = 1; return 0; } static int encode(AVCodecContext *avctx, AVPacket *pkt, int *got_packet, AVFrame *frame) { int ret; *got_packet = 0; ret = avcodec_send_frame(avctx, frame); if (ret < 0) return ret; ret = avcodec_receive_packet(avctx, pkt); if (!ret) *got_packet = 1; if (ret == AVERROR(EAGAIN)) return 0; return ret; } static int am7xxx_play(const char *input_format_string, AVDictionary **input_options, const char *input_path, unsigned int rescale_method, unsigned int upscale, unsigned int quality, am7xxx_image_format image_format, am7xxx_device *dev, int dump_frame) { struct video_input_ctx input_ctx; struct video_output_ctx output_ctx; AVFrame *frame_raw; AVFrame *frame_scaled; int out_buf_size; uint8_t *out_buf; int out_frame_size; uint8_t *out_frame; struct SwsContext *sw_scale_ctx; AVPacket in_packet; AVPacket out_packet; int got_frame; int got_packet; int ret; ret = video_input_init(&input_ctx, input_format_string, input_path, input_options); if (ret < 0) { fprintf(stderr, "cannot initialize input\n"); goto out; } ret = video_output_init(&output_ctx, &input_ctx, upscale, quality, image_format, dev); if (ret < 0) { fprintf(stderr, "cannot initialize input\n"); goto cleanup_input; } /* allocate an input frame */ frame_raw = av_frame_alloc(); if (frame_raw == NULL) { fprintf(stderr, "cannot allocate the raw frame!\n"); ret = -ENOMEM; goto cleanup_output; } /* allocate output frame */ frame_scaled = av_frame_alloc(); if (frame_scaled == NULL) { fprintf(stderr, "cannot allocate the scaled frame!\n"); ret = -ENOMEM; goto cleanup_frame_raw; } frame_scaled->format = (output_ctx.codec_ctx)->pix_fmt; frame_scaled->width = (output_ctx.codec_ctx)->width; frame_scaled->height = (output_ctx.codec_ctx)->height; /* calculate the bytes needed for the output image and create buffer for the output image */ out_buf_size = av_image_get_buffer_size((output_ctx.codec_ctx)->pix_fmt, (output_ctx.codec_ctx)->width, (output_ctx.codec_ctx)->height, 1); out_buf = av_malloc(out_buf_size * sizeof(uint8_t)); if (out_buf == NULL) { fprintf(stderr, "cannot allocate output data buffer!\n"); ret = -ENOMEM; goto cleanup_frame_scaled; } /* assign appropriate parts of buffer to image planes in frame_scaled */ av_image_fill_arrays(frame_scaled->data, frame_scaled->linesize, out_buf, (output_ctx.codec_ctx)->pix_fmt, (output_ctx.codec_ctx)->width, (output_ctx.codec_ctx)->height, 1); sw_scale_ctx = sws_getCachedContext(NULL, (input_ctx.codec_ctx)->width, (input_ctx.codec_ctx)->height, (input_ctx.codec_ctx)->pix_fmt, (output_ctx.codec_ctx)->width, (output_ctx.codec_ctx)->height, (output_ctx.codec_ctx)->pix_fmt, rescale_method, NULL, NULL, NULL); if (sw_scale_ctx == NULL) { fprintf(stderr, "cannot set up the rescaling context!\n"); ret = -EINVAL; goto cleanup_out_buf; } got_packet = 0; while (run) { /* read packet */ ret = av_read_frame(input_ctx.format_ctx, &in_packet); if (ret < 0) { if (ret == (int)AVERROR_EOF || input_ctx.format_ctx->pb->eof_reached) ret = 0; else fprintf(stderr, "av_read_frame failed, EOF?\n"); run = 0; goto end_while; } if (in_packet.stream_index != input_ctx.video_stream_index) { /* that is more or less a "continue", but there is * still the packet to free */ goto end_while; } /* decode */ got_frame = 0; ret = decode(input_ctx.codec_ctx, frame_raw, &got_frame, &in_packet); if (ret < 0) { fprintf(stderr, "cannot decode video\n"); run = 0; goto end_while; } /* if we got the complete frame */ if (got_frame) { /* * Rescaling the frame also changes its pixel format * to the raw format supported by the projector if * this was set in video_output_init() */ sws_scale(sw_scale_ctx, (const uint8_t * const *)frame_raw->data, frame_raw->linesize, 0, (input_ctx.codec_ctx)->height, frame_scaled->data, frame_scaled->linesize); if (output_ctx.raw_output) { out_frame = out_buf; out_frame_size = out_buf_size; } else { frame_scaled->quality = (output_ctx.codec_ctx)->global_quality; av_init_packet(&out_packet); out_packet.data = NULL; out_packet.size = 0; got_packet = 0; ret = encode(output_ctx.codec_ctx, &out_packet, &got_packet, frame_scaled); if (ret < 0 || !got_packet) { fprintf(stderr, "cannot encode video\n"); run = 0; goto end_while; } out_frame = out_packet.data; out_frame_size = out_packet.size; } #ifdef DEBUG if (dump_frame) { char filename[NAME_MAX]; FILE *file; if (!output_ctx.raw_output) snprintf(filename, NAME_MAX, "out_q%03d.jpg", quality); else snprintf(filename, NAME_MAX, "out.raw"); file = fopen(filename, "wb"); fwrite(out_frame, 1, out_frame_size, file); fclose(file); } #else (void) dump_frame; #endif ret = am7xxx_send_image_async(dev, image_format, (output_ctx.codec_ctx)->width, (output_ctx.codec_ctx)->height, out_frame, out_frame_size); if (ret < 0) { perror("am7xxx_send_image_async"); run = 0; goto end_while; } } end_while: if (!output_ctx.raw_output && got_packet) av_packet_unref(&out_packet); av_packet_unref(&in_packet); } sws_freeContext(sw_scale_ctx); cleanup_out_buf: av_free(out_buf); cleanup_frame_scaled: av_frame_free(&frame_scaled); cleanup_frame_raw: av_frame_free(&frame_raw); cleanup_output: /* Freeing the codec context is needed as well, * see https://libav.org/documentation/doxygen/master/group__lavc__core.html#gaf4daa92361efb3523ef5afeb0b54077f */ avcodec_close(output_ctx.codec_ctx); avcodec_free_context(&(output_ctx.codec_ctx)); cleanup_input: avcodec_close(input_ctx.codec_ctx); avcodec_free_context(&(input_ctx.codec_ctx)); avformat_close_input(&(input_ctx.format_ctx)); out: return ret; } #ifdef HAVE_XCB #include static int x_get_screen_dimensions(const char *displayname, int *width, int *height) { int i, screen_number; xcb_connection_t *connection; const xcb_setup_t *setup; xcb_screen_iterator_t iter; connection = xcb_connect(displayname, &screen_number); if (xcb_connection_has_error(connection)) { fprintf(stderr, "Cannot open a connection to %s\n", displayname); return -EINVAL; } setup = xcb_get_setup(connection); if (setup == NULL) { fprintf(stderr, "Cannot get setup for %s\n", displayname); xcb_disconnect(connection); return -EINVAL; } iter = xcb_setup_roots_iterator(setup); for (i = 0; i < screen_number; ++i) { xcb_screen_next(&iter); } xcb_screen_t *screen = iter.data; *width = screen->width_in_pixels; *height = screen->height_in_pixels; xcb_disconnect(connection); return 0; } static char *get_x_screen_size(const char *input_path) { int len; int width; int height; char *screen_size; int ret; ret = x_get_screen_dimensions(input_path, &width, &height); if (ret < 0) { fprintf(stderr, "Cannot get screen dimensions for %s\n", input_path); return NULL; } len = snprintf(NULL, 0, "%dx%d", width, height); screen_size = malloc((len + 1) * sizeof(char)); if (screen_size == NULL) { perror("malloc"); return NULL; } len = snprintf(screen_size, len + 1, "%dx%d", width, height); if (len < 0) { free(screen_size); screen_size = NULL; return NULL; } return screen_size; } #else static char *get_x_screen_size(const char *input_path) { (void) input_path; fprintf(stderr, "%s: fallback implementation, assuming a vga screen\n", __func__); return strdup("vga"); } #endif static void unset_run(int signo) { (void) signo; run = 0; } #ifdef HAVE_SIGACTION static int set_signal_handler(void (*signal_handler)(int)) { struct sigaction new_action; struct sigaction old_action; int ret; new_action.sa_handler = signal_handler; sigemptyset(&new_action.sa_mask); new_action.sa_flags = 0; ret = sigaction(SIGINT, NULL, &old_action); if (ret < 0) { perror("sigaction on old_action"); goto out; } if (old_action.sa_handler != SIG_IGN) { ret = sigaction(SIGINT, &new_action, NULL); if (ret < 0) { perror("sigaction on new_action"); goto out; } } out: return ret; } #else static int set_signal_handler(void (*signal_handler)(int)) { (void)signal_handler; fprintf(stderr, "set_signal_handler() not implemented, sigaction not available\n"); return 0; } #endif static void usage(char *name) { printf("usage: %s [OPTIONS]\n\n", name); printf("OPTIONS:\n"); printf("\t-d \t\tthe device index (default is 0)\n"); #ifdef DEBUG printf("\t-D \t\t\tdump the last frame to a file (only active in DEBUG mode)\n"); #endif printf("\t-f \tthe input device format\n"); printf("\t-i \t\tthe input path\n"); printf("\t-o \t\ta comma separated list of input format options\n"); printf("\t\t\t\tEXAMPLE:\n"); printf("\t\t\t\t\t-o draw_mouse=1,framerate=100,video_size=800x480\n"); printf("\t-s \tthe rescaling method (see swscale.h)\n"); printf("\t-u \t\t\tupscale the image if smaller than the display dimensions\n"); printf("\t-F \t\tthe image format to use (default is JPEG)\n"); printf("\t\t\t\tSUPPORTED FORMATS:\n"); printf("\t\t\t\t\t1 - JPEG\n"); printf("\t\t\t\t\t2 - NV12\n"); printf("\t-q \t\tquality of jpeg sent to the device, between 1 and 100\n"); printf("\t-l \t\tthe verbosity level of libam7xxx output (0-5)\n"); printf("\t-p \t\tthe power mode of device, between %d (off) and %d (turbo)\n", AM7XXX_POWER_OFF, AM7XXX_POWER_TURBO); printf("\t\t\t\tWARNING: Level 2 and greater require the master AND\n"); printf("\t\t\t\t the slave connector to be plugged in.\n"); printf("\t-z \t\tthe display zoom mode, between %d (original) and %d (tele)\n", AM7XXX_ZOOM_ORIGINAL, AM7XXX_ZOOM_TELE); printf("\t-h \t\t\tthis help message\n"); printf("\n\nEXAMPLES OF USE:\n"); printf("\t%s -f x11grab -i :0.0 -o video_size=800x480\n", name); printf("\t%s -f fbdev -i /dev/fb0\n", name); printf("\t%s -f video4linux2 -i /dev/video0 -o video_size=320x240,frame_rate=100 -u -q 90\n", name); printf("\t%s -i http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_640x360.m4v\n", name); } int main(int argc, char *argv[]) { int ret; int opt; char *subopts; char *subopts_saved; char *subopt; char *input_format_string = NULL; AVDictionary *options = NULL; char *input_path = NULL; unsigned int rescale_method = SWS_BICUBIC; unsigned int upscale = 0; unsigned int quality = 95; int log_level = AM7XXX_LOG_INFO; int device_index = 0; int power_mode = AM7XXX_POWER_LOW; int zoom = AM7XXX_ZOOM_ORIGINAL; int format = AM7XXX_IMAGE_FORMAT_JPEG; am7xxx_context *ctx; am7xxx_device *dev; int dump_frame = 0; while ((opt = getopt(argc, argv, "d:Df:i:o:s:uF:q:l:p:z:h")) != -1) { switch (opt) { case 'd': device_index = atoi(optarg); if (device_index < 0) { fprintf(stderr, "Unsupported device index\n"); ret = -EINVAL; goto out; } break; case 'D': dump_frame = 1; #ifndef DEBUG fprintf(stderr, "Warning: the -D option is only active in DEBUG mode.\n"); #endif break; case 'f': input_format_string = strdup(optarg); break; case 'i': input_path = strdup(optarg); break; case 'o': #ifdef HAVE_STRTOK_R /* * parse suboptions, the expected format is something * like: * draw_mouse=1,framerate=100,video_size=800x480 */ subopts = subopts_saved = strdup(optarg); while ((subopt = strtok_r(subopts, ",", &subopts))) { char *subopt_name = strtok_r(subopt, "=", &subopt); char *subopt_value = strtok_r(NULL, "", &subopt); if (subopt_value == NULL) { fprintf(stderr, "invalid suboption: %s\n", subopt_name); continue; } av_dict_set(&options, subopt_name, subopt_value, 0); } free(subopts_saved); #else fprintf(stderr, "Option '-o' not implemented\n"); #endif break; case 's': rescale_method = atoi(optarg); switch(rescale_method) { case SWS_FAST_BILINEAR: case SWS_BILINEAR: case SWS_BICUBIC: case SWS_X: case SWS_POINT: case SWS_AREA: case SWS_BICUBLIN: case SWS_GAUSS: case SWS_SINC: case SWS_LANCZOS: case SWS_SPLINE: break; default: fprintf(stderr, "Unsupported rescale method\n"); ret = -EINVAL; goto out; } break; case 'u': upscale = 1; break; case 'F': format = atoi(optarg); switch(format) { case AM7XXX_IMAGE_FORMAT_JPEG: fprintf(stdout, "JPEG format\n"); break; case AM7XXX_IMAGE_FORMAT_NV12: fprintf(stdout, "NV12 format\n"); break; default: fprintf(stderr, "Unsupported format\n"); ret = -EINVAL; goto out; } break; case 'q': quality = atoi(optarg); if (quality < 1 || quality > 100) { fprintf(stderr, "Invalid quality value, must be between 1 and 100\n"); ret = -EINVAL; goto out; } break; case 'l': log_level = atoi(optarg); if (log_level < AM7XXX_LOG_FATAL || log_level > AM7XXX_LOG_TRACE) { fprintf(stderr, "Unsupported log level, falling back to AM7XXX_LOG_ERROR\n"); log_level = AM7XXX_LOG_ERROR; } break; case 'p': power_mode = atoi(optarg); switch(power_mode) { case AM7XXX_POWER_OFF: case AM7XXX_POWER_LOW: case AM7XXX_POWER_MIDDLE: case AM7XXX_POWER_HIGH: case AM7XXX_POWER_TURBO: fprintf(stdout, "Power mode: %d\n", power_mode); break; default: fprintf(stderr, "Invalid power mode value, must be between %d and %d\n", AM7XXX_POWER_OFF, AM7XXX_POWER_TURBO); ret = -EINVAL; goto out; } break; case 'z': zoom = atoi(optarg); switch(zoom) { case AM7XXX_ZOOM_ORIGINAL: case AM7XXX_ZOOM_H: case AM7XXX_ZOOM_H_V: case AM7XXX_ZOOM_TEST: case AM7XXX_ZOOM_TELE: fprintf(stdout, "Zoom: %d\n", zoom); break; default: fprintf(stderr, "Invalid zoom mode value, must be between %d and %d\n", AM7XXX_ZOOM_ORIGINAL, AM7XXX_ZOOM_TELE); ret = -EINVAL; goto out; } break; case 'h': usage(argv[0]); ret = 0; goto out; default: /* '?' */ usage(argv[0]); ret = -EINVAL; goto out; } } if (input_path == NULL) { fprintf(stderr, "The -i option must always be passed\n\n"); usage(argv[0]); ret = -EINVAL; goto out; } /* * When the input format is 'x11grab' set some useful fallback options * if not supplied by the user, in particular grab full screen */ if (input_format_string && strcmp(input_format_string, "x11grab") == 0) { char *video_size; video_size = get_x_screen_size(input_path); if (!av_dict_get(options, "video_size", NULL, 0)) av_dict_set(&options, "video_size", video_size, 0); if (!av_dict_get(options, "framerate", NULL, 0)) av_dict_set(&options, "framerate", "60", 0); if (!av_dict_get(options, "draw_mouse", NULL, 0)) av_dict_set(&options, "draw_mouse", "1", 0); free(video_size); } ret = set_signal_handler(unset_run); if (ret < 0) { perror("sigaction"); goto out; } ret = am7xxx_init(&ctx); if (ret < 0) { perror("am7xxx_init"); goto out; } am7xxx_set_log_level(ctx, log_level); ret = am7xxx_open_device(ctx, &dev, device_index); if (ret < 0) { perror("am7xxx_open_device"); goto cleanup; } ret = am7xxx_set_zoom_mode(dev, zoom); if (ret < 0) { perror("am7xxx_set_zoom_mode"); goto cleanup; } ret = am7xxx_set_power_mode(dev, power_mode); if (ret < 0) { perror("am7xxx_set_power_mode"); goto cleanup; } /* When setting AM7XXX_ZOOM_TEST don't display the actual image */ if (zoom == AM7XXX_ZOOM_TEST) goto cleanup; ret = am7xxx_play(input_format_string, &options, input_path, rescale_method, upscale, quality, format, dev, dump_frame); if (ret < 0) { fprintf(stderr, "am7xxx_play failed\n"); goto cleanup; } cleanup: am7xxx_shutdown(ctx); out: av_dict_free(&options); free(input_path); free(input_format_string); return ret; } libam7xxx-0.1.7/examples/picoproj.c000066400000000000000000000164371324602670600172720ustar00rootroot00000000000000/* picoproj - test program for libam7xxx * * Copyright (C) 2012-2014 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. * * 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 . */ /** * @example examples/picoproj.c * A minimal example to show how to use libam7xxx to display a static image. */ #include #include #include #include #include #include #include #include #include "am7xxx.h" static void usage(char *name) { printf("usage: %s [OPTIONS]\n\n", name); printf("OPTIONS:\n"); printf("\t-d \t\tthe device index (default is 0)\n"); printf("\t-f \t\tthe image file to upload\n"); printf("\t-F \t\tthe image format to use (default is JPEG)\n"); printf("\t\t\t\tSUPPORTED FORMATS:\n"); printf("\t\t\t\t\t1 - JPEG\n"); printf("\t\t\t\t\t2 - NV12\n"); printf("\t-l \t\tthe verbosity level of libam7xxx output (0-5)\n"); printf("\t-p \t\tthe power mode of device, between %d (off) and %d (turbo)\n", AM7XXX_POWER_OFF, AM7XXX_POWER_TURBO); printf("\t\t\t\tWARNING: Level 2 and greater require the master AND\n"); printf("\t\t\t\t the slave connector to be plugged in.\n"); printf("\t-z \t\tthe display zoom mode, between %d (original) and %d (tele)\n", AM7XXX_ZOOM_ORIGINAL, AM7XXX_ZOOM_TELE); printf("\t-W \tthe width of the image to upload\n"); printf("\t-H \tthe height of the image to upload\n"); printf("\t-h \t\t\tthis help message\n"); printf("\n\nEXAMPLE OF USE:\n"); printf("\t%s -f file.jpg -F 1 -l 5 -W 800 -H 480\n", name); } int main(int argc, char *argv[]) { int ret; int opt; char filename[FILENAME_MAX] = {0}; FILE *image_fp; struct stat st; am7xxx_context *ctx; am7xxx_device *dev; int log_level = AM7XXX_LOG_INFO; int device_index = 0; 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; off_t size; am7xxx_device_info device_info; while ((opt = getopt(argc, argv, "d:f:F:l:p:z:W:H:h")) != -1) { switch (opt) { case 'd': device_index = atoi(optarg); if (device_index < 0) { fprintf(stderr, "Unsupported device index\n"); ret = -EINVAL; goto out; } break; case 'f': if (filename[0] != '\0') fprintf(stderr, "Warning: image file already specified\n"); strncpy(filename, optarg, FILENAME_MAX); break; case 'F': format = atoi(optarg); switch(format) { case AM7XXX_IMAGE_FORMAT_JPEG: fprintf(stdout, "JPEG format\n"); break; case AM7XXX_IMAGE_FORMAT_NV12: fprintf(stdout, "NV12 format\n"); break; default: fprintf(stderr, "Unsupported format\n"); ret = -EINVAL; goto out; } break; case 'l': log_level = atoi(optarg); if (log_level < AM7XXX_LOG_FATAL || log_level > AM7XXX_LOG_TRACE) { fprintf(stderr, "Unsupported log level, falling back to AM7XXX_LOG_ERROR\n"); log_level = AM7XXX_LOG_ERROR; } break; case 'p': power_mode = atoi(optarg); switch(power_mode) { case AM7XXX_POWER_OFF: case AM7XXX_POWER_LOW: case AM7XXX_POWER_MIDDLE: case AM7XXX_POWER_HIGH: case AM7XXX_POWER_TURBO: fprintf(stdout, "Power mode: %d\n", power_mode); break; default: fprintf(stderr, "Invalid power mode value, must be between %d and %d\n", AM7XXX_POWER_OFF, AM7XXX_POWER_TURBO); ret = -EINVAL; goto out; } break; case 'z': zoom = atoi(optarg); switch(zoom) { case AM7XXX_ZOOM_ORIGINAL: case AM7XXX_ZOOM_H: case AM7XXX_ZOOM_H_V: case AM7XXX_ZOOM_TEST: case AM7XXX_ZOOM_TELE: fprintf(stdout, "Zoom: %d\n", zoom); break; default: fprintf(stderr, "Invalid zoom mode value, must be between %d and %d\n", AM7XXX_ZOOM_ORIGINAL, AM7XXX_ZOOM_TELE); ret = -EINVAL; goto out; } break; case 'W': width = atoi(optarg); if (width < 0) { fprintf(stderr, "Unsupported width\n"); ret = -EINVAL; goto out; } break; case 'H': height = atoi(optarg); if (height < 0) { fprintf(stderr, "Unsupported height\n"); ret = -EINVAL; goto out; } break; case 'h': usage(argv[0]); ret = 0; goto out; default: /* '?' */ usage(argv[0]); ret = -EINVAL; goto out; } } if (filename[0] == '\0') { 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"); ret = -EINVAL; goto out; } ret = fstat(fileno(image_fp), &st); if (ret < 0) { perror("fstat"); goto out_close_image_fp; } size = st.st_size; image = malloc(size * sizeof(unsigned char)); if (image == NULL) { perror("malloc"); ret = -ENOMEM; goto out_close_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 if (ferror(image_fp)) perror("fread"); 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"); goto out_free_image; } am7xxx_set_log_level(ctx, log_level); ret = am7xxx_open_device(ctx, &dev, 0); if (ret < 0) { perror("am7xxx_open_device"); goto cleanup; } ret = am7xxx_close_device(dev); if (ret < 0) { perror("am7xxx_close_device"); goto cleanup; } ret = am7xxx_open_device(ctx, &dev, device_index); if (ret < 0) { perror("am7xxx_open_device"); goto cleanup; } ret = am7xxx_get_device_info(dev, &device_info); if (ret < 0) { perror("am7xxx_get_device_info"); goto cleanup; } printf("Native resolution: %dx%d\n", device_info.native_width, device_info.native_height); ret = am7xxx_set_zoom_mode(dev, zoom); if (ret < 0) { perror("am7xxx_set_zoom_mode"); goto cleanup; } ret = am7xxx_set_power_mode(dev, power_mode); if (ret < 0) { perror("am7xxx_set_power_mode"); goto cleanup; } /* When setting AM7XXX_ZOOM_TEST don't display the actual image */ if (zoom == AM7XXX_ZOOM_TEST) { printf("AM7XXX_ZOOM_TEST requested, not sending actual image.\n"); goto cleanup; } if ((unsigned int)width > device_info.native_width || (unsigned int)height > device_info.native_height) 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, (unsigned int)size); if (ret < 0) { perror("am7xxx_send_image"); goto cleanup; } ret = 0; cleanup: am7xxx_shutdown(ctx); out_free_image: free(image); out_close_image_fp: if (fclose(image_fp) == EOF) perror("fclose"); out: return ret; } libam7xxx-0.1.7/src/000077500000000000000000000000001324602670600142375ustar00rootroot00000000000000libam7xxx-0.1.7/src/CMakeLists.txt000066400000000000000000000030551324602670600170020ustar00rootroot00000000000000add_definitions("-D_DEFAULT_SOURCE") # for htole32() add_definitions("-D_POSIX_C_SOURCE=200112L") # for nanosleep() and lroundf() # Express a preference for C99 format strings when using MinGW, see: # https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/ add_definitions("-D__USE_MINGW_ANSI_STDIO=1") # Find packages needed to build library find_package(libusb-1.0 REQUIRED) include_directories(${LIBUSB_1_INCLUDE_DIRS}) set(SRC am7xxx.c serialize.c tools.c) # Build the library add_library(am7xxx SHARED ${SRC}) set_target_properties(am7xxx PROPERTIES VERSION ${PROJECT_VER} SOVERSION ${PROJECT_APIVER}) install(TARGETS am7xxx DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") add_library(am7xxx-static STATIC ${SRC}) set_target_properties(am7xxx-static PROPERTIES OUTPUT_NAME am7xxx) if(UNIX AND NOT APPLE) set_target_properties(am7xxx-static PROPERTIES COMPILE_FLAGS "-fPIC") endif() install(TARGETS am7xxx-static DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") if(NOT WIN32) find_library(MATH_LIB m) else() # not needed on windows set(MATH_LIB "") endif() target_link_libraries(am7xxx ${MATH_LIB} ${LIBUSB_1_LIBRARIES}) target_link_libraries(am7xxx-static ${MATH_LIB} ${LIBUSB_1_LIBRARIES}) # Install the header files install(FILES "am7xxx.h" DESTINATION "${CMAKE_INSTALL_PREFIX}/include") if(UNIX AND NOT APPLE) # Produce a pkg-config file for linking against the shared lib configure_file("libam7xxx.pc.in" "libam7xxx.pc" @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libam7xxx.pc" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig") endif() libam7xxx-0.1.7/src/am7xxx.c000066400000000000000000001106641324602670600156470ustar00rootroot00000000000000/* am7xxx - communication with AM7xxx based USB Pico Projectors and DPFs * * Copyright (C) 2012-2014 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 #include #include #include #include #include "am7xxx.h" #include "serialize.h" #include "tools.h" #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* * If we're not using GNU C, elide __attribute__ * taken from: http://unixwiz.net/techtips/gnu-c-attributes.html) */ #ifndef __GNUC__ #define __attribute__(x) /* NOTHING */ #endif /* * Fix printf format when compiling for Windows with MinGW, see: * https://sourceforge.net/p/mingw-w64/wiki2/gnu%20printf/ */ #ifdef __MINGW_PRINTF_FORMAT #define AM7XXX_PRINTF_FORMAT __MINGW_PRINTF_FORMAT #else #define AM7XXX_PRINTF_FORMAT printf #endif /* Control shared library symbols visibility */ #if defined _WIN32 || defined __CYGWIN__ #define AM7XXX_PUBLIC __declspec(dllexport) #define AM7XXX_LOCAL #else #if __GNUC__ >= 4 #define AM7XXX_PUBLIC __attribute__ ((visibility ("default"))) #define AM7XXX_LOCAL __attribute__ ((visibility ("hidden"))) #else #define AM7XXX_PUBLIC #define AM7XXX_LOCAL #endif #endif static void log_message(am7xxx_context *ctx, int level, const char *function_name, int line, const char *fmt, ...) __attribute__ ((format (AM7XXX_PRINTF_FORMAT, 5, 6))); #define fatal(...) log_message(NULL, AM7XXX_LOG_FATAL, __func__, __LINE__, __VA_ARGS__) #define error(ctx, ...) log_message(ctx, AM7XXX_LOG_ERROR, __func__, __LINE__, __VA_ARGS__) #define warning(ctx, ...) log_message(ctx, AM7XXX_LOG_WARNING, __func__, 0, __VA_ARGS__) #define info(ctx, ...) log_message(ctx, AM7XXX_LOG_INFO, __func__, 0, __VA_ARGS__) #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__) struct am7xxx_ops { int (*set_power_mode)(am7xxx_device *dev, am7xxx_power_mode power); int (*set_zoom_mode)(am7xxx_device *dev, am7xxx_zoom_mode zoom); }; 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 */ struct am7xxx_ops ops; }; static int default_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power); static int picopix_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power); static int default_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom); static int picopix_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom); #define DEFAULT_OPS { \ .set_power_mode = default_set_power_mode, \ .set_zoom_mode = default_set_zoom_mode, \ } static const struct am7xxx_usb_device_descriptor supported_devices[] = { { .name = "Acer C110", .vendor_id = 0x1de1, .product_id = 0xc101, .configuration = 2, .interface_number = 0, .ops = DEFAULT_OPS, }, { .name = "Acer C112", .vendor_id = 0x1de1, .product_id = 0x5501, .configuration = 2, .interface_number = 0, .ops = DEFAULT_OPS, }, { .name ="Aiptek PocketCinema T25", .vendor_id = 0x08ca, .product_id = 0x2144, .configuration = 2, .interface_number = 0, .ops = DEFAULT_OPS, }, { .name = "Philips/Sagemcom PicoPix 1020", .vendor_id = 0x21e7, .product_id = 0x000e, .configuration = 2, .interface_number = 0, .ops = DEFAULT_OPS, }, { .name = "Philips/Sagemcom PicoPix 2055", .vendor_id = 0x21e7, .product_id = 0x0016, .configuration = 2, .interface_number = 0, .ops = { .set_power_mode = picopix_set_power_mode, .set_zoom_mode = picopix_set_zoom_mode, }, }, { .name = "Philips/Sagemcom PicoPix 2330", .vendor_id = 0x21e7, .product_id = 0x0019, .configuration = 1, .interface_number = 0, }, }; /* The header size on the wire is known to be always 24 bytes, regardless of * the memory configuration enforced by different architectures or compilers * for struct am7xxx_header */ #define AM7XXX_HEADER_WIRE_SIZE 24 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; }; struct _am7xxx_context { libusb_context *usb_context; int log_level; am7xxx_device *devices_list; }; typedef enum { AM7XXX_PACKET_TYPE_DEVINFO = 0x01, AM7XXX_PACKET_TYPE_IMAGE = 0x02, AM7XXX_PACKET_TYPE_POWER = 0x04, AM7XXX_PACKET_TYPE_ZOOM = 0x05, AM7XXX_PACKET_TYPE_PICOPIX_POWER_LOW = 0x15, AM7XXX_PACKET_TYPE_PICOPIX_POWER_MEDIUM = 0x16, AM7XXX_PACKET_TYPE_PICOPIX_POWER_HIGH = 0x17, AM7XXX_PACKET_TYPE_PICOPIX_ENABLE_TI = 0x18, AM7XXX_PACKET_TYPE_PICOPIX_DISABLE_TI = 0x19, } am7xxx_packet_type; struct am7xxx_generic_header { uint32_t field0; uint32_t field1; uint32_t field2; uint32_t field3; }; struct am7xxx_devinfo_header { uint32_t native_width; uint32_t native_height; uint32_t unknown0; uint32_t unknown1; }; struct am7xxx_image_header { uint32_t format; uint32_t width; uint32_t height; uint32_t image_size; }; struct am7xxx_power_header { uint32_t bit2; uint32_t bit1; uint32_t bit0; }; struct am7xxx_zoom_header { uint32_t bit1; uint32_t bit0; }; /* * Examples of packet headers: * * Image header: * 02 00 00 00 00 10 3e 10 01 00 00 00 20 03 00 00 e0 01 00 00 53 E8 00 00 * * Power header: * 04 00 00 00 00 0c ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ /* Direction of the communication from the host point of view */ #define AM7XXX_DIRECTION_OUT 0 /* host -> device */ #define AM7XXX_DIRECTION_IN 1 /* host <- device */ struct am7xxx_header { uint32_t packet_type; uint8_t direction; uint8_t header_data_len; uint8_t unknown2; uint8_t unknown3; union { struct am7xxx_generic_header data; struct am7xxx_devinfo_header devinfo; struct am7xxx_image_header image; struct am7xxx_power_header power; struct am7xxx_zoom_header zoom; } header_data; }; #ifdef DEBUG static void debug_dump_generic_header(am7xxx_context *ctx, struct am7xxx_generic_header *g) { if (ctx == NULL || g == NULL) return; debug(ctx, "Generic header:\n"); debug(ctx, "\tfield0: 0x%08x (%u)\n", g->field0, g->field0); debug(ctx, "\tfield1: 0x%08x (%u)\n", g->field1, g->field1); debug(ctx, "\tfield2: 0x%08x (%u)\n", g->field2, g->field2); debug(ctx, "\tfield3: 0x%08x (%u)\n", g->field3, g->field3); } static void debug_dump_devinfo_header(am7xxx_context *ctx, struct am7xxx_devinfo_header *d) { if (ctx == NULL || d == NULL) return; debug(ctx, "Info header:\n"); debug(ctx, "\tnative_width: 0x%08x (%u)\n", d->native_width, d->native_width); debug(ctx, "\tnative_height: 0x%08x (%u)\n", d->native_height, d->native_height); debug(ctx, "\tunknown0: 0x%08x (%u)\n", d->unknown0, d->unknown0); debug(ctx, "\tunknown1: 0x%08x (%u)\n", d->unknown1, d->unknown1); } static void debug_dump_image_header(am7xxx_context *ctx, struct am7xxx_image_header *i) { if (ctx == NULL || i == NULL) return; debug(ctx, "Image header:\n"); debug(ctx, "\tformat: 0x%08x (%u)\n", i->format, i->format); debug(ctx, "\twidth: 0x%08x (%u)\n", i->width, i->width); debug(ctx, "\theight: 0x%08x (%u)\n", i->height, i->height); debug(ctx, "\timage size: 0x%08x (%u)\n", i->image_size, i->image_size); } static void debug_dump_power_header(am7xxx_context *ctx, struct am7xxx_power_header *p) { if (ctx == NULL || p == NULL) return; debug(ctx, "Power header:\n"); debug(ctx, "\tbit2: 0x%08x (%u)\n", p->bit2, p->bit2); debug(ctx, "\tbit1: 0x%08x (%u)\n", p->bit1, p->bit1); debug(ctx, "\tbit0: 0x%08x (%u)\n", p->bit0, p->bit0); } static void debug_dump_zoom_header(am7xxx_context *ctx, struct am7xxx_zoom_header *z) { if (ctx == NULL || z == NULL) return; debug(ctx, "Zoom header:\n"); debug(ctx, "\tbit1: 0x%08x (%u)\n", z->bit1, z->bit1); debug(ctx, "\tbit0: 0x%08x (%u)\n", z->bit0, z->bit0); } static void debug_dump_header(am7xxx_context *ctx, struct am7xxx_header *h) { if (ctx == NULL || h == NULL) return; debug(ctx, "BEGIN\n"); debug(ctx, "packet_type: 0x%08x (%u)\n", h->packet_type, h->packet_type); debug(ctx, "direction: 0x%02hhx (%hhu) (%s)\n", h->direction, h->direction, h->direction == AM7XXX_DIRECTION_IN ? "IN" : h->direction == AM7XXX_DIRECTION_OUT ? "OUT" : "UNKNOWN"); debug(ctx, "header_data_len: 0x%02hhx (%hhu)\n", h->header_data_len, h->header_data_len); debug(ctx, "unknown2: 0x%02hhx (%hhu)\n", h->unknown2, h->unknown2); debug(ctx, "unknown3: 0x%02hhx (%hhu)\n", h->unknown3, h->unknown3); switch(h->packet_type) { case AM7XXX_PACKET_TYPE_DEVINFO: debug_dump_devinfo_header(ctx, &(h->header_data.devinfo)); break; case AM7XXX_PACKET_TYPE_IMAGE: debug_dump_image_header(ctx, &(h->header_data.image)); break; case AM7XXX_PACKET_TYPE_POWER: debug_dump_power_header(ctx, &(h->header_data.power)); break; case AM7XXX_PACKET_TYPE_ZOOM: debug_dump_zoom_header(ctx, &(h->header_data.zoom)); break; default: debug(ctx, "Parsing data not supported for this packet type!\n"); debug_dump_generic_header(ctx, &(h->header_data.data)); break; } debug(ctx, "END\n\n"); } static inline unsigned int in_80chars(unsigned int i) { /* The 3 below is the length of "xx " where xx is the hex string * representation of a byte */ return ((i + 1) % (80 / 3)); } static void trace_dump_buffer(am7xxx_context *ctx, const char *message, uint8_t *buffer, unsigned int len) { unsigned int i; if (ctx == NULL || buffer == NULL || len == 0) return; trace(ctx, "\n"); if (message) trace(ctx, "%s\n", message); for (i = 0; i < len; i++) { trace(ctx, "%02hhX%c", buffer[i], (in_80chars(i) && (i < len - 1)) ? ' ' : '\n'); } trace(ctx, "\n"); } #else static void debug_dump_header(am7xxx_context *ctx, struct am7xxx_header *h) { (void)ctx; (void)h; } static void trace_dump_buffer(am7xxx_context *ctx, const char *message, uint8_t *buffer, unsigned int len) { (void)ctx; (void)message; (void)buffer; (void)len; } #endif /* DEBUG */ static int read_data(am7xxx_device *dev, uint8_t *buffer, unsigned int len) { int ret; int transferred; transferred = 0; ret = libusb_bulk_transfer(dev->usb_device, 0x81, buffer, len, &transferred, 0); if (ret != 0 || (unsigned int)transferred != len) { error(dev->ctx, "%s. Transferred: %d (expected %u)\n", libusb_error_name(ret), transferred, len); return ret; } trace_dump_buffer(dev->ctx, "<-- received", buffer, len); return 0; } static int send_data(am7xxx_device *dev, uint8_t *buffer, unsigned int len) { int ret; int transferred; trace_dump_buffer(dev->ctx, "sending -->", buffer, len); transferred = 0; ret = libusb_bulk_transfer(dev->usb_device, 0x1, buffer, len, &transferred, 0); if (ret != 0 || (unsigned int)transferred != len) { error(dev->ctx, "%s. Transferred: %d (expected %u)\n", libusb_error_name(ret), transferred, len); return ret; } return 0; } static void LIBUSB_CALL 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 dynamic allocations compared to 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; put_le32(h->packet_type, buffer_iterator); put_8(h->direction, buffer_iterator); put_8(h->header_data_len, buffer_iterator); put_8(h->unknown2, buffer_iterator); put_8(h->unknown3, buffer_iterator); put_le32(h->header_data.data.field0, buffer_iterator); put_le32(h->header_data.data.field1, buffer_iterator); put_le32(h->header_data.data.field2, buffer_iterator); put_le32(h->header_data.data.field3, buffer_iterator); } static void unserialize_header(uint8_t *buffer, struct am7xxx_header *h) { uint8_t **buffer_iterator = &buffer; h->packet_type = get_le32(buffer_iterator); h->direction = get_8(buffer_iterator); h->header_data_len = get_8(buffer_iterator); h->unknown2 = get_8(buffer_iterator); h->unknown3 = get_8(buffer_iterator); h->header_data.data.field0 = get_le32(buffer_iterator); h->header_data.data.field1 = get_le32(buffer_iterator); h->header_data.data.field2 = get_le32(buffer_iterator); h->header_data.data.field3 = get_le32(buffer_iterator); } static int read_header(am7xxx_device *dev, struct am7xxx_header *h) { int ret; ret = read_data(dev, dev->buffer, AM7XXX_HEADER_WIRE_SIZE); if (ret < 0) goto out; unserialize_header(dev->buffer, h); if (h->direction == AM7XXX_DIRECTION_IN) { ret = 0; } else { error(dev->ctx, "Expected an AM7XXX_DIRECTION_IN packet, got one with direction = %d. Weird!\n", h->direction); ret = -EINVAL; } debug_dump_header(dev->ctx, h); out: return ret; } static int send_header(am7xxx_device *dev, struct am7xxx_header *h) { int ret; debug_dump_header(dev->ctx, h); /* For symmetry with read_header() we should check here for * h->direction == AM7XXX_DIRECTION_OUT but we just ensure that in all * the callers and save some cycles here. */ serialize_header(h, dev->buffer); ret = send_data(dev, dev->buffer, AM7XXX_HEADER_WIRE_SIZE); if (ret < 0) error(dev->ctx, "failed to send data\n"); return ret; } static int send_command(am7xxx_device *dev, am7xxx_packet_type type) { struct am7xxx_header h = { .packet_type = type, .direction = AM7XXX_DIRECTION_OUT, .header_data_len = 0x00, .unknown2 = 0x3e, .unknown3 = 0x10, .header_data = { .data = { .field0 = 0, .field1 = 0, .field2 = 0, .field3 = 0, }, }, }; return send_header(dev, &h); } /* When level == AM7XXX_LOG_FATAL do not check the log_level from the context * and print the message unconditionally, this makes it possible to print * fatal messages even early on initialization, before the context has been * set up */ static void log_message(am7xxx_context *ctx, int level, const char *function_name, int line, const char *fmt, ...) { va_list ap; if (level == AM7XXX_LOG_FATAL || (ctx && level <= ctx->log_level)) { if (function_name) { fprintf(stderr, "%s", function_name); if (line) fprintf(stderr, "[%d]", line); fprintf(stderr, ": "); } va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } return; } static am7xxx_device *add_new_device(am7xxx_context *ctx, const struct am7xxx_usb_device_descriptor *desc) { am7xxx_device **devices_list; am7xxx_device *new_device; if (ctx == NULL) { fatal("context must not be NULL!\n"); return NULL; } new_device = malloc(sizeof(*new_device)); if (new_device == NULL) { debug(ctx, "cannot allocate a new device (%s)\n", strerror(errno)); return NULL; } 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); if (*devices_list == NULL) { *devices_list = new_device; } else { am7xxx_device *prev = *devices_list; while (prev->next) prev = prev->next; prev->next = new_device; } return new_device; } static am7xxx_device *find_device(am7xxx_context *ctx, unsigned int device_index) { unsigned int i = 0; am7xxx_device *current; if (ctx == NULL) { fatal("context must not be NULL!\n"); return NULL; } current = ctx->devices_list; while (current && i++ < device_index) current = current->next; return current; } static int open_device(am7xxx_context *ctx, unsigned int device_index, libusb_device *usb_dev, am7xxx_device **dev) { int ret; int current_configuration; *dev = find_device(ctx, device_index); if (*dev == NULL) { ret = -ENODEV; goto out; } /* the usb device has already been opened */ if ((*dev)->usb_device) { ret = 1; goto out; } ret = libusb_open(usb_dev, &((*dev)->usb_device)); if (ret < 0) { debug(ctx, "libusb_open failed: %s\n", libusb_error_name(ret)); goto out; } /* XXX, the device is now open, if any of the calls below fail we need * to close it again before bailing out. */ current_configuration = -1; ret = libusb_get_configuration((*dev)->usb_device, ¤t_configuration); if (ret < 0) { debug(ctx, "libusb_get_configuration failed: %s\n", libusb_error_name(ret)); goto out_libusb_close; } if (current_configuration != (*dev)->desc->configuration) { /* * In principle, before setting a new configuration, kernel * drivers should be detached from _all_ interfaces; for * example calling something like the following "invented" * function _before_ setting the new configuration: * * libusb_detach_all_kernel_drivers((*dev)->usb_device); * * However, in practice, this is not necessary for most * devices as they have only one configuration. * * When a device only has one configuration: * * - if there was a kernel driver bound to the device, it * had already set the configuration and the call below * will be skipped; * * - if no kernel driver was bound to the device, the call * below will suceed. */ ret = libusb_set_configuration((*dev)->usb_device, (*dev)->desc->configuration); if (ret < 0) { debug(ctx, "libusb_set_configuration failed: %s\n", libusb_error_name(ret)); debug(ctx, "Cannot set configuration %hhu\n", (*dev)->desc->configuration); goto out_libusb_close; } } libusb_set_auto_detach_kernel_driver((*dev)->usb_device, 1); ret = libusb_claim_interface((*dev)->usb_device, (*dev)->desc->interface_number); if (ret < 0) { debug(ctx, "libusb_claim_interface failed: %s\n", libusb_error_name(ret)); debug(ctx, "Cannot claim interface %hhu\n", (*dev)->desc->interface_number); goto out_libusb_close; } /* Checking that the configuration has not changed, as suggested in * http://libusb.sourceforge.net/api-1.0/caveats.html */ current_configuration = -1; ret = libusb_get_configuration((*dev)->usb_device, ¤t_configuration); if (ret < 0) { debug(ctx, "libusb_get_configuration after claim failed: %s\n", libusb_error_name(ret)); goto out_libusb_release_interface; } if (current_configuration != (*dev)->desc->configuration) { debug(ctx, "libusb configuration changed (expected: %hhu, current: %d)\n", (*dev)->desc->configuration, current_configuration); ret = -EINVAL; goto out_libusb_release_interface; } out: return ret; out_libusb_release_interface: libusb_release_interface((*dev)->usb_device, (*dev)->desc->interface_number); out_libusb_close: libusb_close((*dev)->usb_device); (*dev)->usb_device = NULL; return ret; } typedef enum { SCAN_OP_BUILD_DEVLIST, SCAN_OP_OPEN_DEVICE, } scan_op; /** * This is where the central logic of multi-device support is. * * When 'op' == SCAN_OP_BUILD_DEVLIST the parameters 'open_device_index' and * 'dev' are ignored; the function returns 0 on success or a negative value * on error. * * When 'op' == SCAN_OP_OPEN_DEVICE the function opens the supported USB * device with index 'open_device_index' and returns the correspondent * am7xxx_device in the 'dev' parameter; the function returns the value from * open_device(), which is 0 on success, 1 if the device was already open or * a negative value on error. * * NOTES: * if scan_devices() fails when called with 'op' == SCAN_OP_BUILD_DEVLIST, * the caller might want to call am7xxx_shutdown() in order to remove * devices possibly added before the failure. */ static int scan_devices(am7xxx_context *ctx, scan_op op, unsigned int open_device_index, am7xxx_device **dev) { ssize_t num_devices; libusb_device **list; unsigned int current_index; int i; int ret; if (ctx == NULL) { fatal("context must not be NULL!\n"); return -EINVAL; } if (op == SCAN_OP_BUILD_DEVLIST && ctx->devices_list != NULL) { error(ctx, "device scan done already? Abort!\n"); return -EINVAL; } num_devices = libusb_get_device_list(ctx->usb_context, &list); if (num_devices < 0) { ret = -ENODEV; goto out; } current_index = 0; for (i = 0; i < num_devices; i++) { struct libusb_device_descriptor desc; unsigned int j; ret = libusb_get_device_descriptor(list[i], &desc); if (ret < 0) continue; for (j = 0; j < ARRAY_SIZE(supported_devices); j++) { if (desc.idVendor == supported_devices[j].vendor_id && desc.idProduct == supported_devices[j].product_id) { if (op == SCAN_OP_BUILD_DEVLIST) { am7xxx_device *new_device; info(ctx, "am7xxx device found, index: %d, name: %s\n", current_index, supported_devices[j].name); new_device = add_new_device(ctx, &supported_devices[j]); if (new_device == NULL) { /* XXX, the caller may want * to call am7xxx_shutdown() if * we fail here, as we may have * added some devices already */ debug(ctx, "Cannot create a new device\n"); ret = -ENODEV; goto out; } } else if (op == SCAN_OP_OPEN_DEVICE && current_index == open_device_index) { ret = open_device(ctx, open_device_index, list[i], dev); if (ret < 0) debug(ctx, "open_device failed\n"); /* exit the loop unconditionally after * attempting to open the device * requested by the user */ goto out; } current_index++; } } } /* if we made it up to here when op == SCAN_OP_OPEN_DEVICE, * no devices to open had been found. */ if (op == SCAN_OP_OPEN_DEVICE) { error(ctx, "Cannot find any device to open\n"); ret = -ENODEV; goto out; } /* everything went fine when building the device list */ ret = 0; out: libusb_free_device_list(list, 1); return ret; } /* Device specific operations */ static int default_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power) { int ret; struct am7xxx_header h = { .packet_type = AM7XXX_PACKET_TYPE_POWER, .direction = AM7XXX_DIRECTION_OUT, .header_data_len = sizeof(struct am7xxx_power_header), .unknown2 = 0x3e, .unknown3 = 0x10, }; switch(power) { case AM7XXX_POWER_OFF: h.header_data.power.bit2 = 0; h.header_data.power.bit1 = 0; h.header_data.power.bit0 = 0; break; case AM7XXX_POWER_LOW: h.header_data.power.bit2 = 0; h.header_data.power.bit1 = 0; h.header_data.power.bit0 = 1; break; case AM7XXX_POWER_MIDDLE: h.header_data.power.bit2 = 0; h.header_data.power.bit1 = 1; h.header_data.power.bit0 = 0; break; case AM7XXX_POWER_HIGH: h.header_data.power.bit2 = 0; h.header_data.power.bit1 = 1; h.header_data.power.bit0 = 1; break; case AM7XXX_POWER_TURBO: h.header_data.power.bit2 = 1; h.header_data.power.bit1 = 0; h.header_data.power.bit0 = 0; break; default: error(dev->ctx, "Unsupported power mode.\n"); return -EINVAL; }; ret = send_header(dev, &h); if (ret < 0) return ret; return 0; } static int picopix_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power) { switch(power) { case AM7XXX_POWER_LOW: return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_LOW); case AM7XXX_POWER_MIDDLE: return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_MEDIUM); case AM7XXX_POWER_HIGH: return send_command(dev, AM7XXX_PACKET_TYPE_PICOPIX_POWER_HIGH); case AM7XXX_POWER_OFF: case AM7XXX_POWER_TURBO: default: error(dev->ctx, "Unsupported power mode.\n"); return -EINVAL; }; } static int default_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom) { int ret; struct am7xxx_header h = { .packet_type = AM7XXX_PACKET_TYPE_ZOOM, .direction = AM7XXX_DIRECTION_OUT, .header_data_len = sizeof(struct am7xxx_zoom_header), .unknown2 = 0x3e, .unknown3 = 0x10, }; switch(zoom) { case AM7XXX_ZOOM_ORIGINAL: h.header_data.zoom.bit1 = 0; h.header_data.zoom.bit0 = 0; break; case AM7XXX_ZOOM_H: h.header_data.zoom.bit1 = 0; h.header_data.zoom.bit0 = 1; break; case AM7XXX_ZOOM_H_V: h.header_data.zoom.bit1 = 1; h.header_data.zoom.bit0 = 0; break; case AM7XXX_ZOOM_TEST: h.header_data.zoom.bit1 = 1; h.header_data.zoom.bit0 = 1; break; case AM7XXX_ZOOM_TELE: default: error(dev->ctx, "Unsupported zoom mode.\n"); return -EINVAL; }; ret = send_header(dev, &h); if (ret < 0) return ret; return 0; } static int picopix_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom) { int ret; am7xxx_packet_type packet_type; switch(zoom) { case AM7XXX_ZOOM_ORIGINAL: packet_type = AM7XXX_PACKET_TYPE_PICOPIX_DISABLE_TI; break; case AM7XXX_ZOOM_TELE: packet_type = AM7XXX_PACKET_TYPE_PICOPIX_ENABLE_TI; break; case AM7XXX_ZOOM_H: case AM7XXX_ZOOM_H_V: case AM7XXX_ZOOM_TEST: default: error(dev->ctx, "Unsupported zoom mode.\n"); return -EINVAL; }; ret = send_command(dev, packet_type); if (ret < 0) return ret; /* The Windows drivers wait for 100ms and send the same command again, * probably to overcome a firmware deficiency */ ret = msleep(100); if (ret < 0) return ret; return send_command(dev, packet_type); } /* Public API */ AM7XXX_PUBLIC int am7xxx_init(am7xxx_context **ctx) { int ret; *ctx = malloc(sizeof(**ctx)); if (*ctx == NULL) { fatal("cannot allocate the context (%s)\n", strerror(errno)); return -ENOMEM; } memset(*ctx, 0, sizeof(**ctx)); /* Set the highest log level during initialization */ (*ctx)->log_level = AM7XXX_LOG_TRACE; ret = libusb_init(&((*ctx)->usb_context)); if (ret < 0) { error(*ctx, "libusb_init failed: %s\n", libusb_error_name(ret)); goto out_free_context; } libusb_set_debug((*ctx)->usb_context, LIBUSB_LOG_LEVEL_INFO); ret = scan_devices(*ctx, SCAN_OP_BUILD_DEVLIST , 0, NULL); if (ret < 0) { error(*ctx, "scan_devices() failed\n"); am7xxx_shutdown(*ctx); goto out; } /* Set a quieter log level as default for normal operation */ (*ctx)->log_level = AM7XXX_LOG_ERROR; return 0; out_free_context: free(*ctx); *ctx = NULL; out: return ret; } AM7XXX_PUBLIC void am7xxx_shutdown(am7xxx_context *ctx) { am7xxx_device *current; if (ctx == NULL) { fatal("context must not be NULL!\n"); return; } current = ctx->devices_list; while (current) { am7xxx_device *next = current->next; am7xxx_close_device(current); free(current->device_info); free(current); current = next; } libusb_exit(ctx->usb_context); free(ctx); ctx = NULL; } AM7XXX_PUBLIC void am7xxx_set_log_level(am7xxx_context *ctx, am7xxx_log_level log_level) { ctx->log_level = log_level; } AM7XXX_PUBLIC int am7xxx_open_device(am7xxx_context *ctx, am7xxx_device **dev, unsigned int device_index) { int ret; if (ctx == NULL) { fatal("context must not be NULL!\n"); return -EINVAL; } ret = scan_devices(ctx, SCAN_OP_OPEN_DEVICE, device_index, dev); if (ret < 0) { errno = ENODEV; goto out; } else if (ret > 0) { warning(ctx, "device %d already open\n", device_index); errno = EBUSY; ret = -EBUSY; goto out; } /* Philips/Sagemcom PicoPix projectors require that the DEVINFO packet * is the first one to be sent to the device in order for it to * successfully return the correct device information. * * NOTE: am7xxx_get_device_info() will fetch the actual device info * from the device only the very first time it's called for a given * device, otherwise, it'll return a cached version of the device info * (from a previous call to am7xxx_open_device(), for instance). */ ret = am7xxx_get_device_info(*dev, NULL); if (ret < 0) error(ctx, "cannot get device info\n"); out: return ret; } AM7XXX_PUBLIC int am7xxx_close_device(am7xxx_device *dev) { if (dev == NULL) { fatal("dev must not be NULL!\n"); return -EINVAL; } if (dev->usb_device) { 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 0; } AM7XXX_PUBLIC int am7xxx_get_device_info(am7xxx_device *dev, am7xxx_device_info *device_info) { int ret; struct am7xxx_header h; /* if there is a cached copy of the device info, just return that */ if (dev->device_info) goto return_value; ret = send_command(dev, AM7XXX_PACKET_TYPE_DEVINFO); if (ret < 0) return ret; memset(&h, 0, sizeof(h)); ret = read_header(dev, &h); if (ret < 0) return ret; if (h.packet_type != AM7XXX_PACKET_TYPE_DEVINFO) { error(dev->ctx, "expected packet type: %d, got %d instead!\n", AM7XXX_PACKET_TYPE_DEVINFO, h.packet_type); errno = EINVAL; return -EINVAL; } dev->device_info = malloc(sizeof(*dev->device_info)); if (dev->device_info == NULL) { error(dev->ctx, "cannot allocate a device info (%s)\n", strerror(errno)); return -ENOMEM; } memset(dev->device_info, 0, sizeof(*dev->device_info)); dev->device_info->native_width = h.header_data.devinfo.native_width; dev->device_info->native_height = h.header_data.devinfo.native_height; #if 0 /* No reason to expose these in the public API until we know what they mean */ dev->device_info->unknown0 = h.header_data.devinfo.unknown0; dev->device_info->unknown1 = h.header_data.devinfo.unknown1; #endif return_value: if (device_info) memcpy(device_info, dev->device_info, sizeof(*device_info)); return 0; } AM7XXX_PUBLIC int am7xxx_calc_scaled_image_dimensions(am7xxx_device *dev, unsigned int upscale, unsigned int original_width, unsigned int original_height, unsigned int *scaled_width, unsigned int *scaled_height) { am7xxx_device_info device_info; float width_ratio; float height_ratio; int ret; ret = am7xxx_get_device_info(dev, &device_info); if (ret < 0) { error(dev->ctx, "cannot get device info\n"); return ret; } /* * Check if we need to rescale; if the input image fits the native * dimensions there is no need to, unless we want to upscale. */ if (!upscale && original_width <= device_info.native_width && original_height <= device_info.native_height ) { debug(dev->ctx, "CASE 0, no rescaling, the original image fits already\n"); *scaled_width = original_width; *scaled_height = original_height; return 0; } /* Input dimensions relative to the device native dimensions */ width_ratio = (float)original_width / device_info.native_width; height_ratio = (float)original_height / device_info.native_height; if (width_ratio > height_ratio) { /* * The input is proportionally "wider" than the device viewport * so its height needs to be adjusted */ debug(dev->ctx, "CASE 1, original image wider, adjust the scaled height\n"); *scaled_width = device_info.native_width; *scaled_height = (unsigned int)lroundf(original_height / width_ratio); } else if (width_ratio < height_ratio) { /* * The input is proportionally "taller" than the device viewport * so its width needs to be adjusted */ debug(dev->ctx, "CASE 2 original image taller, adjust the scaled width\n"); *scaled_width = (unsigned int)lroundf(original_width / height_ratio); *scaled_height = device_info.native_height; } else { debug(dev->ctx, "CASE 3, just rescale, same aspect ratio already\n"); *scaled_width = device_info.native_width; *scaled_height = device_info.native_height; } debug(dev->ctx, "scaled dimensions: %dx%d\n", *scaled_width, *scaled_height); return 0; } AM7XXX_PUBLIC int am7xxx_send_image(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(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) { if (dev->desc->ops.set_power_mode == NULL) { warning(dev->ctx, "setting power mode is unsupported on this device\n"); return 0; } return dev->desc->ops.set_power_mode(dev, power); } AM7XXX_PUBLIC int am7xxx_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom) { if (dev->desc->ops.set_zoom_mode == NULL) { warning(dev->ctx, "setting zoom mode is unsupported on this device\n"); return 0; } return dev->desc->ops.set_zoom_mode(dev, zoom); } libam7xxx-0.1.7/src/am7xxx.h000066400000000000000000000267711324602670600156610ustar00rootroot00000000000000/* am7xxx - communication with AM7XXX based USB Pico Projectors and DPFs * * Copyright (C) 2012-2014 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 . */ /** * @file * Public libam7xxx API. */ #ifndef __AM7XXX_H #define __AM7XXX_H #ifdef __cplusplus extern "C" { #endif /** * @typedef am7xxx_context * * An opaque data type representing a context. */ struct _am7xxx_context; typedef struct _am7xxx_context am7xxx_context; /** * @typedef am7xxx_device * * An opaque data type representing an am7xxx device. */ struct _am7xxx_device; typedef struct _am7xxx_device am7xxx_device; /** * A struct describing device specific properties. * * A user program may want to inspect these before providing data to the * device. For instance, when sending an image the user may want to rescale it * to the device native width and height in order to be sure the image will be * displayed in its entirety. */ typedef struct { unsigned int native_width; /**< The device native width. */ unsigned int native_height; /**< The device native height. */ } am7xxx_device_info; /** * The verbosity level of logging messages. * * This can be set with am7xxx_set_log_level() and the level will be used * internally by libam7xxx to adjust the granularity of the information * exposed to the user about the internal library operations. */ typedef enum { AM7XXX_LOG_FATAL = 0, /**< Fatal messages, the user application should stop if it gets one of this. */ AM7XXX_LOG_ERROR = 1, /**< Error messages, typically they describe API functions failures. */ AM7XXX_LOG_WARNING = 2, /**< Warnings about conditions worth mentioning to the user. */ AM7XXX_LOG_INFO = 3, /**< Informations about the device operations. */ AM7XXX_LOG_DEBUG = 4, /**< Informations about the library internals. */ AM7XXX_LOG_TRACE = 5, /**< Verbose informations about the communication with the hardware. */ } am7xxx_log_level; /** * The image formats accepted by the device. */ typedef enum { AM7XXX_IMAGE_FORMAT_JPEG = 1, /**< JPEG format. */ AM7XXX_IMAGE_FORMAT_NV12 = 2, /**< Raw YUV in the NV12 variant. */ } am7xxx_image_format; /** * The device power modes. * * An am7xxx device can operate in several power modes. A certain power mode * may have effect on the display brightness or on the device power * consumption. * * @note Most am7xxx devices come with a Y-shaped USB cable with a Master and * a Slave connector, higher power modes may require that both connectors are * plugged in to the host system for the device to work properly. * * @note At higher power modes some devices may use a fan to cool down the * internal hardware components, and hence may be noisier in this case. */ typedef enum { AM7XXX_POWER_OFF = 0, /**< Display is powered off, no image shown. */ AM7XXX_POWER_LOW = 1, /**< Low power consumption but also low brightness. */ AM7XXX_POWER_MIDDLE = 2, /**< Middle level of brightness. This and upper modes need both the Master and Slave USB connectors plugged. */ AM7XXX_POWER_HIGH = 3, /**< More brightness, but more power consumption. */ AM7XXX_POWER_TURBO = 4, /**< Max brightness and power consumption. */ } am7xxx_power_mode; /** * The display zoom modes. * * An am7xxx device can display images using several zoom modes. * * @note Changing the zoom mode can change the aspect ratio of the displayed * image. * * @note On the zoom test screen the version of the firmware running on the * device is shown as well (e.g SPI_V21.0.0_2011.03.18). * * @note The Tele mode is available only on some PicoPix models, when using it * the image is distorted like if a different lens was used, but the global * aspect ratio of the image does not change. */ typedef enum { AM7XXX_ZOOM_ORIGINAL = 0, /**< Original Size, as retrieved via #am7xxx_device_info. */ AM7XXX_ZOOM_H = 1, /**< Zoom 1: H Scale (changes aspect ratio). */ AM7XXX_ZOOM_H_V = 2, /**< Zoom 2: H/V Scale (changes aspect ratio). */ AM7XXX_ZOOM_TEST = 3, /**< Zoom test screen, the firmware version is shown as well. */ AM7XXX_ZOOM_TELE = 4, /**< Zoom Tele: available on some PicoPix models. */ } am7xxx_zoom_mode; /** * Initialize the library context and data structures, and scan for devices. * * @param[out] ctx A pointer to the context the library will be used in. * * @return 0 on success, a negative value on error */ int am7xxx_init(am7xxx_context **ctx); /** * Cleanup the library data structures and free the context. * * @param[in,out] ctx The context to free. */ void am7xxx_shutdown(am7xxx_context *ctx); /** * Set verbosity level of log messages. * * @note The level is per-context. * * @note Messages of level AM7XXX_LOG_FATAL are always shown, regardless * of the value of the log_level parameter. * * @param[in] ctx The context to set the log level for * @param[in] log_level The verbosity level to use in the context (see @link am7xxx_log_level @endlink) */ void am7xxx_set_log_level(am7xxx_context *ctx, am7xxx_log_level log_level); /** * Open an am7xxx_device according to a index. * * The semantics of the 'device_index' argument follows the order * of the devices as found when scanning the bus at am7xxx_init() time. * * @note When the user tries to open a device already opened the function * returns -EBUSY and the device is left open. * * @param[in] ctx The context to open the device in * @param[out] dev A pointer to the structure representing the device to open * @param[in] device_index The index of the device on the bus * * @return 0 on success, a negative value on error */ int am7xxx_open_device(am7xxx_context *ctx, am7xxx_device **dev, unsigned int device_index); /** * Close an am7xxx_device. * * Close an am7xxx_device so that it becomes available for some other * user/process to open it. * * @param[in] dev A pointer to the structure representing the device to close * * @return 0 on success, a negative value on error */ int am7xxx_close_device(am7xxx_device *dev); /** * Get info about an am7xxx device. * * Get information about a device, in the form of a * @link am7xxx_device_info @endlink structure. * * @param[in] dev A pointer to the structure representing the device to get info of * @param[out] device_info A pointer to the structure where to store the device info (see @link am7xxx_device_info @endlink) * * @return 0 on success, a negative value on error */ int am7xxx_get_device_info(am7xxx_device *dev, am7xxx_device_info *device_info); /** * Calculate the dimensions of an image to be shown on an am7xxx device. * * Before sending images bigger than the device native dimensions the user * needs to rescale them, this utility function does the calculation in a way * that the original image aspect ratio is preserved. * * @param[in] dev A pointer to the structure representing the device to get info of * @param[in] upscale Whether to calculate scaled dimensions for images smaller than the native dimensions * @param[in] original_width The width of the original image * @param[in] original_height The height of the original image * @param[out] scaled_width The width the rescaled image should have * @param[out] scaled_height The height the rescaled image should have * * @return 0 on success, a negative value on error */ int am7xxx_calc_scaled_image_dimensions(am7xxx_device *dev, unsigned int upscale, unsigned int original_width, unsigned int original_height, unsigned int *scaled_width, unsigned int *scaled_height); /** * 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 * until another image get sent or some command resets or turns off the display. * * @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(am7xxx_device *dev, am7xxx_image_format format, unsigned int width, unsigned int height, unsigned char *image, unsigned int image_size); /** * Queue transfer of an image for display on an am7xxx device and return immediately. * * 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 * on again by using only am7xxx_set_power_mode(), am7xxx_set_zoom_mode() has * to be called first, the current guess is that the latter performs some * other resets beside setting the zoom mode. * * @param[in] dev A pointer to the structure representing the device to set power mode to * @param[in] power The power mode to put the device in (see #am7xxx_power_mode enum) * * @return 0 on success, a negative value on error * */ int am7xxx_set_power_mode(am7xxx_device *dev, am7xxx_power_mode power); /** * Set the zoom mode of an am7xxx device. * * @note When setting the mode to AM7XXX_ZOOM_TEST, the calling program might * want to skip displaying actual images. * * @note It looks like that power mode and zoom mode are related somehow wrt. * resetting the operational mode after AM7XXX_POWER_OFF, applications can * restore the display properly using this combination: * - Off: power mode 0, zoom mode 3 * - On: power mode != 0, zoom mode != 3 * * @param[in] dev A pointer to the structure representing the device to set zoom mode to * @param[in] zoom The zoom mode to put the device in (see #am7xxx_zoom_mode enum) * * @return 0 on success, a negative value on error * */ int am7xxx_set_zoom_mode(am7xxx_device *dev, am7xxx_zoom_mode zoom); #ifdef __cplusplus } #endif #endif /* __AM7XXX_H */ libam7xxx-0.1.7/src/libam7xxx.pc.in000066400000000000000000000004161324602670600171140ustar00rootroot00000000000000prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: @PROJECT_NAME@ Description: @PROJECT_DESCRIPTION@ Requires.private: libusb-1.0 Version: @PROJECT_APIVER@ Libs: -L${libdir} -lam7xxx Cflags: -I${includedir} libam7xxx-0.1.7/src/portable_endian.h000066400000000000000000000021421324602670600175350ustar00rootroot00000000000000/* * Public domain, stripped down version of: * https://gist.github.com/panzi/6856583 */ #ifndef __PORTABLE_ENDIAN_H #define __PORTABLE_ENDIAN_H #if (defined(_WIN16) || defined(_WIN32) || defined(_WIN64)) && !defined(__WINDOWS__) # define __WINDOWS__ #endif #if defined(__linux__) || defined(__CYGWIN__) # include #elif defined(__APPLE__) # include # define htole32(x) OSSwapHostToLittleInt32(x) # define le32toh(x) OSSwapLittleToHostInt32(x) #elif defined(__OpenBSD__) # include #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) # include # define le32toh(x) letoh32(x) #elif defined(__WINDOWS__) # include # include # if BYTE_ORDER == LITTLE_ENDIAN # define htole32(x) (x) # define le32toh(x) (x) # elif BYTE_ORDER == BIG_ENDIAN /* that would be xbox 360 */ # define htole32(x) __builtin_bswap32(x) # define le32toh(x) __builtin_bswap32(x) # else # error byte order not supported # endif #else #error platform not supported #endif #endif /* __PORTABLE_ENDIAN_H */ libam7xxx-0.1.7/src/serialize.c000066400000000000000000000025721324602670600164000ustar00rootroot00000000000000/* am7xxx - communication with AM7xxx based USB Pico Projectors and DPFs * * Copyright (C) 2012-2014 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 "portable_endian.h" #include "serialize.h" uint8_t get_8(uint8_t **bufferp) { uint8_t tmp; tmp = *bufferp[0]; *bufferp += 1; return tmp; } uint32_t get_le32(uint8_t **bufferp) { uint32_t tmp; memcpy(&tmp, *bufferp, sizeof (tmp)); *bufferp += sizeof (tmp); return le32toh(tmp); } uint8_t *put_8(uint8_t value, uint8_t **bufferp) { *bufferp[0] = value; *bufferp += 1; return *bufferp; } uint8_t *put_le32(uint32_t value, uint8_t **bufferp) { uint32_t tmp; tmp = htole32(value); memcpy(*bufferp, &tmp, sizeof (tmp)); *bufferp += sizeof (tmp); return *bufferp; } libam7xxx-0.1.7/src/serialize.h000066400000000000000000000024001324602670600163730ustar00rootroot00000000000000/* am7xxx - communication with AM7xxx based USB Pico Projectors and DPFs * * Copyright (C) 2012-2014 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 . */ /* You can transform a serialization block of code which uses put-* into the * correspondent unserialization block with this vim substitution pattern: * * s/put_\([^(]*\)(\([^,]*\),\s*\([^)]*\))/\2 = get_\1(\3)/g */ #ifndef __SERIALIZE_H #define __SERIALIZE_H #include uint8_t get_8(uint8_t **bufferp); uint32_t get_le32(uint8_t **bufferp); uint8_t *put_8(uint8_t value, uint8_t **bufferp); uint8_t *put_le32(uint32_t value, uint8_t **bufferp); #endif /* __SERIALIZE_H */ libam7xxx-0.1.7/src/tools.c000066400000000000000000000025411324602670600155450ustar00rootroot00000000000000/* am7xxx - communication with AM7xxx based USB Pico Projectors and DPFs * * Copyright (C) 2014-2018 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 . */ #ifdef _WIN32 #include #else #include #include #endif #include "tools.h" /** * Sleep for a period expressed in milliseconds * * @param[in] msecs Time to sleep in milliseconds * * @return 0 on success, -1 on error */ int msleep(unsigned long msecs) { #ifdef _WIN32 Sleep(msecs); #else struct timespec delay; int ret; delay.tv_sec = msecs / 1000; delay.tv_nsec = (msecs % 1000) * 1000000; while (1) { ret = nanosleep(&delay, &delay); if (ret == -1 && errno == EINTR) continue; break; } if (ret == -1) return ret; #endif return 0; } libam7xxx-0.1.7/src/tools.h000066400000000000000000000015531324602670600155540ustar00rootroot00000000000000/* am7xxx - communication with AM7xxx based USB Pico Projectors and DPFs * * Copyright (C) 2014 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 . */ #ifndef __TOOLS_H #define __TOOLS_H int msleep(unsigned long msecs); #endif /* __TOOLS_H */