From: Antonio Ospite Date: Fri, 13 Jan 2012 02:20:14 +0000 (+0100) Subject: Use Cmake and make libam7xxx a shared library X-Git-Tag: v0.1.0~33 X-Git-Url: https://git.ao2.it/libam7xxx.git/commitdiff_plain/3339bee3f62dbfa3586cc4db5201f7fc704ab037?ds=inline;hp=-c Use Cmake and make libam7xxx a shared library Also move the source code to a src/ subdirectory in order to avoid cluttering the project root dir. --- 3339bee3f62dbfa3586cc4db5201f7fc704ab037 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..199bc80 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,103 @@ +cmake_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 0) +set(PROJECT_VER_PATCH 1) +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/") + +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) + +if (CMAKE_COMPILER_IS_GNUCC) + add_definitions(-Wall) + + # let CFLAGS env override this + if(CMAKE_C_FLAGS STREQUAL "") + set(CMAKE_C_FLAGS "-std=c99 -pedantic -Wall -Wextra -O2") + endif() + + # Don't make pedantic checks errors, + # as vanilla libusb-1.0.8 can't live with that + #add_flags(CMAKE_C_FLAGS -pedantic-errors) + + # GCC >= 4.6 + #add_flags(CMAKE_C_FLAGS -Wunused-but-set-variable) + + add_flags(CMAKE_C_FLAGS + -fno-common + -Wall + -Wextra + -Wformat=2 + -Winit-self + -Winline + -Wpacked + -Wp,-D_FORTIFY_SOURCE=2 + -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 + -Wunsafe-loop-optimizations + -Wwrite-strings + ) +endif() + +set(CMAKE_C_FLAGS_DEBUG "-g -DDEBUG=1") +set(CMAKE_C_FLAGS_RELEASE "-O2") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") + +# Use git for some maintainance tasks +find_package(Git) +if(GIT_FOUND) + 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 \"${ARCHIVE_PREFIX}.tar.gz\" --prefix=\"${ARCHIVE_PREFIX}/\" HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + + add_custom_target(changelog + COMMAND ${GIT_EXECUTABLE} log --pretty=\"format:%ai %aN <%aE>%n%n%x09* %s%d%n\" > ChangeLog + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) +endif(GIT_FOUND) + +# Add library project +add_subdirectory(src) diff --git a/Makefile b/Makefile deleted file mode 100644 index 514621b..0000000 --- a/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -CFLAGS ?= -std=c99 -pedantic -Wall -Wextra -O2 - -# Don't make pedantic checks errors, -# as vanilla libusb-1.0.8 can't live with that -#CFLAGS += -pedantic-errors - -# GCC >= 4.6 -#CFLAGS += -Wunused-but-set-variable - -CFLAGS += -fno-common \ - -Wall \ - -Wextra \ - -Wformat=2 \ - -Winit-self \ - -Winline \ - -Wpacked \ - -Wp,-D_FORTIFY_SOURCE=2 \ - -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 \ - -Wunsafe-loop-optimizations \ - -Wwrite-strings - -CFLAGS += $(shell pkg-config --cflags libusb-1.0) -LDLIBS += $(shell pkg-config --libs libusb-1.0) - -PREFIX ?= /usr/local -bindir := $(PREFIX)/sbin - -all: picoproj - -CFLAGS += -D_BSD_SOURCE # for htole32() -CFLAGS += -D_POSIX_C_SOURCE=2 # for getopt() - -picoproj: picoproj.o am7xxx.o - -install: picoproj - install -d $(DESTDIR)$(bindir) - install -m 755 picoproj $(DESTDIR)$(bindir) - -BACKUP_PREFIX=libpicoproj-$(shell date +%Y%m%d%H%M) -backup: - git archive \ - -o $(BACKUP_PREFIX).tar.gz \ - --prefix=$(BACKUP_PREFIX)/ \ - HEAD - -changelog: - git log --pretty="format:%ai %aN <%aE>%n%n%x09* %s%d%n" > ChangeLog - -clean: - rm -rf *~ *.o picoproj diff --git a/am7xxx.c b/am7xxx.c deleted file mode 100644 index d81d1a8..0000000 --- a/am7xxx.c +++ /dev/null @@ -1,197 +0,0 @@ -/* am7xxx - communication with AM7xxx based USB Pico Projectors and DPFs - * - * Copyright (C) 2011 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 "am7xxx.h" - -#define AM7XXX_VENDOR_ID 0x1de1 -#define AM7XXX_PRODUCT_ID 0xc101 - -#if 1 -static uint8_t reference_image_header[] = { - 0x02, 0x00, 0x00, 0x00, - 0x00, - 0x10, - 0x3e, - 0x10, - 0x01, 0x00, 0x00, 0x00, - 0x20, 0x03, 0x00, 0x00, - 0xe0, 0x01, 0x00, 0x00, - 0x53, 0xE8, 0x00, 0x00 -}; -#endif - -static void dump_image_header(struct am7xxx_image_header *i) -{ - if (i == NULL) - return; - - printf("Image header:\n"); - printf("format: 0x%08x (%u)\n", i->format, i->format); - printf("width: 0x%08x (%u)\n", i->width, i->width); - printf("height: 0x%08x (%u)\n", i->height, i->height); - printf("image size: 0x%08x (%u)\n", i->image_size, i->image_size); -} - -static void dump_header(struct am7xxx_header *h) -{ - if (h == NULL) - return; - - printf("packet_type: 0x%08x (%u)\n", h->packet_type, h->packet_type); - printf("unknown0: 0x%02hhx (%hhu)\n", h->unknown0, h->unknown0); - printf("header_len: 0x%02hhx (%hhu)\n", h->header_len, h->header_len); - printf("unknown2: 0x%02hhx (%hhu)\n", h->unknown2, h->unknown2); - printf("unknown3: 0x%02hhx (%hhu)\n", h->unknown3, h->unknown3); - - switch(h->packet_type) { - case AM7XXX_PACKET_TYPE_IMAGE: - dump_image_header(&(h->header_data.image)); - break; - - default: - printf("Packet type not supported!\n"); - break; - } - - fflush(stdout); -} - -static inline unsigned int in_80chars(unsigned int i) -{ - return ((i+1) % (80/3)); -} - -static void dump_buffer(uint8_t *buffer, unsigned int len) -{ - unsigned int i; - - if (buffer == NULL || len == 0) - return; - - for (i = 0; i < len; i++) { - printf("%02hhX%c", buffer[i], (in_80chars(i) && (i < len - 1)) ? ' ' : '\n'); - } - fflush(stdout); -} - -static int send_data(am7xxx_device dev, uint8_t *buffer, unsigned int len) -{ - int ret; - int transferred; - - dump_buffer(buffer, len); - - ret = libusb_bulk_transfer(dev, 1, buffer, len, &transferred, 0); - if (ret != 0 || (unsigned int)transferred != len) { - fprintf(stderr, "Error: ret: %d\ttransferred: %d (expected %u)\n", - ret, transferred, len); - return ret; - } - - return 0; -} - -static int send_header(am7xxx_device dev, struct am7xxx_header *h) -{ - union { - struct am7xxx_header header; - uint8_t buffer[sizeof (struct am7xxx_header)]; - } data; - - data.header = *h; - - return send_data(dev, data.buffer, sizeof (struct am7xxx_header)); -} - -am7xxx_device am7xxx_init(void) -{ - am7xxx_device dev; - - libusb_init(NULL); - libusb_set_debug(NULL, 3); - - dev = libusb_open_device_with_vid_pid(NULL, - AM7XXX_VENDOR_ID, - AM7XXX_PRODUCT_ID); - if (dev == NULL) { - errno = ENODEV; - perror("libusb_open_device_with_vid_pid"); - goto out_libusb_exit; - } - - libusb_set_configuration(dev, 1); - libusb_claim_interface(dev, 0); - - return dev; - -out_libusb_exit: - libusb_exit(NULL); - return NULL; -} - -void am7xxx_shutdown(am7xxx_device dev) -{ - if (dev) { - libusb_close(dev); - libusb_exit(NULL); - } -} - -int am7xxx_send_image(am7xxx_device dev, - am7xxx_image_format format, - unsigned int width, - unsigned int height, - uint8_t *image, - unsigned int size) -{ - int ret; - struct am7xxx_header h = { - .packet_type = htole32(AM7XXX_PACKET_TYPE_IMAGE), - .unknown0 = 0x00, - .header_len = sizeof(struct am7xxx_image_header), - .unknown2 = 0x3e, - .unknown3 = 0x10, - .header_data = { - .image = { - .format = htole32(format), - .width = htole32(width), - .height = htole32(height), - .image_size = htole32(size), - }, - }, - }; - - dump_header(&h); - printf("\n"); - - printf("Dump Buffers\n"); - dump_buffer(reference_image_header, sizeof(struct am7xxx_header)); - - ret = send_header(dev, &h); - if (ret < 0) - return ret; - - if (image == NULL || size == 0) - return 0; - - return send_data(dev, image, size); -} diff --git a/am7xxx.h b/am7xxx.h deleted file mode 100644 index d8d69d7..0000000 --- a/am7xxx.h +++ /dev/null @@ -1,90 +0,0 @@ -/* am7xxx - communication with AM7XXX based USB Pico Projectors and DPFs - * - * Copyright (C) 2011 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 . - */ - -#ifndef __AM7XXX_H -#define __AM7XXX_H - -#include -#include - -typedef libusb_device_handle *am7xxx_device; - -typedef enum { - AM7XXX_PACKET_TYPE_INIT = 0x01, - AM7XXX_PACKET_TYPE_IMAGE = 0x02, - AM7XXX_PACKET_TYPE_POWER = 0x04, - AM7XXX_PACKET_TYPE_UNKNOWN = 0x05, -} am7xxx_packet_type; - -typedef enum { - AM7XXX_IMAGE_FORMAT_JPEG = 1, -} am7xxx_image_format; - -typedef enum { - AM7XXX_POWER_OFF = 0, - AM7XXX_POWER_LOW = 1, - AM7XXX_POWER_MID = 2, - AM7XXX_POWER_HIGH = 3, -} am7xxx_power_mode; - -struct am7xxx_image_header { - uint32_t format; - uint32_t width; - uint32_t height; - uint32_t image_size; -}; - -struct am7xxx_power_header { - uint32_t power_low; - uint32_t power_mid; - uint32_t power_high; -}; - -/* - * 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 - */ - -struct am7xxx_header { - uint32_t packet_type; - uint8_t unknown0; - uint8_t header_len; - uint8_t unknown2; - uint8_t unknown3; - union { - struct am7xxx_image_header image; - struct am7xxx_power_header power; - } header_data; -}; - -am7xxx_device am7xxx_init(void); -void am7xxx_shutdown(am7xxx_device dev); - -int am7xxx_send_image(am7xxx_device dev, - am7xxx_image_format format, - unsigned int width, - unsigned int height, - uint8_t *image, - unsigned int size); - -#endif /* __AM7XXX_H */ diff --git a/cmake_modules/Findlibusb-1.0.cmake b/cmake_modules/Findlibusb-1.0.cmake new file mode 100644 index 0000000..405ed51 --- /dev/null +++ b/cmake_modules/Findlibusb-1.0.cmake @@ -0,0 +1,98 @@ +# - 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-1.0/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 + 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) \ No newline at end of file diff --git a/picoproj.c b/picoproj.c deleted file mode 100644 index 010d4d1..0000000 --- a/picoproj.c +++ /dev/null @@ -1,149 +0,0 @@ -/* picoproj - test program for libam7xxx - * - * Copyright (C) 2011 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 -#include -#include -#include -#include - -#include "am7xxx.h" - -static void usage(char *name) -{ - printf("usage: %s [OPTIONS]\n\n", name); - printf("OPTIONS:\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-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"); -} - -int main(int argc, char *argv[]) -{ - int ret; - int exit_code = EXIT_SUCCESS; - int opt; - - char filename[FILENAME_MAX] = {0}; - int image_fd = -1; - am7xxx_device dev; - int format = AM7XXX_IMAGE_FORMAT_JPEG; - int width = 800; - int height = 480; - uint8_t *image = NULL; - unsigned int size = 59475; - - while ((opt = getopt(argc, argv, "f:F:W:H:h")) != -1) { - switch (opt) { - case 'f': - strncpy(filename, optarg, FILENAME_MAX); - break; - case 'F': - format = atoi(optarg); - if (format != 1) { - fprintf(stderr, "Unsupported format\n"); - exit(EXIT_FAILURE); - } - break; - case 'W': - width = atoi(optarg); - if (width < 0) { - fprintf(stderr, "Unsupported width\n"); - exit(EXIT_FAILURE); - } - break; - case 'H': - height = atoi(optarg); - if (height < 0) { - fprintf(stderr, "Unsupported height\n"); - exit(EXIT_FAILURE); - } - break; - default: /* '?' */ - usage(argv[0]); - exit(EXIT_FAILURE); - } - } - - if (filename[0] != '\0') { - struct stat st; - - image_fd = open(filename, O_RDONLY); - if (image_fd < 0) { - perror("open"); - exit_code = EXIT_FAILURE; - goto out; - } - if (fstat(image_fd, &st) < 0) { - perror("fstat"); - exit_code = EXIT_FAILURE; - goto out_close_image_fd; - } - size = st.st_size; - - image = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, image_fd, 0); - if (image == NULL) { - perror("mmap"); - exit_code = EXIT_FAILURE; - goto out_close_image_fd; - } - } - - dev = am7xxx_init(); - if (dev == NULL) { - perror("am7xxx_init"); - exit_code = EXIT_FAILURE; - goto out_munmap; - } - - ret = am7xxx_send_image(dev, format, width, height, image, size); - if (ret < 0) { - perror("am7xxx_send_image"); - exit_code = EXIT_FAILURE; - goto cleanup; - } - - exit_code = EXIT_SUCCESS; - -cleanup: - am7xxx_shutdown(dev); - -out_munmap: - if (image != NULL) { - ret = munmap(image, size); - if (ret < 0) - perror("munmap"); - } - -out_close_image_fd: - if (image_fd >= 0) { - ret = close(image_fd); - if (ret < 0) - perror("close"); - } - -out: - exit(exit_code); -} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..39f4e86 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,44 @@ +add_definitions("-D_BSD_SOURCE") # for htole32() +add_definitions("-D_POSIX_C_SOURCE=2") # for getopt() + +# Find packages needed to build library +find_package(libusb-1.0 REQUIRED) +include_directories(${LIBUSB_1_INCLUDE_DIRS}) + +set(SRC am7xxx.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") + +target_link_libraries(am7xxx ${LIBUSB_1_LIBRARIES}) +target_link_libraries(am7xxx-static ${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() + +# Build the test app +add_executable(picoproj picoproj.c) +target_link_libraries(picoproj am7xxx) +install(TARGETS picoproj + DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") diff --git a/src/am7xxx.c b/src/am7xxx.c new file mode 100644 index 0000000..d81d1a8 --- /dev/null +++ b/src/am7xxx.c @@ -0,0 +1,197 @@ +/* am7xxx - communication with AM7xxx based USB Pico Projectors and DPFs + * + * Copyright (C) 2011 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 "am7xxx.h" + +#define AM7XXX_VENDOR_ID 0x1de1 +#define AM7XXX_PRODUCT_ID 0xc101 + +#if 1 +static uint8_t reference_image_header[] = { + 0x02, 0x00, 0x00, 0x00, + 0x00, + 0x10, + 0x3e, + 0x10, + 0x01, 0x00, 0x00, 0x00, + 0x20, 0x03, 0x00, 0x00, + 0xe0, 0x01, 0x00, 0x00, + 0x53, 0xE8, 0x00, 0x00 +}; +#endif + +static void dump_image_header(struct am7xxx_image_header *i) +{ + if (i == NULL) + return; + + printf("Image header:\n"); + printf("format: 0x%08x (%u)\n", i->format, i->format); + printf("width: 0x%08x (%u)\n", i->width, i->width); + printf("height: 0x%08x (%u)\n", i->height, i->height); + printf("image size: 0x%08x (%u)\n", i->image_size, i->image_size); +} + +static void dump_header(struct am7xxx_header *h) +{ + if (h == NULL) + return; + + printf("packet_type: 0x%08x (%u)\n", h->packet_type, h->packet_type); + printf("unknown0: 0x%02hhx (%hhu)\n", h->unknown0, h->unknown0); + printf("header_len: 0x%02hhx (%hhu)\n", h->header_len, h->header_len); + printf("unknown2: 0x%02hhx (%hhu)\n", h->unknown2, h->unknown2); + printf("unknown3: 0x%02hhx (%hhu)\n", h->unknown3, h->unknown3); + + switch(h->packet_type) { + case AM7XXX_PACKET_TYPE_IMAGE: + dump_image_header(&(h->header_data.image)); + break; + + default: + printf("Packet type not supported!\n"); + break; + } + + fflush(stdout); +} + +static inline unsigned int in_80chars(unsigned int i) +{ + return ((i+1) % (80/3)); +} + +static void dump_buffer(uint8_t *buffer, unsigned int len) +{ + unsigned int i; + + if (buffer == NULL || len == 0) + return; + + for (i = 0; i < len; i++) { + printf("%02hhX%c", buffer[i], (in_80chars(i) && (i < len - 1)) ? ' ' : '\n'); + } + fflush(stdout); +} + +static int send_data(am7xxx_device dev, uint8_t *buffer, unsigned int len) +{ + int ret; + int transferred; + + dump_buffer(buffer, len); + + ret = libusb_bulk_transfer(dev, 1, buffer, len, &transferred, 0); + if (ret != 0 || (unsigned int)transferred != len) { + fprintf(stderr, "Error: ret: %d\ttransferred: %d (expected %u)\n", + ret, transferred, len); + return ret; + } + + return 0; +} + +static int send_header(am7xxx_device dev, struct am7xxx_header *h) +{ + union { + struct am7xxx_header header; + uint8_t buffer[sizeof (struct am7xxx_header)]; + } data; + + data.header = *h; + + return send_data(dev, data.buffer, sizeof (struct am7xxx_header)); +} + +am7xxx_device am7xxx_init(void) +{ + am7xxx_device dev; + + libusb_init(NULL); + libusb_set_debug(NULL, 3); + + dev = libusb_open_device_with_vid_pid(NULL, + AM7XXX_VENDOR_ID, + AM7XXX_PRODUCT_ID); + if (dev == NULL) { + errno = ENODEV; + perror("libusb_open_device_with_vid_pid"); + goto out_libusb_exit; + } + + libusb_set_configuration(dev, 1); + libusb_claim_interface(dev, 0); + + return dev; + +out_libusb_exit: + libusb_exit(NULL); + return NULL; +} + +void am7xxx_shutdown(am7xxx_device dev) +{ + if (dev) { + libusb_close(dev); + libusb_exit(NULL); + } +} + +int am7xxx_send_image(am7xxx_device dev, + am7xxx_image_format format, + unsigned int width, + unsigned int height, + uint8_t *image, + unsigned int size) +{ + int ret; + struct am7xxx_header h = { + .packet_type = htole32(AM7XXX_PACKET_TYPE_IMAGE), + .unknown0 = 0x00, + .header_len = sizeof(struct am7xxx_image_header), + .unknown2 = 0x3e, + .unknown3 = 0x10, + .header_data = { + .image = { + .format = htole32(format), + .width = htole32(width), + .height = htole32(height), + .image_size = htole32(size), + }, + }, + }; + + dump_header(&h); + printf("\n"); + + printf("Dump Buffers\n"); + dump_buffer(reference_image_header, sizeof(struct am7xxx_header)); + + ret = send_header(dev, &h); + if (ret < 0) + return ret; + + if (image == NULL || size == 0) + return 0; + + return send_data(dev, image, size); +} diff --git a/src/am7xxx.h b/src/am7xxx.h new file mode 100644 index 0000000..d8d69d7 --- /dev/null +++ b/src/am7xxx.h @@ -0,0 +1,90 @@ +/* am7xxx - communication with AM7XXX based USB Pico Projectors and DPFs + * + * Copyright (C) 2011 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 . + */ + +#ifndef __AM7XXX_H +#define __AM7XXX_H + +#include +#include + +typedef libusb_device_handle *am7xxx_device; + +typedef enum { + AM7XXX_PACKET_TYPE_INIT = 0x01, + AM7XXX_PACKET_TYPE_IMAGE = 0x02, + AM7XXX_PACKET_TYPE_POWER = 0x04, + AM7XXX_PACKET_TYPE_UNKNOWN = 0x05, +} am7xxx_packet_type; + +typedef enum { + AM7XXX_IMAGE_FORMAT_JPEG = 1, +} am7xxx_image_format; + +typedef enum { + AM7XXX_POWER_OFF = 0, + AM7XXX_POWER_LOW = 1, + AM7XXX_POWER_MID = 2, + AM7XXX_POWER_HIGH = 3, +} am7xxx_power_mode; + +struct am7xxx_image_header { + uint32_t format; + uint32_t width; + uint32_t height; + uint32_t image_size; +}; + +struct am7xxx_power_header { + uint32_t power_low; + uint32_t power_mid; + uint32_t power_high; +}; + +/* + * 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 + */ + +struct am7xxx_header { + uint32_t packet_type; + uint8_t unknown0; + uint8_t header_len; + uint8_t unknown2; + uint8_t unknown3; + union { + struct am7xxx_image_header image; + struct am7xxx_power_header power; + } header_data; +}; + +am7xxx_device am7xxx_init(void); +void am7xxx_shutdown(am7xxx_device dev); + +int am7xxx_send_image(am7xxx_device dev, + am7xxx_image_format format, + unsigned int width, + unsigned int height, + uint8_t *image, + unsigned int size); + +#endif /* __AM7XXX_H */ diff --git a/src/libam7xxx.pc.in b/src/libam7xxx.pc.in new file mode 100644 index 0000000..2ad2256 --- /dev/null +++ b/src/libam7xxx.pc.in @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: @PROJECT_NAME@ +Description: @PROJECT_DESCRIPTION@ +Requires: libusb-1.0 +Version: @PROJECT_APIVER@ +Libs: -L${libdir} -lam7xxx +Cflags: -I${includedir} diff --git a/src/picoproj.c b/src/picoproj.c new file mode 100644 index 0000000..010d4d1 --- /dev/null +++ b/src/picoproj.c @@ -0,0 +1,149 @@ +/* picoproj - test program for libam7xxx + * + * Copyright (C) 2011 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 +#include +#include +#include +#include + +#include "am7xxx.h" + +static void usage(char *name) +{ + printf("usage: %s [OPTIONS]\n\n", name); + printf("OPTIONS:\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-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"); +} + +int main(int argc, char *argv[]) +{ + int ret; + int exit_code = EXIT_SUCCESS; + int opt; + + char filename[FILENAME_MAX] = {0}; + int image_fd = -1; + am7xxx_device dev; + int format = AM7XXX_IMAGE_FORMAT_JPEG; + int width = 800; + int height = 480; + uint8_t *image = NULL; + unsigned int size = 59475; + + while ((opt = getopt(argc, argv, "f:F:W:H:h")) != -1) { + switch (opt) { + case 'f': + strncpy(filename, optarg, FILENAME_MAX); + break; + case 'F': + format = atoi(optarg); + if (format != 1) { + fprintf(stderr, "Unsupported format\n"); + exit(EXIT_FAILURE); + } + break; + case 'W': + width = atoi(optarg); + if (width < 0) { + fprintf(stderr, "Unsupported width\n"); + exit(EXIT_FAILURE); + } + break; + case 'H': + height = atoi(optarg); + if (height < 0) { + fprintf(stderr, "Unsupported height\n"); + exit(EXIT_FAILURE); + } + break; + default: /* '?' */ + usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + if (filename[0] != '\0') { + struct stat st; + + image_fd = open(filename, O_RDONLY); + if (image_fd < 0) { + perror("open"); + exit_code = EXIT_FAILURE; + goto out; + } + if (fstat(image_fd, &st) < 0) { + perror("fstat"); + exit_code = EXIT_FAILURE; + goto out_close_image_fd; + } + size = st.st_size; + + image = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, image_fd, 0); + if (image == NULL) { + perror("mmap"); + exit_code = EXIT_FAILURE; + goto out_close_image_fd; + } + } + + dev = am7xxx_init(); + if (dev == NULL) { + perror("am7xxx_init"); + exit_code = EXIT_FAILURE; + goto out_munmap; + } + + ret = am7xxx_send_image(dev, format, width, height, image, size); + if (ret < 0) { + perror("am7xxx_send_image"); + exit_code = EXIT_FAILURE; + goto cleanup; + } + + exit_code = EXIT_SUCCESS; + +cleanup: + am7xxx_shutdown(dev); + +out_munmap: + if (image != NULL) { + ret = munmap(image, size); + if (ret < 0) + perror("munmap"); + } + +out_close_image_fd: + if (image_fd >= 0) { + ret = close(image_fd); + if (ret < 0) + perror("close"); + } + +out: + exit(exit_code); +}