diff --git a/tools/ptpcam/COPYING b/tools/ptpcam/COPYING new file mode 100644 index 00000000..5a965fbc --- /dev/null +++ b/tools/ptpcam/COPYING @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Library 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 diff --git a/tools/ptpcam/Makefile b/tools/ptpcam/Makefile new file mode 100644 index 00000000..ad594f8d --- /dev/null +++ b/tools/ptpcam/Makefile @@ -0,0 +1,8 @@ +CC=gcc +CFLAGS= +LDFLAGS=-lusb + +all: ptpcam + +ptpcam: config.h libptp-endian.h libptp-stdint.h myusb.c properties.c ptp-pack.c ptp.c ptp.h ptpcam.c ptpcam.h + $(CC) -o ptpcam myusb.c properties.c ptp.c ptpcam.c $(CFLAGS) $(LDFLAGS) diff --git a/tools/ptpcam/Makefile.win32 b/tools/ptpcam/Makefile.win32 new file mode 100644 index 00000000..067c54dc --- /dev/null +++ b/tools/ptpcam/Makefile.win32 @@ -0,0 +1,8 @@ +CC=gcc +CFLAGS=-IC:\MinGW\include -I"C:\Program Files\LibUSB-Win32\include" +LDFLAGS="C:\Program Files\LibUSB-Win32\lib\gcc\libusb.a" -lws2_32 -lkernel32 + +all: ptpcam + +ptpcam: config.h libptp-endian.h libptp-stdint.h myusb.c properties.c ptp-pack.c ptp.c ptp.h ptpcam.c ptpcam.h + $(CC) -o ptpcam myusb.c properties.c ptp.c ptpcam.c $(CFLAGS) $(LDFLAGS) diff --git a/tools/ptpcam/README b/tools/ptpcam/README new file mode 100644 index 00000000..9fc4bf79 --- /dev/null +++ b/tools/ptpcam/README @@ -0,0 +1 @@ +requires libusb... etc. diff --git a/tools/ptpcam/config.h b/tools/ptpcam/config.h new file mode 100644 index 00000000..bc8cbff0 --- /dev/null +++ b/tools/ptpcam/config.h @@ -0,0 +1,100 @@ +/* config.h. Generated by configure. */ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the `alarm' function. */ +#define HAVE_ALARM 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the `getopt_long' function. */ +#define HAVE_GETOPT_LONG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIBINTL_H 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Linux OS */ +#define LINUX_OS + +/* Name of package */ +#define PACKAGE "libptp2" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Unknown OS */ +/* #undef UNKNOWN_OS */ + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ diff --git a/tools/ptpcam/libptp-endian.h b/tools/ptpcam/libptp-endian.h new file mode 100644 index 00000000..ad8de2ce --- /dev/null +++ b/tools/ptpcam/libptp-endian.h @@ -0,0 +1,96 @@ +/* This file is generated automatically by configure */ +/* It is valid only for the system type i686-pc-linux-gnu */ + +#ifndef __BYTEORDER_H +#define __BYTEORDER_H + +#ifdef WIN32 +#include +#else +/* ntohl and relatives live here */ +#include + +/* Define generic byte swapping functions */ +#include +#endif + +#define swap16(x) bswap_16(x) +#define swap32(x) bswap_32(x) +#define swap64(x) bswap_64(x) + +/* The byte swapping macros have the form: */ +/* EENN[a]toh or htoEENN[a] where EE is be (big endian) or */ +/* le (little-endian), NN is 16 or 32 (number of bits) and a, */ +/* if present, indicates that the endian side is a pointer to an */ +/* array of uint8_t bytes instead of an integer of the specified length. */ +/* h refers to the host's ordering method. */ + +/* So, to convert a 32-bit integer stored in a buffer in little-endian */ +/* format into a uint32_t usable on this machine, you could use: */ +/* uint32_t value = le32atoh(&buf[3]); */ +/* To put that value back into the buffer, you could use: */ +/* htole32a(&buf[3], value); */ + +/* Define aliases for the standard byte swapping macros */ +/* Arguments to these macros must be properly aligned on natural word */ +/* boundaries in order to work properly on all architectures */ + +/* Uncomment if system endian.h does not provide them */ +//#define htobe16(x) htons(x) +//#define htobe32(x) htonl(x) +//#define be16toh(x) ntohs(x) +//#define be32toh(x) ntohl(x) + +#define HTOBE16(x) (x) = htobe16(x) +#define HTOBE32(x) (x) = htobe32(x) +#define BE32TOH(x) (x) = be32toh(x) +#define BE16TOH(x) (x) = be16toh(x) + +/* On little endian machines, these macros are null */ +#define htole16(x) (x) +#define htole32(x) (x) +#define htole64(x) (x) +#define le16toh(x) (x) +#define le32toh(x) (x) +#define le64toh(x) (x) + +#define HTOLE16(x) (void) (x) +#define HTOLE32(x) (void) (x) +#define HTOLE64(x) (void) (x) +#define LE16TOH(x) (void) (x) +#define LE32TOH(x) (void) (x) +#define LE64TOH(x) (void) (x) + +/* Uncomment if system endian.h does not provide them */ +//#define htobe64(x) swap64(x) +//#define be64toh(x) swap64(x) + +#define HTOBE64(x) (x) = htobe64(x) +#define BE64TOH(x) (x) = be64toh(x) + +/* Define the C99 standard length-specific integer types */ +#include "libptp-stdint.h" + +/* Here are some macros to create integers from a byte array */ +/* These are used to get and put integers from/into a uint8_t array */ +/* with a specific endianness. This is the most portable way to generate */ +/* and read messages to a network or serial device. Each member of a */ +/* packet structure must be handled separately. */ + +/* The i386 and compatibles can handle unaligned memory access, */ +/* so use the optimized macros above to do this job */ +#define be16atoh(x) be16toh(*(uint16_t*)(x)) +#define be32atoh(x) be32toh(*(uint32_t*)(x)) +#define be64atoh(x) be64toh(*(uint64_t*)(x)) +#define le16atoh(x) le16toh(*(uint16_t*)(x)) +#define le32atoh(x) le32toh(*(uint32_t*)(x)) +#define le64atoh(x) le64toh(*(uint64_t*)(x)) + +#define htobe16a(a,x) *(uint16_t*)(a) = htobe16(x) +#define htobe32a(a,x) *(uint32_t*)(a) = htobe32(x) +#define htobe64a(a,x) *(uint64_t*)(a) = htobe64(x) +#define htole16a(a,x) *(uint16_t*)(a) = htole16(x) +#define htole32a(a,x) *(uint32_t*)(a) = htole32(x) +#define htole64a(a,x) *(uint64_t*)(a) = htole64(x) + +#endif /*__BYTEORDER_H*/ diff --git a/tools/ptpcam/libptp-stdint.h b/tools/ptpcam/libptp-stdint.h new file mode 100644 index 00000000..80ecf419 --- /dev/null +++ b/tools/ptpcam/libptp-stdint.h @@ -0,0 +1,2 @@ +/* This file is generated automatically by configure */ +#include diff --git a/tools/ptpcam/myusb.c b/tools/ptpcam/myusb.c new file mode 100644 index 00000000..943fae95 --- /dev/null +++ b/tools/ptpcam/myusb.c @@ -0,0 +1,141 @@ +/* myusb.c + * + * Copyright (C) 2001-2005 Mariusz Woloszyn + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" +#ifdef LINUX_OS + +/* + * libusb has changed the kernel interface used for bulk read/write operations. + * the new, threaded (URB) interface is not required in this application + * especially that it fails sometimes unexpectedly. + * to avoid using TheNewBetterInterface we redefine the old one in this place. + * most of the code below is copied from libusb 0.1.8 or so. + */ + +#include +#include +#include + +#define IOCTL_USB_CONTROL _IOWR('U', 0, struct usb_ctrltransfer) +#define IOCTL_USB_BULK _IOWR('U', 2, struct usb_bulktransfer) +#define IOCTL_USB_RESETEP _IOR('U', 3, unsigned int) +#define IOCTL_USB_SETINTF _IOR('U', 4, struct usb_setinterface) +#define IOCTL_USB_SETCONFIG _IOR('U', 5, unsigned int) +#define IOCTL_USB_GETDRIVER _IOW('U', 8, struct usb_getdriver) +#define IOCTL_USB_SUBMITURB _IOR('U', 10, struct usb_urb) +#define IOCTL_USB_DISCARDURB _IO('U', 11) +#define IOCTL_USB_REAPURB _IOW('U', 12, void *) +#define IOCTL_USB_REAPURBNDELAY _IOW('U', 13, void *) +#define IOCTL_USB_CLAIMINTF _IOR('U', 15, unsigned int) +#define IOCTL_USB_RELEASEINTF _IOR('U', 16, unsigned int) +#define IOCTL_USB_IOCTL _IOWR('U', 18, struct usb_ioctl) +#define IOCTL_USB_RESET _IO('U', 20) +#define IOCTL_USB_CLEAR_HALT _IOR('U', 21, unsigned int) +#define IOCTL_USB_DISCONNECT _IO('U', 22) /* via IOCTL_USB_IOCTL */ +#define IOCTL_USB_CONNECT _IO('U', 23) /* via IOCTL_USB_IOCTL */ + + +struct usb_bulktransfer { + /* keep in sync with usbdevice_fs.h:usbdevfs_bulktransfer */ + unsigned int ep; + unsigned int len; + unsigned int timeout; /* in milliseconds */ + + /* pointer to data */ + void *data; +}; + +struct usb_dev_handle { + int fd; + + struct usb_bus *bus; + struct usb_device *device; + + int config; + int interface; + int altsetting; + + /* Added by RMT so implementations can store other per-open-device data */ + void *impl_info; +}; + + +/* Linux usbdevfs has a limit of one page size per read/write. 4096 is */ +/* the most portable maximum we can do for now */ +#define MAX_READ_WRITE 4096 + +int myusb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, + int timeout); +int myusb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, + int timeout) +{ + struct usb_bulktransfer bulk; + int ret, sent = 0; + + /* Ensure the endpoint address is correct */ + if (ep < 0 || ep > 0x0f) + return (-EINVAL); + + do { + bulk.ep = ep; + bulk.len = length - sent; + if (bulk.len > MAX_READ_WRITE) + bulk.len = MAX_READ_WRITE; + bulk.timeout = timeout; + bulk.data = (unsigned char *)bytes + sent; + + ret = ioctl(dev->fd, IOCTL_USB_BULK, &bulk); + if (ret < 0) + return (-errno); + + sent += ret; + } while (ret > 0 && sent < length); + + return sent; +} + +int myusb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int myusb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout) +{ + struct usb_bulktransfer bulk; + int ret, retrieved = 0, requested; + + /* Ensure the endpoint address is correct */ + ep |= USB_ENDPOINT_IN; + + do { + bulk.ep = ep; + requested = size - retrieved; + if (requested > MAX_READ_WRITE) + requested = MAX_READ_WRITE; + bulk.len = requested; + bulk.timeout = timeout; + bulk.data = (unsigned char *)bytes + retrieved; + + ret = ioctl(dev->fd, IOCTL_USB_BULK, &bulk); + if (ret < 0) + return (-errno); + + retrieved += ret; + } while (ret > 0 && retrieved < size && ret == requested); + + return retrieved; +} +#endif /* LINUX_OS */ diff --git a/tools/ptpcam/properties.c b/tools/ptpcam/properties.c new file mode 100644 index 00000000..81dc5724 --- /dev/null +++ b/tools/ptpcam/properties.c @@ -0,0 +1,891 @@ + +/* properties.c + * + * Copyright (C) 2005 Mariusz Woloszyn + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "config.h" + +#include "ptp.h" +#include +#include +#include + +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + +#define SVALLEN 256 +#define SVALRET(s) { \ + if (n>=SVALLEN) s[SVALLEN]='\0'; \ + return s;\ +} + +int +ptp_property_issupported(PTPParams* params, uint16_t property) +{ + int i=0; + + for (;ideviceinfo.DevicePropertiesSupported_len;i++) { + if (params->deviceinfo.DevicePropertiesSupported[i]==property) + return 1; + } + return 0; +} + +static struct { + uint16_t dpc; + const char *txt; +} ptp_device_properties[] = { + {PTP_DPC_Undefined, N_("PTP Undefined Property")}, + {PTP_DPC_BatteryLevel, N_("Battery Level")}, + {PTP_DPC_FunctionalMode, N_("Functional Mode")}, + {PTP_DPC_ImageSize, N_("Image Size")}, + {PTP_DPC_CompressionSetting, N_("Compression Setting")}, + {PTP_DPC_WhiteBalance, N_("White Balance")}, + {PTP_DPC_RGBGain, N_("RGB Gain")}, + {PTP_DPC_FNumber, N_("F-Number")}, + {PTP_DPC_FocalLength, N_("Focal Length")}, + {PTP_DPC_FocusDistance, N_("Focus Distance")}, + {PTP_DPC_FocusMode, N_("Focus Mode")}, + {PTP_DPC_ExposureMeteringMode, N_("Exposure Metering Mode")}, + {PTP_DPC_FlashMode, N_("Flash Mode")}, + {PTP_DPC_ExposureTime, N_("Exposure Time")}, + {PTP_DPC_ExposureProgramMode, N_("Exposure Program Mode")}, + {PTP_DPC_ExposureIndex, N_("Exposure Index (film speed ISO)")}, + {PTP_DPC_ExposureBiasCompensation, N_("Exposure Bias Compensation")}, + {PTP_DPC_DateTime, N_("Date Time")}, + {PTP_DPC_CaptureDelay, N_("Pre-Capture Delay")}, + {PTP_DPC_StillCaptureMode, N_("Still Capture Mode")}, + {PTP_DPC_Contrast, N_("Contrast")}, + {PTP_DPC_Sharpness, N_("Sharpness")}, + {PTP_DPC_DigitalZoom, N_("Digital Zoom")}, + {PTP_DPC_EffectMode, N_("Effect Mode")}, + {PTP_DPC_BurstNumber, N_("Burst Number")}, + {PTP_DPC_BurstInterval, N_("Burst Interval")}, + {PTP_DPC_TimelapseNumber, N_("Timelapse Number")}, + {PTP_DPC_TimelapseInterval, N_("Timelapse Interval")}, + {PTP_DPC_FocusMeteringMode, N_("Focus Metering Mode")}, + {PTP_DPC_UploadURL, N_("Upload URL")}, + {PTP_DPC_Artist, N_("Artist")}, + {PTP_DPC_CopyrightInfo, N_("Copyright Info")}, + {0,NULL} +}; +static struct { + uint16_t dpc; + const char *txt; +} ptp_device_properties_EK[] = { + {PTP_DPC_EK_ColorTemperature, N_("EK Color Temperature")}, + {PTP_DPC_EK_DateTimeStampFormat,N_("EK Date Time Stamp Format")}, + {PTP_DPC_EK_BeepMode, N_("EK Beep Mode")}, + {PTP_DPC_EK_VideoOut, N_("EK Video Out")}, + {PTP_DPC_EK_PowerSaving, N_("EK Power Saving")}, + {PTP_DPC_EK_UI_Language, N_("EK UI Language")}, + {0,NULL} +}; + +static struct { + uint16_t dpc; + const char *txt; +} ptp_device_properties_CANON[] = { + {PTP_DPC_CANON_BeepMode, N_("CANON Beep Mode")}, + {PTP_DPC_CANON_UnixTime, N_("CANON Time measured in" + " secondssince 01-01-1970")}, + {PTP_DPC_CANON_FlashMemory, N_("CANON Flash Card Capacity")}, + {PTP_DPC_CANON_CameraModel, N_("CANON Camera Model")}, + {0,NULL} +}; +/** + * Properties reported by Corey Manders and Mehreen Chaudary, revised for + * D70 by Mariusz Woloszyn + **/ +static struct { + uint16_t dpc; + const char *txt; +} ptp_device_properties_NIKON[] = { + {PTP_DPC_NIKON_ShootingBank, N_("NIKON Shooting Bank")}, + {PTP_DPC_NIKON_ShootingBankNameA, N_("NIKON Shooting Bank Name A")}, + {PTP_DPC_NIKON_ShootingBankNameB, N_("NIKON Shooting Bank Name B")}, + {PTP_DPC_NIKON_ShootingBankNameC, N_("NIKON Shooting Bank Name C")}, + {PTP_DPC_NIKON_ShootingBankNameD, N_("NIKON Shooting Bank Name D")}, + {PTP_DPC_NIKON_RawCompression, N_("NIKON Raw Compression")}, + {PTP_DPC_NIKON_WhiteBalanceAutoBias, N_("NIKON White Balance Auto Bias")}, + {PTP_DPC_NIKON_WhiteBalanceTungstenBias, N_("NIKON White Balance Tungsten Bias")}, + {PTP_DPC_NIKON_WhiteBalanceFlourescentBias, N_("NIKON White Balance Flourescent Bias")}, + {PTP_DPC_NIKON_WhiteBalanceDaylightBias, N_("NIKON White Balance Daylight Bias")}, + {PTP_DPC_NIKON_WhiteBalanceFlashBias, N_("NIKON White Balance Flash Bias")}, + {PTP_DPC_NIKON_WhiteBalanceCloudyBias, N_("NIKON White Balance Cloudy Bias")}, + {PTP_DPC_NIKON_WhiteBalanceShadeBias, N_("NIKON White Balance Shade Bias")}, + {PTP_DPC_NIKON_WhiteBalanceColorTemperature, N_("NIKON White Balance Color Temperature")}, + {PTP_DPC_NIKON_ImageSharpening, N_("NIKON Image Sharpening")}, + {PTP_DPC_NIKON_ToneCompensation, N_("NIKON Tone Compensation")}, + {PTP_DPC_NIKON_ColorMode, N_("NIKON Color Mode")}, + {PTP_DPC_NIKON_HueAdjustment, N_("NIKON Hue Adjustment")}, + {PTP_DPC_NIKON_NonCPULensDataFocalLength, N_("NIKON Non CPU Lens Data Focal Length")}, + {PTP_DPC_NIKON_NonCPULensDataMaximumAperture, N_("NIKON Non CPU Lens Data Maximum Aperture")}, + {PTP_DPC_NIKON_CSMMenuBankSelect, N_("NIKON CSM Menu Bank Select")}, + {PTP_DPC_NIKON_MenuBankNameA, N_("NIKON Menu Bank Name A")}, + {PTP_DPC_NIKON_MenuBankNameB, N_("NIKON Menu Bank Name B")}, + {PTP_DPC_NIKON_MenuBankNameC, N_("NIKON Menu Bank Name C")}, + {PTP_DPC_NIKON_MenuBankNameD, N_("NIKON Menu Bank Name D")}, + {PTP_DPC_NIKON_A1AFCModePriority, N_("NIKON (A1) AFC Mode Priority")}, + {PTP_DPC_NIKON_A2AFSModePriority, N_("NIKON (A2) AFS Mode Priority")}, + {PTP_DPC_NIKON_A3GroupDynamicAF, N_("NIKON (A3) Group Dynamic AF")}, + {PTP_DPC_NIKON_A4AFActivation, N_("NIKON (A4) AF Activation")}, + {PTP_DPC_NIKON_A5FocusAreaIllumManualFocus, N_("NIKON (A5) Focus Area Illum Manual Focus")}, + {PTP_DPC_NIKON_FocusAreaIllumContinuous, N_("NIKON Focus Area Illum Continuous")}, + {PTP_DPC_NIKON_FocusAreaIllumWhenSelected, N_("NIKON Focus Area Illum When Selected")}, + {PTP_DPC_NIKON_FocusAreaWrap, N_("NIKON Focus Area Wrap")}, + {PTP_DPC_NIKON_A7VerticalAFON, N_("NIKON (A7) Vertical AF ON")}, + {PTP_DPC_NIKON_ISOAuto, N_("NIKON ISO Auto")}, + {PTP_DPC_NIKON_B2ISOStep, N_("NIKON (B2) ISO Step")}, + {PTP_DPC_NIKON_EVStep, N_("NIKON EV Step")}, + {PTP_DPC_NIKON_B4ExposureCompEv, N_("NIKON (B4) Exposure Comp Ev")}, + {PTP_DPC_NIKON_ExposureCompensation, N_("NIKON Exposure Compensation by Command Dial only")}, + {PTP_DPC_NIKON_CenterWeightArea, N_("NIKON Center Weighted Area")}, + {PTP_DPC_NIKON_AELockMode, N_("NIKON AE Lock Mode")}, + {PTP_DPC_NIKON_AELAFLMode, N_("NIKON AE-L/AF-L Mode")}, + {PTP_DPC_NIKON_MeterOff, N_("NIKON Meter-Off")}, + {PTP_DPC_NIKON_SelfTimer, N_("NIKON Self Timer")}, + {PTP_DPC_NIKON_MonitorOff, N_("NIKON Monitor Off")}, + {PTP_DPC_NIKON_D1ShootingSpeed, N_("NIKON (D1) Shooting Speed")}, + {PTP_DPC_NIKON_ExposureTime, N_("NIKON Exposure Time")}, + {PTP_DPC_NIKON_ACPower, N_("NIKON AC Power")}, + {PTP_DPC_NIKON_D2MaximumShots, N_("NIKON (D2) Maximum Shots")}, + {PTP_DPC_NIKON_D3ExpDelayMode, N_("NIKON (D3) ExpDelayMode")}, + {PTP_DPC_NIKON_LongExposureNoiseReduction, N_("NIKON Long Exposure Noise Reduction")}, + {PTP_DPC_NIKON_FileNumberSequence, N_("NIKON File Number Sequence")}, + {PTP_DPC_NIKON_D6ControlPanelFinderRearControl, N_("NIKON (D6) Control Panel Finder Rear Control")}, + {PTP_DPC_NIKON_ControlPanelFinderViewfinder, N_("NIKON Control Panel Finder Viewfinder")}, + {PTP_DPC_NIKON_D7Illumination, N_("NIKON (D7) Illumination")}, + {PTP_DPC_NIKON_E1FlashSyncSpeed, N_("NIKON (E1) Flash Sync Speed")}, + {PTP_DPC_NIKON_FlashShutterSpeed, N_("NIKON Slowest Flash Shutter Speed")}, + {PTP_DPC_NIKON_E3AAFlashMode, N_("NIKON (E3) AA Flash Mode")}, + {PTP_DPC_NIKON_E4ModelingFlash, N_("NIKON (E4) Modeling Flash")}, + {PTP_DPC_NIKON_BracketSet, N_("NIKON Bracket Set")}, + {PTP_DPC_NIKON_E6ManualModeBracketing, N_("NIKON (E6) Manual Mode Bracketing")}, + {PTP_DPC_NIKON_BracketOrder, N_("NIKON Bracket Order")}, + {PTP_DPC_NIKON_E8AutoBracketSelection, N_("NIKON (E8) Auto Bracket Selection")}, + {PTP_DPC_NIKON_BracketingSet, N_("NIKON Auto Bracketing Set")}, + {PTP_DPC_NIKON_F1CenterButtonShootingMode, N_("NIKON (F1) Center Button Shooting Mode")}, + {PTP_DPC_NIKON_CenterButtonPlaybackMode, N_("NIKON Center Button Playback Mode")}, + {PTP_DPC_NIKON_F2Multiselector, N_("NIKON (F2) Multiselector")}, + {PTP_DPC_NIKON_F3PhotoInfoPlayback, N_("NIKON (F3) PhotoInfoPlayback")}, + {PTP_DPC_NIKON_F4AssignFuncButton, N_("NIKON (F4) Assign Function Button")}, + {PTP_DPC_NIKON_F5CustomizeCommDials, N_("NIKON (F5) Customize Comm Dials")}, + {PTP_DPC_NIKON_ReverseCommandDial, N_("NIKON Reverse Command Dials")}, + {PTP_DPC_NIKON_ApertureSetting, N_("NIKON Aperture Setting")}, + {PTP_DPC_NIKON_MenusAndPlayback, N_("NIKON Menus and Playback")}, + {PTP_DPC_NIKON_F6ButtonsAndDials, N_("NIKON (F6) Buttons and Dials")}, + {PTP_DPC_NIKON_NoCFCard, N_("NIKON No CF Card")}, + {PTP_DPC_NIKON_ImageRotation, N_("NIKON Image Rotation")}, + {PTP_DPC_NIKON_Bracketing, N_("NIKON Bracketing")}, + {PTP_DPC_NIKON_ExposureBracketingIntervalDist, N_("NIKON Exposure Bracketing Interval Distance")}, + {PTP_DPC_NIKON_BracketingProgram, N_("NIKON Bracketing Program")}, + {PTP_DPC_NIKON_WhiteBalanceBracketStep, N_("NIKON White Balance Bracket Step")}, + {PTP_DPC_NIKON_AutofocusLCDTopMode2, N_("NIKON Autofocus LCD Top Mode 2")}, + {PTP_DPC_NIKON_AutofocusArea, N_("NIKON Autofocus Area selector")}, + {PTP_DPC_NIKON_LightMeter, N_("NIKON Light Meter")}, + {PTP_DPC_NIKON_ExposureApertureLock, N_("NIKON Exposure Aperture Lock")}, + {PTP_DPC_NIKON_MaximumShots, N_("NIKON Maximum Shots")}, + {PTP_DPC_NIKON_AFLLock, N_("NIKON AF-L Locked")}, + {PTP_DPC_NIKON_BeepOff, N_("NIKON Beep")}, + {PTP_DPC_NIKON_AutofocusMode, N_("NIKON Autofocus Mode")}, + {PTP_DPC_NIKON_AFAssist, N_("NIKON AF Assist Lamp")}, + {PTP_DPC_NIKON_PADVPMode, N_("NIKON Auto ISO shutter limit for P A and DVP Mode")}, + {PTP_DPC_NIKON_ImageReview, N_("NIKON Image Review")}, + {PTP_DPC_NIKON_GridDisplay, N_("NIKON Viewfinder Grid Display")}, + {PTP_DPC_NIKON_AFAreaIllumination, N_("NIKON AF Area Illumination")}, + {PTP_DPC_NIKON_FlashMode, N_("NIKON Flash Mode")}, + {PTP_DPC_NIKON_FlashCommanderMode, N_("NIKON Flash Commander Mode")}, + {PTP_DPC_NIKON_FlashSign, N_("NIKON Flash Signal Indicator")}, + {PTP_DPC_NIKON_GridDisplay, N_("NIKON Grid Display")}, + {PTP_DPC_NIKON_FlashModeManualPower, N_("NIKON Flash Manual Mode Power")}, + {PTP_DPC_NIKON_FlashModeCommanderPower, N_("NIKON Flash Commander Mode Power")}, + {PTP_DPC_NIKON_FlashExposureCompensation, N_("NIKON Flash Exposure Compensation")}, + {PTP_DPC_NIKON_RemoteTimeout, N_("NIKON Remote Timeout")}, + {PTP_DPC_NIKON_ImageCommentString, N_("NIKON Image Comment String")}, + {PTP_DPC_NIKON_ImageCommentAttach, N_("NIKON Image Comment Attach")}, + {PTP_DPC_NIKON_FlashOpen, N_("NIKON Flash Open")}, + {PTP_DPC_NIKON_FlashCharged, N_("NIKON Flash Charged")}, + {PTP_DPC_NIKON_LensID, N_("NIKON Lens ID")}, + {PTP_DPC_NIKON_FocalLengthMin, N_("NIKON Min. Focal Length")}, + {PTP_DPC_NIKON_FocalLengthMax, N_("NIKON Max. Focal Length")}, + {PTP_DPC_NIKON_MaxApAtMinFocalLength, N_("NIKON Max. Aperture at Min. Focal Length")}, + {PTP_DPC_NIKON_MaxApAtMaxFocalLength, N_("NIKON Max. Aperture at Max. Focal Length")}, + {PTP_DPC_NIKON_LowLight, N_("NIKON Low Light Indicator")}, + {PTP_DPC_NIKON_CSMMenu, N_("NIKON CSM Menu")}, + {PTP_DPC_NIKON_OptimizeImage, N_("NIKON Optimize Image")}, + {PTP_DPC_NIKON_AutoExposureLock, N_("NIKON AE Lock")}, + {PTP_DPC_NIKON_AutoFocusLock, N_("NIKON AF Lock")}, + {PTP_DPC_NIKON_CameraOrientation, N_("NIKON Camera orientation")}, + {PTP_DPC_NIKON_BracketingIncrement, N_("NIKON Bracketing Increment")}, + {PTP_DPC_NIKON_Saturation, N_("NIKON Saturation")}, + + {0,NULL} +}; + + +/* return ptp property name */ + +const char* +ptp_prop_getname(PTPParams* params, uint16_t dpc) +{ + int i; + /* Device Property descriptions */ + for (i=0; ptp_device_properties[i].txt!=NULL; i++) + if (ptp_device_properties[i].dpc==dpc) + return (ptp_device_properties[i].txt); + + /*if (dpc|PTP_DPC_EXTENSION_MASK==PTP_DPC_EXTENSION)*/ + switch (params->deviceinfo.VendorExtensionID) { + case PTP_VENDOR_EASTMAN_KODAK: + for (i=0; ptp_device_properties_EK[i].txt!=NULL; i++) + if (ptp_device_properties_EK[i].dpc==dpc) + return (ptp_device_properties_EK[i].txt); + break; + + case PTP_VENDOR_CANON: + for (i=0; ptp_device_properties_CANON[i].txt!=NULL; i++) + if (ptp_device_properties_CANON[i].dpc==dpc) + return (ptp_device_properties_CANON[i].txt); + break; + case PTP_VENDOR_NIKON: + for (i=0; ptp_device_properties_NIKON[i].txt!=NULL; i++) + if (ptp_device_properties_NIKON[i].dpc==dpc) + return (ptp_device_properties_NIKON[i].txt); + break; + + + } + return NULL; +} + +uint16_t +ptp_prop_getcodebyname(PTPParams* params, char* name) +{ + int i; + for (i=0; ptp_device_properties[i].txt!=NULL; i++) + if (!strncasecmp(ptp_device_properties[i].txt,name, + strlen(name))) + return ptp_device_properties[i].dpc; + + /* XXX*/ + for (i=0; ptp_device_properties_NIKON[i].txt!=NULL; i++) + if (!strncasecmp(ptp_device_properties_NIKON[i].txt,name, + strlen(name))) + return ptp_device_properties_NIKON[i].dpc; + + return 0; +} + +/* properties interpretation */ + +static const char* +ptp_prop_NIKON_d100(PTPParams* params, PTPDevicePropDesc *dpd, char* strval) +{ + static char strvalret[SVALLEN]; + uint32_t val= (uint32_t) strtol (strval, NULL, 10); + uint16_t numerator=(uint16_t) (val >> 16); + uint16_t denominator=(uint16_t) val; + int n; + + n=snprintf(strvalret,SVALLEN,"%i/%i",numerator, denominator); + SVALRET(strvalret); +} + +static const char* +ptp_prop_getdescscale10000(PTPParams* params, PTPDevicePropDesc *dpd, char* strval) +{ + long long int value=strtoll(strval, NULL, 10); + double floatvalue=(double) value/(double )10000.0; + static char strvalret[SVALLEN]; + int i,n; + static struct { + uint16_t dpc; + const char *units; + } prop_units[] = { + {PTP_DPC_ExposureTime, N_("s")}, + {0, NULL} + }; + + switch (params->deviceinfo.VendorExtensionID) { + case PTP_VENDOR_NIKON: + //RETPROPDESC(pd_NIKONN); + break; + } + + //RETPROPDESC(pd); + for (i=0; prop_units[i].dpc!=0; i++) { + if (prop_units[i].dpc==dpd->DevicePropertyCode) { + n=snprintf(strvalret,SVALLEN,"%.4f%s",floatvalue,prop_units[i].units); + SVALRET(strvalret); + } + } + return NULL; +} + +static const char* +ptp_prop_getdescscale1000(PTPParams* params, PTPDevicePropDesc *dpd, char* strval) +{ + long long int value=strtoll(strval, NULL, 10); + double floatvalue=(double) value/(double )1000.0; + static char strvalret[SVALLEN]; + int i,n; + static struct { + uint16_t dpc; + const char *units; + int prec; + } prop_units[] = { + {PTP_DPC_ExposureBiasCompensation, N_(""),1}, + {0, NULL} + }; + static struct { + uint16_t dpc; + const char *units; + int prec; + } prop_units_NIKON[] = { + {0, NULL} + }; + + switch (params->deviceinfo.VendorExtensionID) { + case PTP_VENDOR_NIKON: + for (i=0; prop_units_NIKON[i].dpc!=0; i++) { + if (prop_units_NIKON[i].dpc==dpd->DevicePropertyCode){ + n=snprintf(strvalret,SVALLEN,"%.*f%s", + prop_units_NIKON[i].prec,floatvalue, + prop_units_NIKON[i].units); + SVALRET(strvalret); + } + } + break; + + } + + for (i=0; prop_units[i].dpc!=0; i++) { + if (prop_units[i].dpc==dpd->DevicePropertyCode) { + n=snprintf(strvalret,SVALLEN,"%.*f%s", + prop_units[i].prec,floatvalue, + prop_units[i].units); + SVALRET(strvalret); + } + } + return NULL; +} + +static const char* +ptp_prop_getdescscale100(PTPParams* params, PTPDevicePropDesc *dpd, char* strval) +{ + long long int value=strtoll(strval, NULL, 10); + double floatvalue=(double) value/(double )100.0; + static char strvalret[SVALLEN]; + int i,n; + static struct { + uint16_t dpc; + const char *units; + int prec; + } prop_units[] = { + {PTP_DPC_FNumber, N_(""),1}, + {PTP_DPC_FocalLength, N_("mm"),0}, + {0, NULL} + }; + static struct { + uint16_t dpc; + const char *units; + int prec; + } prop_units_NIKON[] = { + {PTP_DPC_NIKON_FocalLengthMin, N_(""),0}, + {PTP_DPC_NIKON_FocalLengthMax, N_(""),0}, + {PTP_DPC_NIKON_MaxApAtMinFocalLength, N_(""),1}, + {PTP_DPC_NIKON_MaxApAtMaxFocalLength, N_(""),1}, + {0, NULL} + }; + + switch (params->deviceinfo.VendorExtensionID) { + case PTP_VENDOR_NIKON: + for (i=0; prop_units_NIKON[i].dpc!=0; i++) { + if (prop_units_NIKON[i].dpc==dpd->DevicePropertyCode){ + n=snprintf(strvalret,SVALLEN,"%.*f%s", + prop_units_NIKON[i].prec,floatvalue, + prop_units_NIKON[i].units); + SVALRET(strvalret); + } + } + break; + } + + for (i=0; prop_units[i].dpc!=0; i++) { + if (prop_units[i].dpc==dpd->DevicePropertyCode) { + n=snprintf(strvalret,SVALLEN,"%.*f%s", + prop_units[i].prec,floatvalue, + prop_units[i].units); + SVALRET(strvalret); + } + } + return NULL; +} + + + + +static struct { + uint16_t dpc; + char *val; + const char *txt; +} ptp_property_meaning[] = { + {PTP_DPC_WhiteBalance, "1", N_("Manual")}, + {PTP_DPC_WhiteBalance, "2", N_("Automatic")}, + {PTP_DPC_WhiteBalance, "3", N_("One-push Automatic")}, + {PTP_DPC_WhiteBalance, "4", N_("Daylight")}, + {PTP_DPC_WhiteBalance, "5", N_("Fluorescent")}, + {PTP_DPC_WhiteBalance, "6", N_("Tungsten")}, + {PTP_DPC_WhiteBalance, "7", N_("Flash")}, + {PTP_DPC_FocusMode, "1", N_("Manual")}, + {PTP_DPC_FocusMode, "2", N_("Automatic")}, + {PTP_DPC_FocusMode, "3", N_("Automatic Macro")}, + {PTP_DPC_ExposureMeteringMode, "1", N_("Manual")}, + {PTP_DPC_ExposureMeteringMode, "2", N_("Center-weighted")}, + {PTP_DPC_ExposureMeteringMode, "3", N_("Multi-spot")}, + {PTP_DPC_ExposureMeteringMode, "4", N_("Center-spot")}, + {PTP_DPC_FlashMode, "1", N_("Auto flash")}, + {PTP_DPC_FlashMode, "2", N_("Flash off")}, + {PTP_DPC_FlashMode, "3", N_("Fill flash")}, + {PTP_DPC_FlashMode, "4", N_("Red eye auto")}, + {PTP_DPC_FlashMode, "5", N_("Red eye fill")}, + {PTP_DPC_FlashMode, "6", N_("External flash")}, + {PTP_DPC_ExposureProgramMode, "1", N_("Manual")}, + {PTP_DPC_ExposureProgramMode, "2", N_("Automatic (P)")}, + {PTP_DPC_ExposureProgramMode, "3", N_("Aperture Priority")}, + {PTP_DPC_ExposureProgramMode, "4", N_("Shutter Priority")}, + {PTP_DPC_ExposureProgramMode, "5", N_("Program Creative")}, + {PTP_DPC_ExposureProgramMode, "6", N_("Program Action")}, + {PTP_DPC_ExposureProgramMode, "7", N_("Portrait")}, + {PTP_DPC_StillCaptureMode, "1", N_("Normal")}, + {PTP_DPC_StillCaptureMode, "2", N_("Burst")}, + {PTP_DPC_StillCaptureMode, "3", N_("Timelapse")}, + {PTP_DPC_FocusMeteringMode, "1", N_("Center-spot")}, + {PTP_DPC_FocusMeteringMode, "2", N_("Multi-spot")}, + + /* returned by function call */ + {PTP_DPC_FNumber, (char*) ptp_prop_getdescscale100, NULL}, + {PTP_DPC_FocalLength, (char*) ptp_prop_getdescscale100, NULL}, + {PTP_DPC_ExposureTime, (char*) ptp_prop_getdescscale10000, NULL}, + {PTP_DPC_ExposureBiasCompensation,(char*) ptp_prop_getdescscale1000,NULL}, + {0, NULL, NULL} +}; + +static struct { + uint16_t dpc; + char *val; + const char *txt; +} ptp_property_meaning_NIKON[] = { + {PTP_DPC_CompressionSetting, "0", N_("JPEG Basic")}, + {PTP_DPC_CompressionSetting, "1", N_("JPEG Normal")}, + {PTP_DPC_CompressionSetting, "2", N_("JPEG Fine")}, + {PTP_DPC_CompressionSetting, "4", N_("NEF RAW")}, + {PTP_DPC_CompressionSetting, "5", N_("NEF+JPEG Basic")}, + {PTP_DPC_WhiteBalance, "2", N_("Automatic")}, + {PTP_DPC_WhiteBalance, "4", N_("Direct Sunlight")}, + {PTP_DPC_WhiteBalance, "5", N_("Fluorescent")}, + {PTP_DPC_WhiteBalance, "6", N_("Incadescent")}, + {PTP_DPC_WhiteBalance, "7", N_("Flash")}, + {PTP_DPC_WhiteBalance, "32784", N_("Cloudy")}, + {PTP_DPC_WhiteBalance, "32785", N_("Shade")}, + {PTP_DPC_WhiteBalance, "32786", N_("Color Temperature")}, + {PTP_DPC_WhiteBalance, "32787", N_("Preset")}, + {PTP_DPC_FocusMode, "32784", N_("AF-S (single-servo)")}, + {PTP_DPC_FocusMode, "32785", N_("AF-C (continuous-servo)")}, + {PTP_DPC_FlashMode, "4", N_("Red-eye reduction")}, + {PTP_DPC_FlashMode, "32784", N_("Front-courtain")}, + {PTP_DPC_FlashMode, "32785", N_("Slow Sync")}, + {PTP_DPC_FlashMode, "32786", N_("(Slow) Rear-curtain")}, + {PTP_DPC_FlashMode, "32787", N_("Slow Sync with Red-eye")}, + {PTP_DPC_ExposureProgramMode, "32784", N_("Camera Auto")}, + {PTP_DPC_ExposureProgramMode, "32785", N_("Portrait")}, + {PTP_DPC_ExposureProgramMode, "32786", N_("Landscape")}, + {PTP_DPC_ExposureProgramMode, "32787", N_("Close Up")}, + {PTP_DPC_ExposureProgramMode, "32788", N_("Sports")}, + {PTP_DPC_ExposureProgramMode, "32789", N_("Night Portrait")}, + {PTP_DPC_ExposureProgramMode, "32790", N_("Night Landscape")}, + {PTP_DPC_StillCaptureMode, "1", N_("Single Frame")}, + {PTP_DPC_StillCaptureMode, "2", N_("Continuous")}, + {PTP_DPC_StillCaptureMode, "32784", N_("Continuous Low Speed")}, + {PTP_DPC_StillCaptureMode, "32785", N_("Self-timer")}, + {PTP_DPC_StillCaptureMode, "32787", N_("Remote")}, + {PTP_DPC_StillCaptureMode, "32786", N_("Mirror Up")}, + {PTP_DPC_StillCaptureMode, "32788", N_("Delayed Remote")}, + {PTP_DPC_FocusMeteringMode, "2", N_("Dynamic Area")}, + {PTP_DPC_FocusMeteringMode, "32784", N_("Single Area")}, + {PTP_DPC_FocusMeteringMode, "32785", N_("Closest Subject")}, + {PTP_DPC_FocusMeteringMode, "32786", N_("Group Dynamic")}, + {PTP_DPC_NIKON_ImageSharpening, "0", N_("Auto")}, + {PTP_DPC_NIKON_ImageSharpening, "1", N_("Normal")}, + {PTP_DPC_NIKON_ImageSharpening, "2", N_("-2 Low")}, + {PTP_DPC_NIKON_ImageSharpening, "3", N_("-1 Medium Low")}, + {PTP_DPC_NIKON_ImageSharpening, "4", N_("+1 Medium High")}, + {PTP_DPC_NIKON_ImageSharpening, "5", N_("+2 High")}, + {PTP_DPC_NIKON_ImageSharpening, "6", N_("None")}, + {PTP_DPC_NIKON_ToneCompensation, "0", N_("Auto")}, + {PTP_DPC_NIKON_ToneCompensation, "1", N_("Normal")}, + {PTP_DPC_NIKON_ToneCompensation, "2", N_("-2 Low Contrast")}, + {PTP_DPC_NIKON_ToneCompensation, "3", N_("-1 Medium Low")}, + {PTP_DPC_NIKON_ToneCompensation, "4", N_("+1 Medium High")}, + {PTP_DPC_NIKON_ToneCompensation, "5", N_("+2 High Contrast")}, + {PTP_DPC_NIKON_ToneCompensation, "6", N_("Custom")}, + {PTP_DPC_NIKON_ColorMode, "0", N_("Ia (sRGB)")}, + {PTP_DPC_NIKON_ColorMode, "1", N_("II (Adobe RGB)")}, + {PTP_DPC_NIKON_ColorMode, "2", N_("IIIa (sRGB)")}, + {PTP_DPC_NIKON_Saturation, "0", N_("Normal")}, + {PTP_DPC_NIKON_Saturation, "1", N_("Moderate")}, + {PTP_DPC_NIKON_Saturation, "2", N_("Enhanced")}, + {PTP_DPC_NIKON_OptimizeImage, "0", N_("Normal")}, + {PTP_DPC_NIKON_OptimizeImage, "1", N_("Vivid")}, + {PTP_DPC_NIKON_OptimizeImage, "2", N_("Sharp")}, + {PTP_DPC_NIKON_OptimizeImage, "3", N_("Soft")}, + {PTP_DPC_NIKON_OptimizeImage, "4", N_("Direct Print")}, + {PTP_DPC_NIKON_OptimizeImage, "5", N_("Portrait")}, + {PTP_DPC_NIKON_OptimizeImage, "6", N_("Landscape")}, + {PTP_DPC_NIKON_OptimizeImage, "7", N_("Custom")}, + {PTP_DPC_NIKON_FocusAreaWrap, "1", N_("Wrap")}, + {PTP_DPC_NIKON_FocusAreaWrap, "0", N_("No Wrap")}, + {PTP_DPC_NIKON_ISOAuto, "0", N_("Off")}, + {PTP_DPC_NIKON_ISOAuto, "1", N_("On")}, + {PTP_DPC_NIKON_ExposureCompensation, "0", N_("Off")}, + {PTP_DPC_NIKON_ExposureCompensation, "1", N_("On")}, + {PTP_DPC_NIKON_CenterWeightArea, "0", N_("6mm")}, + {PTP_DPC_NIKON_CenterWeightArea, "1", N_("8mm")}, + {PTP_DPC_NIKON_CenterWeightArea, "2", N_("10mm")}, + {PTP_DPC_NIKON_CenterWeightArea, "3", N_("12mm")}, + {PTP_DPC_NIKON_AELockMode, "0", N_("AE-L Button")}, + {PTP_DPC_NIKON_AELockMode, "1", N_("Release Button")}, + {PTP_DPC_NIKON_AELAFLMode, "0", N_("Exposure and Focus Lock")}, + {PTP_DPC_NIKON_AELAFLMode, "1", N_("Exposure Lock Only")}, + {PTP_DPC_NIKON_AELAFLMode, "2", N_("Focus Lock Only")}, + {PTP_DPC_NIKON_AELAFLMode, "3", N_("Exposure Lock Hold")}, + {PTP_DPC_NIKON_AELAFLMode, "4", N_("AF-ON")}, + {PTP_DPC_NIKON_AELAFLMode, "5", N_("FV Lock")}, + {PTP_DPC_NIKON_MeterOff, "0", N_("4s")}, + {PTP_DPC_NIKON_MeterOff, "1", N_("6s")}, + {PTP_DPC_NIKON_MeterOff, "2", N_("8s")}, + {PTP_DPC_NIKON_MeterOff, "3", N_("16s")}, + {PTP_DPC_NIKON_MeterOff, "4", N_("30min")}, + {PTP_DPC_NIKON_SelfTimer, "0", N_("2s")}, + {PTP_DPC_NIKON_SelfTimer, "1", N_("5s")}, + {PTP_DPC_NIKON_SelfTimer, "2", N_("10s")}, + {PTP_DPC_NIKON_SelfTimer, "3", N_("20s")}, + {PTP_DPC_NIKON_MonitorOff, "0", N_("10s")}, + {PTP_DPC_NIKON_MonitorOff, "1", N_("20s")}, + {PTP_DPC_NIKON_MonitorOff, "2", N_("1m")}, + {PTP_DPC_NIKON_MonitorOff, "3", N_("5m")}, + {PTP_DPC_NIKON_MonitorOff, "4", N_("10m")}, + {PTP_DPC_NIKON_LongExposureNoiseReduction, "0", N_("Off")}, + {PTP_DPC_NIKON_LongExposureNoiseReduction, "1", N_("On")}, + {PTP_DPC_NIKON_FileNumberSequence, "0", N_("Off")}, + {PTP_DPC_NIKON_FileNumberSequence, "1", N_("On")}, + {PTP_DPC_NIKON_FileNumberSequence, "2", N_("Reset!")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "0", N_("1/60")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "1", N_("1/30")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "2", N_("1/15")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "3", N_("1/8")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "4", N_("1/4")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "5", N_("1/2")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "6", N_("1s")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "7", N_("2s")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "8", N_("4s")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "9", N_("8s")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "10", N_("15s")}, + {PTP_DPC_NIKON_FlashShutterSpeed, "11", N_("30s")}, + {PTP_DPC_NIKON_BracketSet, "0", N_("AE & Flash")}, + {PTP_DPC_NIKON_BracketSet, "1", N_("AE Only")}, + {PTP_DPC_NIKON_BracketSet, "2", N_("Flash Only")}, + {PTP_DPC_NIKON_BracketSet, "3", N_("White Balance")}, + {PTP_DPC_NIKON_BracketOrder, "0", N_("MTR->Under->Over")}, + {PTP_DPC_NIKON_BracketOrder, "1", N_("Under->MTR->Over")}, + {PTP_DPC_NIKON_ReverseCommandDial, "0", N_("No")}, + {PTP_DPC_NIKON_ReverseCommandDial, "1", N_("Yes")}, + {PTP_DPC_NIKON_NoCFCard, "1", N_("Release Locked")}, + {PTP_DPC_NIKON_NoCFCard, "0", N_("Enabled Release")}, + {PTP_DPC_NIKON_ImageCommentAttach, "1", N_("On")}, + {PTP_DPC_NIKON_ImageCommentAttach, "0", N_("Off")}, + {PTP_DPC_NIKON_ImageRotation, "0", N_("Automatic")}, + {PTP_DPC_NIKON_ImageRotation, "1", N_("Off")}, + {PTP_DPC_NIKON_BracketingProgram, "0", N_("-2F")}, + {PTP_DPC_NIKON_BracketingProgram, "1", N_("+2F")}, + {PTP_DPC_NIKON_BracketingProgram, "2", N_("3F")}, + {PTP_DPC_NIKON_Bracketing, "0", N_("Off")}, + {PTP_DPC_NIKON_Bracketing, "1", N_("On")}, + {PTP_DPC_NIKON_AutofocusArea, "0", N_("
")}, + {PTP_DPC_NIKON_AutofocusArea, "1", N_("")}, + {PTP_DPC_NIKON_AutofocusArea, "2", N_("")}, + {PTP_DPC_NIKON_AutofocusArea, "3", N_("")}, + {PTP_DPC_NIKON_AutofocusArea, "4", N_("")}, + {PTP_DPC_NIKON_CameraOrientation, "0", N_("Landscape")}, + {PTP_DPC_NIKON_CameraOrientation, "1", N_("Left Hand")}, + {PTP_DPC_NIKON_CameraOrientation, "2", N_("Right Hand")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-18", N_("-3")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-16", N_("-2.7")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-15", N_("-2.5")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-14", N_("-2.3")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-12", N_("-2.0")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-10", N_("-1.7")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-9", N_("-1.5")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-8", N_("-1.3")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-6", N_("-1.0")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-4", N_("-0.7")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-3", N_("-0.5")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "-2", N_("-0.3")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "0", N_("0.0")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "2", N_("+0.3")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "3", N_("+0.5")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "4", N_("+0.7")}, + {PTP_DPC_NIKON_FlashExposureCompensation, "6", N_("+1.0")}, + {PTP_DPC_NIKON_BeepOff, "1", N_("Off")}, + {PTP_DPC_NIKON_BeepOff, "0", N_("On")}, + {PTP_DPC_NIKON_AutofocusMode, "0", N_("AF-S (single-servo)")}, + {PTP_DPC_NIKON_AutofocusMode, "1", N_("AF-C (continuous-servo)")}, + {PTP_DPC_NIKON_AFAssist, "0", N_("On")}, + {PTP_DPC_NIKON_AFAssist, "1", N_("Off")}, + {PTP_DPC_NIKON_PADVPMode, "0", N_("1/125")}, + {PTP_DPC_NIKON_PADVPMode, "1", N_("1/60")}, + {PTP_DPC_NIKON_PADVPMode, "2", N_("1/30")}, + {PTP_DPC_NIKON_PADVPMode, "3", N_("1/15")}, + {PTP_DPC_NIKON_PADVPMode, "4", N_("1/8")}, + {PTP_DPC_NIKON_PADVPMode, "5", N_("1/4")}, + {PTP_DPC_NIKON_PADVPMode, "6", N_("1/2")}, + {PTP_DPC_NIKON_PADVPMode, "7", N_("1")}, + {PTP_DPC_NIKON_PADVPMode, "8", N_("2")}, + {PTP_DPC_NIKON_PADVPMode, "9", N_("4")}, + {PTP_DPC_NIKON_PADVPMode, "10", N_("8")}, + {PTP_DPC_NIKON_PADVPMode, "11", N_("15")}, + {PTP_DPC_NIKON_PADVPMode, "12", N_("30")}, + {PTP_DPC_NIKON_ImageReview, "0", N_("On")}, + {PTP_DPC_NIKON_ImageReview, "1", N_("Off")}, + {PTP_DPC_NIKON_AFAreaIllumination, "0", N_("Auto")}, + {PTP_DPC_NIKON_AFAreaIllumination, "1", N_("Off")}, + {PTP_DPC_NIKON_AFAreaIllumination, "2", N_("On")}, + {PTP_DPC_NIKON_FlashMode, "0", N_("TTL")}, + {PTP_DPC_NIKON_FlashMode, "1", N_("Manual")}, + {PTP_DPC_NIKON_FlashMode, "2", N_("Commander Mode")}, + {PTP_DPC_NIKON_FlashCommanderMode, "0", N_("TTL")}, + {PTP_DPC_NIKON_FlashCommanderMode, "1", N_("AA")}, + {PTP_DPC_NIKON_FlashCommanderMode, "2", N_("M")}, + {PTP_DPC_NIKON_FlashSign, "0", N_("On")}, + {PTP_DPC_NIKON_FlashSign, "1", N_("Off")}, + {PTP_DPC_NIKON_RemoteTimeout, "0", N_("1min")}, + {PTP_DPC_NIKON_RemoteTimeout, "1", N_("5min")}, + {PTP_DPC_NIKON_RemoteTimeout, "2", N_("10min")}, + {PTP_DPC_NIKON_RemoteTimeout, "3", N_("15min")}, + {PTP_DPC_NIKON_GridDisplay, "0", N_("Off")}, + {PTP_DPC_NIKON_GridDisplay, "1", N_("On")}, + {PTP_DPC_NIKON_FlashModeManualPower, "0", N_("Full power")}, + {PTP_DPC_NIKON_FlashModeManualPower, "1", N_("1/2 power")}, + {PTP_DPC_NIKON_FlashModeManualPower, "2", N_("1/4 power")}, + {PTP_DPC_NIKON_FlashModeManualPower, "3", N_("1/8 power")}, + {PTP_DPC_NIKON_FlashModeManualPower, "4", N_("1/16 power")}, + {PTP_DPC_NIKON_FlashModeCommanderPower, "0", N_("FULL")}, + {PTP_DPC_NIKON_FlashModeCommanderPower, "1", N_("1/2")}, + {PTP_DPC_NIKON_FlashModeCommanderPower, "2", N_("1/4")}, + {PTP_DPC_NIKON_FlashModeCommanderPower, "3", N_("1/8")}, + {PTP_DPC_NIKON_FlashModeCommanderPower, "4", N_("1/16")}, + {PTP_DPC_NIKON_FlashModeCommanderPower, "5", N_("1/32")}, + {PTP_DPC_NIKON_FlashModeCommanderPower, "6", N_("1/64")}, + {PTP_DPC_NIKON_FlashModeCommanderPower, "7", N_("1/128")}, + {PTP_DPC_NIKON_CSMMenu, "0", N_("Simple")}, + {PTP_DPC_NIKON_CSMMenu, "1", N_("Detailed")}, + {PTP_DPC_NIKON_CSMMenu, "2", N_("Yet Unknown/Hidden?")}, + {PTP_DPC_NIKON_BracketingIncrement, "12", N_("2.0")}, + {PTP_DPC_NIKON_BracketingIncrement, "10", N_("1.7")}, + {PTP_DPC_NIKON_BracketingIncrement, "9", N_("1.5")}, + {PTP_DPC_NIKON_BracketingIncrement, "8", N_("1.3")}, + {PTP_DPC_NIKON_BracketingIncrement, "6", N_("1.0")}, + {PTP_DPC_NIKON_BracketingIncrement, "4", N_("0.7")}, + {PTP_DPC_NIKON_BracketingIncrement, "3", N_("0.5")}, + {PTP_DPC_NIKON_BracketingIncrement, "2", N_("0.3")}, + {PTP_DPC_NIKON_BracketingIncrement, "0", N_("0.0")}, + {PTP_DPC_NIKON_EVStep, "0", N_("1/3")}, + {PTP_DPC_NIKON_EVStep, "1", N_("1/2")}, + {PTP_DPC_NIKON_LowLight, "0", N_("No")}, + {PTP_DPC_NIKON_LowLight, "1", N_("Yes")}, + {PTP_DPC_NIKON_FlashOpen, "0", N_("No")}, + {PTP_DPC_NIKON_FlashOpen, "1", N_("Yes")}, + {PTP_DPC_NIKON_FlashCharged, "0", N_("No")}, + {PTP_DPC_NIKON_FlashCharged, "1", N_("Yes")}, + {PTP_DPC_NIKON_AutoExposureLock, "1", N_("Locked")}, + {PTP_DPC_NIKON_AutoExposureLock, "0", N_("Not Locked")}, + + {PTP_DPC_ExposureTime, "4294967295", N_("bulb")}, + {PTP_DPC_NIKON_ExposureTime, "4294967295", N_("bulb")}, + + /* returned by function call */ + {PTP_DPC_NIKON_FocalLengthMin, (char*) ptp_prop_getdescscale100, NULL}, + {PTP_DPC_NIKON_FocalLengthMax, (char*) ptp_prop_getdescscale100, NULL}, + {PTP_DPC_NIKON_MaxApAtMinFocalLength,(char*) ptp_prop_getdescscale100, NULL}, + {PTP_DPC_NIKON_MaxApAtMaxFocalLength,(char*) ptp_prop_getdescscale100, NULL}, + {PTP_DPC_NIKON_ExposureTime,(char*) ptp_prop_NIKON_d100, NULL}, + {0, NULL, NULL} +}; + + +/* return property value description */ +#define RETPROPDESC(desc) \ + {\ + for (i=0; desc[i].dpc!=0; i++) { \ + if (desc[i].txt!=NULL) { \ + if (desc[i].dpc==dpd->DevicePropertyCode && \ + !strcmp(desc[i].val,strval))\ + return (desc[i].txt);\ + } \ + else {\ + if (desc[i].dpc==dpd->DevicePropertyCode) \ + return (((const char* (*) ()) desc[i].val) (params, dpd, strval)); \ + }\ + } \ + } + +/** + * ptp_prop_getdescbystring: + * params: PTPParams* + * PTPDevicePropDesc *dpd - Device Property structure + * void *value - if not null convert this value + * (used internaty to convert + * values other than current) + * + * Returns: pointer to staticaly allocated buffer with property value + * meaning as string + * + **/ +const char* +ptp_prop_getdescbystring(PTPParams* params,PTPDevicePropDesc *dpd,const char *strval) +{ + int i; + + switch (params->deviceinfo.VendorExtensionID) { + case PTP_VENDOR_NIKON: + RETPROPDESC(ptp_property_meaning_NIKON); + break; + } + + RETPROPDESC(ptp_property_meaning); + + return NULL; +} + +/** + * ptp_prop_getdesc: + * params: PTPParams* + * PTPDevicePropDesc *dpd - Device Property structure + * void *value - if not null convert this value + * (used internaty to convert + * values other than current) + * + * Returns: pointer to staticaly allocated buffer with property value + * meaning as string + * + **/ +const char* +ptp_prop_getdesc(PTPParams* params, PTPDevicePropDesc *dpd, void *val) +{ + const char *strval; + /* Get Device Property value as string */ + strval=ptp_prop_tostr(params, dpd, val); + + return ptp_prop_getdescbystring(params, dpd, strval); +} + +/** + * ptp_prop_tostr: + * params: PTPParams* + * PTPDevicePropDesc *dpd - Device Property structure + * void *value - if not null convert this value + * (used internaty to convert + * values other than current) + * + * Returns: pointer to staticaly allocated buffer with property value + * representation as string + * + **/ + +const char * +ptp_prop_tostr (PTPParams* params, PTPDevicePropDesc *dpd, void *val) +{ + static char strval[SVALLEN]; + int n; + void *value=val==NULL?dpd->CurrentValue:val; + + memset(&strval, 0, SVALLEN); + + switch (dpd->DataType) { + case PTP_DTC_INT8: + n=snprintf(strval,SVALLEN,"%hhi",*(char*)value); + SVALRET(strval); + case PTP_DTC_UINT8: + n=snprintf(strval,SVALLEN,"%hhu",*(unsigned char*)value); + SVALRET(strval); + case PTP_DTC_INT16: + n=snprintf(strval,SVALLEN,"%hi",*(int16_t*)value); + SVALRET(strval); + case PTP_DTC_UINT16: + n=snprintf(strval,SVALLEN,"%hu",*(uint16_t*)value); + SVALRET(strval); + case PTP_DTC_INT32: + n=snprintf(strval,SVALLEN,"%li",(long int)*(int32_t*)value); + SVALRET(strval); + case PTP_DTC_UINT32: + n=snprintf(strval,SVALLEN,"%lu",(unsigned long)*(uint32_t*)value); + SVALRET(strval); + case PTP_DTC_STR: + n=snprintf(strval,SVALLEN,"\"%s\"",(char *)value); + SVALRET(strval); + } + return NULL; +} + +const char* +ptp_prop_getvalbyname(PTPParams* params, char* name, uint16_t dpc) +{ + int i; + /* doeasn't match for function interpretation */ + for (i=0; ptp_property_meaning[i].txt!=NULL; i++) + if (ptp_property_meaning[i].dpc==dpc) + if (! strncasecmp(ptp_property_meaning[i].txt,name, + strlen(name))) + return ptp_property_meaning[i].val; + + /* XXX */ + for (i=0; ptp_property_meaning_NIKON[i].txt!=NULL; i++) + if (ptp_property_meaning_NIKON[i].dpc==dpc) + if (!strncasecmp(ptp_property_meaning_NIKON[i].txt,name, + strlen(name))) + return ptp_property_meaning_NIKON[i].val; + + return NULL; +} + diff --git a/tools/ptpcam/ptp-pack.c b/tools/ptpcam/ptp-pack.c new file mode 100644 index 00000000..daf811b2 --- /dev/null +++ b/tools/ptpcam/ptp-pack.c @@ -0,0 +1,773 @@ +/* ptp-pack.c + * + * Copyright (C) 2002-2005 Mariusz Woloszyn + * + * This file is part of libptp2. + * + * libptp2 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. + * + * libptp2 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 libptp2; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* curently this file is included into ptp.c */ + +static inline uint16_t +htod16p (PTPParams *params, uint16_t var) +{ + return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var)); +} + +static inline uint32_t +htod32p (PTPParams *params, uint32_t var) +{ + return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var)); +} + +static inline void +htod16ap (PTPParams *params, unsigned char *a, uint16_t val) +{ + if (params->byteorder==PTP_DL_LE) + htole16a(a,val); else + htobe16a(a,val); +} + +static inline void +htod32ap (PTPParams *params, unsigned char *a, uint32_t val) +{ + if (params->byteorder==PTP_DL_LE) + htole32a(a,val); else + htobe32a(a,val); +} + +static inline uint16_t +dtoh16p (PTPParams *params, uint16_t var) +{ + return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var)); +} + +static inline uint32_t +dtoh32p (PTPParams *params, uint32_t var) +{ + return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var)); +} + +static inline uint16_t +dtoh16ap (PTPParams *params, unsigned char *a) +{ + return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a)); +} + +static inline uint32_t +dtoh32ap (PTPParams *params, unsigned char *a) +{ + return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a)); +} + +#define htod8a(a,x) *(uint8_t*)(a) = x +#define htod16a(a,x) htod16ap(params,(unsigned char *)a,x) +#define htod32a(a,x) htod32ap(params,(unsigned char *)a,x) +#define htod16(x) htod16p(params,x) +#define htod32(x) htod32p(params,x) + +#define dtoh8a(x) (*(uint8_t*)(x)) +#define dtoh16a(a) dtoh16ap(params,(unsigned char *)a) +#define dtoh32a(a) dtoh32ap(params,(unsigned char *)a) +#define dtoh16(x) dtoh16p(params,x) +#define dtoh32(x) dtoh32p(params,x) + + +static inline char* +ptp_unpack_string(PTPParams *params, char* data, uint16_t offset, uint8_t *len) +{ + int i; + char *string=NULL; + + *len=dtoh8a(&data[offset]); + if (*len) { + string=malloc(*len); + memset(string, 0, *len); + for (i=0;i<*len && i< PTP_MAXSTRLEN; i++) { + string[i]=(char)dtoh16a(&data[offset+i*2+1]); + } + /* be paranoid! :( */ + string[*len-1]=0; + } + return (string); +} + +static inline void +ptp_pack_string(PTPParams *params, char *string, char* data, uint16_t offset, uint8_t *len) +{ + int i; + *len = (uint8_t)strlen(string); + + /* XXX: check strlen! */ + htod8a(&data[offset],*len+1); + for (i=0;i<*len && i< PTP_MAXSTRLEN; i++) { + htod16a(&data[offset+i*2+1],(uint16_t)string[i]); + } +} + +static inline uint32_t +ptp_unpack_uint32_t_array(PTPParams *params, char* data, uint16_t offset, uint32_t **array) +{ + uint32_t n, i=0; + + n=dtoh32a(&data[offset]); + *array = malloc (n*sizeof(uint32_t)); + while (n>i) { + (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]); + i++; + } + return n; +} + +static inline uint32_t +ptp_unpack_uint16_t_array(PTPParams *params, char* data, uint16_t offset, uint16_t **array) +{ + uint32_t n, i=0; + + n=dtoh32a(&data[offset]); + *array = malloc (n*sizeof(uint16_t)); + while (n>i) { + (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]); + i++; + } + return n; +} + +/* DeviceInfo pack/unpack */ + +#define PTP_di_StandardVersion 0 +#define PTP_di_VendorExtensionID 2 +#define PTP_di_VendorExtensionVersion 6 +#define PTP_di_VendorExtensionDesc 8 +#define PTP_di_FunctionalMode 8 +#define PTP_di_OperationsSupported 10 + +static inline void +ptp_unpack_DI (PTPParams *params, char* data, PTPDeviceInfo *di) +{ + uint8_t len; + unsigned int totallen; + + di->StaqndardVersion = dtoh16a(&data[PTP_di_StandardVersion]); + di->VendorExtensionID = + dtoh32a(&data[PTP_di_VendorExtensionID]); + di->VendorExtensionVersion = + dtoh16a(&data[PTP_di_VendorExtensionVersion]); + di->VendorExtensionDesc = + ptp_unpack_string(params, data, + PTP_di_VendorExtensionDesc, &len); + totallen=len*2+1; + di->FunctionalMode = + dtoh16a(&data[PTP_di_FunctionalMode+totallen]); + di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->OperationsSupported); + totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t); + di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->EventsSupported); + totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t); + di->DevicePropertiesSupported_len = + ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->DevicePropertiesSupported); + totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t); + di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->CaptureFormats); + totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t); + di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data, + PTP_di_OperationsSupported+totallen, + &di->ImageFormats); + totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t); + di->Manufacturer = ptp_unpack_string(params, data, + PTP_di_OperationsSupported+totallen, + &len); + totallen+=len*2+1; + di->Model = ptp_unpack_string(params, data, + PTP_di_OperationsSupported+totallen, + &len); + totallen+=len*2+1; + di->DeviceVersion = ptp_unpack_string(params, data, + PTP_di_OperationsSupported+totallen, + &len); + totallen+=len*2+1; + di->SerialNumber = ptp_unpack_string(params, data, + PTP_di_OperationsSupported+totallen, + &len); +} + +/* ObjectHandles array pack/unpack */ + +#define PTP_oh 0 + +static inline void +ptp_unpack_OH (PTPParams *params, char* data, PTPObjectHandles *oh) +{ + oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler); +} + +/* StoreIDs array pack/unpack */ + +#define PTP_sids 0 + +static inline void +ptp_unpack_SIDs (PTPParams *params, char* data, PTPStorageIDs *sids) +{ + sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids, + &sids->Storage); +} + +/* StorageInfo pack/unpack */ + +#define PTP_si_StorageType 0 +#define PTP_si_FilesystemType 2 +#define PTP_si_AccessCapability 4 +#define PTP_si_MaxCapability 6 +#define PTP_si_FreeSpaceInBytes 14 +#define PTP_si_FreeSpaceInImages 22 +#define PTP_si_StorageDescription 26 + +static inline void +ptp_unpack_SI (PTPParams *params, char* data, PTPStorageInfo *si) +{ + uint8_t storagedescriptionlen; + + si->StorageType=dtoh16a(&data[PTP_si_StorageType]); + si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]); + si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]); + /* XXX no dtoh64a !!! skiping next two */ + si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]); + si->StorageDescription=ptp_unpack_string(params, data, + PTP_si_StorageDescription, &storagedescriptionlen); + si->VolumeLabel=ptp_unpack_string(params, data, + PTP_si_StorageDescription+storagedescriptionlen*2+1, + &storagedescriptionlen); +} + +/* ObjectInfo pack/unpack */ + +#define PTP_oi_StorageID 0 +#define PTP_oi_ObjectFormat 4 +#define PTP_oi_ProtectionStatus 6 +#define PTP_oi_ObjectCompressedSize 8 +#define PTP_oi_ThumbFormat 12 +#define PTP_oi_ThumbCompressedSize 14 +#define PTP_oi_ThumbPixWidth 18 +#define PTP_oi_ThumbPixHeight 22 +#define PTP_oi_ImagePixWidth 26 +#define PTP_oi_ImagePixHeight 30 +#define PTP_oi_ImageBitDepth 34 +#define PTP_oi_ParentObject 38 +#define PTP_oi_AssociationType 42 +#define PTP_oi_AssociationDesc 44 +#define PTP_oi_SequenceNumber 48 +#define PTP_oi_filenamelen 52 +#define PTP_oi_Filename 53 + +static inline uint32_t +ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, char** oidataptr) +{ + char* oidata; + uint8_t filenamelen; + uint8_t capturedatelen=0; + /* let's allocate some memory first; XXX i'm sure it's wrong */ + oidata=malloc(PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4); + /* the caller should free it after use! */ +#if 0 + char *capture_date="20020101T010101"; /* XXX Fake date */ +#endif + memset (oidata, 0, (PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4)); + htod32a(&oidata[PTP_oi_StorageID],oi->StorageID); + htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat); + htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus); + htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize); + htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat); + htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize); + htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth); + htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight); + htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth); + htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight); + htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth); + htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject); + htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType); + htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc); + htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber); + + ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen); +/* + filenamelen=(uint8_t)strlen(oi->Filename); + htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1); + for (i=0;idata[PTP_oi_Filename+i*2]=oi->Filename[i]; + } +*/ + /* + *XXX Fake date. + * for example Kodak sets Capture date on the basis of EXIF data. + * Spec says that this field is from perspective of Initiator. + */ +#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/ + capturedatelen=strlen(capture_date); + htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2], + capturedatelen+1); + for (i=0;iStorageID=dtoh32a(&data[PTP_oi_StorageID]); + oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]); + oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]); + oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]); + oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]); + oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]); + oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]); + oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]); + oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]); + oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]); + oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]); + oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]); + oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]); + oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]); + oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]); + oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen); + + capture_date = ptp_unpack_string(params, data, + PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen); + /* subset of ISO 8601, without '.s' tenths of second and + * time zone + */ + if (capturedatelen>15) + { + strncpy (tmp, capture_date, 4); + tmp[4] = 0; + tm.tm_year=atoi (tmp) - 1900; + strncpy (tmp, capture_date + 4, 2); + tmp[2] = 0; + tm.tm_mon = atoi (tmp) - 1; + strncpy (tmp, capture_date + 6, 2); + tmp[2] = 0; + tm.tm_mday = atoi (tmp); + strncpy (tmp, capture_date + 9, 2); + tmp[2] = 0; + tm.tm_hour = atoi (tmp); + strncpy (tmp, capture_date + 11, 2); + tmp[2] = 0; + tm.tm_min = atoi (tmp); + strncpy (tmp, capture_date + 13, 2); + tmp[2] = 0; + tm.tm_sec = atoi (tmp); + oi->CaptureDate=mktime (&tm); + } + free(capture_date); + + /* now it's modification date ;) */ + capture_date = ptp_unpack_string(params, data, + PTP_oi_filenamelen+filenamelen*2 + +capturedatelen*2+2,&capturedatelen); + if (capturedatelen>15) + { + strncpy (tmp, capture_date, 4); + tmp[4] = 0; + tm.tm_year=atoi (tmp) - 1900; + strncpy (tmp, capture_date + 4, 2); + tmp[2] = 0; + tm.tm_mon = atoi (tmp) - 1; + strncpy (tmp, capture_date + 6, 2); + tmp[2] = 0; + tm.tm_mday = atoi (tmp); + strncpy (tmp, capture_date + 9, 2); + tmp[2] = 0; + tm.tm_hour = atoi (tmp); + strncpy (tmp, capture_date + 11, 2); + tmp[2] = 0; + tm.tm_min = atoi (tmp); + strncpy (tmp, capture_date + 13, 2); + tmp[2] = 0; + tm.tm_sec = atoi (tmp); + oi->ModificationDate=mktime (&tm); + } + free(capture_date); +} + +/* Custom Type Value Assignement (without Length) macro frequently used below */ +#define CTVAL(type,func,target) { \ + *target = malloc(sizeof(type)); \ + **(type **)target = \ + func(data);\ +} + +static inline void +ptp_unpack_DPV (PTPParams *params, char* data, void** value, uint16_t datatype) +{ + + switch (datatype) { + case PTP_DTC_INT8: + CTVAL(int8_t,dtoh8a,value); + break; + case PTP_DTC_UINT8: + CTVAL(uint8_t,dtoh8a,value); + break; + case PTP_DTC_INT16: + CTVAL(int16_t,dtoh16a,value); + break; + case PTP_DTC_UINT16: + CTVAL(uint16_t,dtoh16a,value); + break; + case PTP_DTC_INT32: + CTVAL(int32_t,dtoh32a,value); + break; + case PTP_DTC_UINT32: + CTVAL(uint32_t,dtoh32a,value); + break; + /* XXX: other int types are unimplemented */ + /* XXX: int arrays are unimplemented also */ + case PTP_DTC_STR: + { + uint8_t len; + *(char **)&(*value)=ptp_unpack_string(params,data,0,&len); + break; + } + } +} + + +/* Device Property pack/unpack */ + +#define PTP_dpd_DevicePropertyCode 0 +#define PTP_dpd_DataType 2 +#define PTP_dpd_GetSet 4 +#define PTP_dpd_FactoryDefaultValue 5 + +/* Custom Type Value Assignement macro frequently used below */ +#define CTVA(type,func,target) { \ + target = malloc(sizeof(type)); \ + *(type *)target = \ + func(&data[PTP_dpd_FactoryDefaultValue+totallen]);\ + totallen+=sizeof(type); \ +} + +/* Many Custom Types Vale Assignement macro frequently used below */ + +#define MCTVA(type,func,target,n) { \ + uint16_t i; \ + for (i=0;iDevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]); + dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]); + dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]); + dpd->FactoryDefaultValue = NULL; + dpd->CurrentValue = NULL; + switch (dpd->DataType) { + case PTP_DTC_INT8: + CTVA(int8_t,dtoh8a,dpd->FactoryDefaultValue); + CTVA(int8_t,dtoh8a,dpd->CurrentValue); + break; + case PTP_DTC_UINT8: + CTVA(uint8_t,dtoh8a,dpd->FactoryDefaultValue); + CTVA(uint8_t,dtoh8a,dpd->CurrentValue); + break; + case PTP_DTC_INT16: + CTVA(int16_t,dtoh16a,dpd->FactoryDefaultValue); + CTVA(int16_t,dtoh16a,dpd->CurrentValue); + break; + case PTP_DTC_UINT16: + CTVA(uint16_t,dtoh16a,dpd->FactoryDefaultValue); + CTVA(uint16_t,dtoh16a,dpd->CurrentValue); + break; + case PTP_DTC_INT32: + CTVA(int32_t,dtoh32a,dpd->FactoryDefaultValue); + CTVA(int32_t,dtoh32a,dpd->CurrentValue); + break; + case PTP_DTC_UINT32: + CTVA(uint32_t,dtoh32a,dpd->FactoryDefaultValue); + CTVA(uint32_t,dtoh32a,dpd->CurrentValue); + break; + /* XXX: other int types are unimplemented */ + /* XXX: int arrays are unimplemented also */ + case PTP_DTC_STR: + dpd->FactoryDefaultValue = (void *)ptp_unpack_string + (params,data,PTP_dpd_FactoryDefaultValue,&len); + totallen=len*2+1; + dpd->CurrentValue = (void *)ptp_unpack_string + (params, data, PTP_dpd_FactoryDefaultValue + + totallen, &len); + totallen+=len*2+1; + break; + } + /* if totallen==0 then Data Type format is not supported by this + code or the Data Type is a string (with two empty strings as + values). In both cases Form Flag should be set to 0x00 and FORM is + not present. */ + dpd->FormFlag=PTP_DPFF_None; + if (totallen==0) return; + + dpd->FormFlag=dtoh8a(&data[PTP_dpd_FactoryDefaultValue+totallen]); + totallen+=sizeof(uint8_t); + switch (dpd->FormFlag) { + case PTP_DPFF_Range: + switch (dpd->DataType) { + case PTP_DTC_INT8: + CTVA(int8_t,dtoh8a,dpd->FORM.Range.MinimumValue); + CTVA(int8_t,dtoh8a,dpd->FORM.Range.MaximumValue); + CTVA(int8_t,dtoh8a,dpd->FORM.Range.StepSize); + break; + case PTP_DTC_UINT8: + CTVA(uint8_t,dtoh8a,dpd->FORM.Range.MinimumValue); + CTVA(uint8_t,dtoh8a,dpd->FORM.Range.MaximumValue); + CTVA(uint8_t,dtoh8a,dpd->FORM.Range.StepSize); + break; + case PTP_DTC_INT16: + CTVA(int16_t,dtoh16a,dpd->FORM.Range.MinimumValue); + CTVA(int16_t,dtoh16a,dpd->FORM.Range.MaximumValue); + CTVA(int16_t,dtoh16a,dpd->FORM.Range.StepSize); + break; + case PTP_DTC_UINT16: + CTVA(uint16_t,dtoh16a,dpd->FORM.Range.MinimumValue); + CTVA(uint16_t,dtoh16a,dpd->FORM.Range.MaximumValue); + CTVA(uint16_t,dtoh16a,dpd->FORM.Range.StepSize); + break; + case PTP_DTC_INT32: + CTVA(int32_t,dtoh32a,dpd->FORM.Range.MinimumValue); + CTVA(int32_t,dtoh32a,dpd->FORM.Range.MaximumValue); + CTVA(int32_t,dtoh32a,dpd->FORM.Range.StepSize); + break; + case PTP_DTC_UINT32: + CTVA(uint32_t,dtoh32a,dpd->FORM.Range.MinimumValue); + CTVA(uint32_t,dtoh32a,dpd->FORM.Range.MaximumValue); + CTVA(uint32_t,dtoh32a,dpd->FORM.Range.StepSize); + break; + /* XXX: other int types are unimplemented */ + /* XXX: int arrays are unimplemented also */ + /* XXX: does it make any sense: "a range of strings"? */ + } + break; + case PTP_DPFF_Enumeration: +#define N dpd->FORM.Enum.NumberOfValues + N = dtoh16a(&data[PTP_dpd_FactoryDefaultValue+totallen]); + totallen+=sizeof(uint16_t); + dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(void *)); + switch (dpd->DataType) { + case PTP_DTC_INT8: + MCTVA(int8_t,dtoh8a,dpd->FORM.Enum.SupportedValue,N); + break; + case PTP_DTC_UINT8: + MCTVA(uint8_t,dtoh8a,dpd->FORM.Enum.SupportedValue,N); + break; + case PTP_DTC_INT16: + MCTVA(int16_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N); + break; + case PTP_DTC_UINT16: + MCTVA(uint16_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N); + break; + case PTP_DTC_INT32: + MCTVA(int32_t,dtoh32a,dpd->FORM.Enum.SupportedValue,N); + break; + case PTP_DTC_UINT32: + MCTVA(uint32_t,dtoh32a,dpd->FORM.Enum.SupportedValue,N); + break; + case PTP_DTC_STR: + { + int i; + for(i=0;iFORM.Enum.SupportedValue[i]= + ptp_unpack_string + (params,data,PTP_dpd_FactoryDefaultValue + +totallen,&len); + totallen+=len*2+1; + } + } + break; + } + } +} + +static inline uint32_t +ptp_pack_DPV (PTPParams *params, void* value, char** dpvptr, uint16_t datatype) +{ + char* dpv=NULL; + uint32_t size=0; + + switch (datatype) { + case PTP_DTC_INT8: + size=sizeof(int8_t); + dpv=malloc(size); + htod8a(dpv,*(int8_t*)value); + break; + case PTP_DTC_UINT8: + size=sizeof(uint8_t); + dpv=malloc(size); + htod8a(dpv,*(uint8_t*)value); + break; + case PTP_DTC_INT16: + size=sizeof(int16_t); + dpv=malloc(size); + htod16a(dpv,*(int16_t*)value); + break; + case PTP_DTC_UINT16: + size=sizeof(uint16_t); + dpv=malloc(size); + htod16a(dpv,*(uint16_t*)value); + break; + case PTP_DTC_INT32: + size=sizeof(int32_t); + dpv=malloc(size); + htod32a(dpv,*(int32_t*)value); + break; + case PTP_DTC_UINT32: + size=sizeof(uint32_t); + dpv=malloc(size); + htod32a(dpv,*(uint32_t*)value); + break; + /* XXX: other int types are unimplemented */ + /* XXX: int arrays are unimplemented also */ + case PTP_DTC_STR: + { + uint8_t len; + size=strlen((char*)value)*2+3; + dpv=malloc(size); + memset(dpv,0,size); + ptp_pack_string(params, (char *)value, dpv, 0, &len); + } + break; + } + *dpvptr=dpv; + return size; +} + + +/* + PTP USB Event container unpack + Copyright (c) 2003 Nikolai Kopanygin +*/ + +#define PTP_ec_Length 0 +#define PTP_ec_Type 4 +#define PTP_ec_Code 6 +#define PTP_ec_TransId 8 +#define PTP_ec_Param1 12 +#define PTP_ec_Param2 16 +#define PTP_ec_Param3 20 + +static inline void +ptp_unpack_EC (PTPParams *params, char* data, PTPUSBEventContainer *ec) +{ + if (data==NULL) + return; + ec->length=dtoh32a(&data[PTP_ec_Length]); + ec->type=dtoh16a(&data[PTP_ec_Type]); + ec->code=dtoh16a(&data[PTP_ec_Code]); + ec->trans_id=dtoh32a(&data[PTP_ec_TransId]); + if (ec->length>=(PTP_ec_Param1+4)) + ec->param1=dtoh32a(&data[PTP_ec_Param1]); + else + ec->param1=0; + if (ec->length>=(PTP_ec_Param2+4)) + ec->param2=dtoh32a(&data[PTP_ec_Param2]); + else + ec->param2=0; + if (ec->length>=(PTP_ec_Param3+4)) + ec->param3=dtoh32a(&data[PTP_ec_Param3]); + else + ec->param3=0; +} + +/* + PTP Canon Folder Entry unpack + Copyright (c) 2003 Nikolai Kopanygin +*/ +#define PTP_cfe_ObjectHandle 0 +#define PTP_cfe_ObjectFormatCode 4 +#define PTP_cfe_Flags 6 +#define PTP_cfe_ObjectSize 7 +#define PTP_cfe_Time 11 +#define PTP_cfe_Filename 15 + +static inline void +ptp_unpack_Canon_FE (PTPParams *params, char* data, PTPCANONFolderEntry *fe) +{ + int i; + if (data==NULL) + return; + fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]); + fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]); + fe->Flags=dtoh8a(&data[PTP_cfe_Flags]); + fe->ObjectSize=dtoh32a(&data[PTP_cfe_ObjectSize]); + fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]); + for (i=0; iFilename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]); +} + +#define PTP_NIKON_ec_Num 0 +#define PTP_NIKON_ec_Code 2 +#define PTP_NIKON_ec_Param1 4 + +static inline void +ptp_nikon_unpack_EC (PTPParams *params, char *evdata, PTPUSBEventContainer** event, uint16_t* evnum) +{ + int i=0; + PTPUSBEventContainer *events; + + *evnum=dtoh16a(&evdata[PTP_NIKON_ec_Num]); + events=calloc(*evnum, sizeof(PTPUSBEventContainer)); + + *event=events; + while (i<*evnum) { + events->code = dtoh16a(&evdata[PTP_NIKON_ec_Code+ + ((sizeof(uint16_t)+sizeof(uint32_t))*i)]); + events->param1 = dtoh32a(&evdata[PTP_NIKON_ec_Param1+ + ((sizeof(uint16_t)+sizeof(uint32_t))*i)]); + events++; + i++; + } +} + diff --git a/tools/ptpcam/ptp.c b/tools/ptpcam/ptp.c new file mode 100644 index 00000000..e3af82e8 --- /dev/null +++ b/tools/ptpcam/ptp.c @@ -0,0 +1,2011 @@ +/* ptp.c + * + * Copyright (C) 2001-2005 Mariusz Woloszyn + * + * This file is part of libptp2. + * + * libptp2 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. + * + * libptp2 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 libptp2; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "ptp.h" + +#include +#include +#include +#include + +#ifdef WIN32 +#include +#endif + +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + +#define CHECK_PTP_RC(result) {uint16_t r=(result); if (r!=PTP_RC_OK) return r;} + +#define PTP_CNT_INIT(cnt) {memset(&cnt,0,sizeof(cnt));} + +static void +ptp_debug (PTPParams *params, const char *format, ...) +{ + va_list args; + + va_start (args, format); + if (params->debug_func!=NULL) + params->debug_func (params->data, format, args); + else + { + vfprintf (stderr, format, args); + fprintf (stderr,"\n"); + fflush (stderr); + } + va_end (args); +} + +static void +ptp_error (PTPParams *params, const char *format, ...) +{ + va_list args; + + va_start (args, format); + if (params->error_func!=NULL) + params->error_func (params->data, format, args); + else + { + vfprintf (stderr, format, args); + fprintf (stderr,"\n"); + fflush (stderr); + } + va_end (args); +} + +/* Pack / unpack functions */ + +#include "ptp-pack.c" + +/* send / receive functions */ + +uint16_t +ptp_usb_sendreq (PTPParams* params, PTPContainer* req) +{ + static uint16_t ret; + static PTPUSBBulkContainer usbreq; + + PTP_CNT_INIT(usbreq); + /* build appropriate USB container */ + usbreq.length=htod32(PTP_USB_BULK_REQ_LEN- + (sizeof(uint32_t)*(5-req->Nparam))); + usbreq.type=htod16(PTP_USB_CONTAINER_COMMAND); + usbreq.code=htod16(req->Code); + usbreq.trans_id=htod32(req->Transaction_ID); + usbreq.payload.params.param1=htod32(req->Param1); + usbreq.payload.params.param2=htod32(req->Param2); + usbreq.payload.params.param3=htod32(req->Param3); + usbreq.payload.params.param4=htod32(req->Param4); + usbreq.payload.params.param5=htod32(req->Param5); + /* send it to responder */ + ret=params->write_func((unsigned char *)&usbreq, + PTP_USB_BULK_REQ_LEN-(sizeof(uint32_t)*(5-req->Nparam)), + params->data); + if (ret!=PTP_RC_OK) { + ret = PTP_ERROR_IO; +/* ptp_error (params, + "PTP: request code 0x%04x sending req error 0x%04x", + req->Code,ret); */ + } + return ret; +} + +uint16_t +ptp_usb_senddata (PTPParams* params, PTPContainer* ptp, + unsigned char *data, unsigned int size) +{ + static uint16_t ret; + static PTPUSBBulkContainer usbdata; + + /* build appropriate USB container */ + usbdata.length=htod32(PTP_USB_BULK_HDR_LEN+size); + usbdata.type=htod16(PTP_USB_CONTAINER_DATA); + usbdata.code=htod16(ptp->Code); + usbdata.trans_id=htod32(ptp->Transaction_ID); + memcpy(usbdata.payload.data,data, + (sizewrite_func((unsigned char *)&usbdata, PTP_USB_BULK_HDR_LEN+ + ((sizedata); + if (ret!=PTP_RC_OK) { + ret = PTP_ERROR_IO; +/* ptp_error (params, + "PTP: request code 0x%04x sending data error 0x%04x", + ptp->Code,ret);*/ + return ret; + } + if (size<=PTP_USB_BULK_PAYLOAD_LEN) return ret; + /* if everything OK send the rest */ + ret=params->write_func (data+PTP_USB_BULK_PAYLOAD_LEN, + size-PTP_USB_BULK_PAYLOAD_LEN, params->data); + if (ret!=PTP_RC_OK) { + ret = PTP_ERROR_IO; +/* ptp_error (params, + "PTP: request code 0x%04x sending data error 0x%04x", + ptp->Code,ret); */ + } + return ret; +} + +uint16_t +ptp_usb_getdata (PTPParams* params, PTPContainer* ptp, + unsigned char **data) +{ + static uint16_t ret; + static PTPUSBBulkContainer usbdata; + + PTP_CNT_INIT(usbdata); +#if 0 + if (*data!=NULL) return PTP_ERROR_BADPARAM; +#endif + do { + static uint32_t len; + /* read first(?) part of data */ + ret=params->read_func((unsigned char *)&usbdata, + sizeof(usbdata), params->data); + if (ret!=PTP_RC_OK) { + ret = PTP_ERROR_IO; + break; + } else + if (dtoh16(usbdata.type)!=PTP_USB_CONTAINER_DATA) { + ret = PTP_ERROR_DATA_EXPECTED; + break; + } else + if (dtoh16(usbdata.code)!=ptp->Code) { + ret = dtoh16(usbdata.code); + break; + } + /* evaluate data length */ + len=dtoh32(usbdata.length)-PTP_USB_BULK_HDR_LEN; + /* allocate memory for data if not allocated already */ + if (*data==NULL) *data=calloc(1,len); + /* copy first part of data to 'data' */ + memcpy(*data,usbdata.payload.data, + PTP_USB_BULK_PAYLOAD_LENread_func(((unsigned char *)(*data))+ + PTP_USB_BULK_PAYLOAD_LEN, + len-PTP_USB_BULK_PAYLOAD_LEN, + params->data); + if (ret!=PTP_RC_OK) { + ret = PTP_ERROR_IO; + break; + } + } while (0); +/* + if (ret!=PTP_RC_OK) { + ptp_error (params, + "PTP: request code 0x%04x getting data error 0x%04x", + ptp->Code, ret); + }*/ + return ret; +} + +uint16_t +ptp_usb_getresp (PTPParams* params, PTPContainer* resp) +{ + static uint16_t ret; + static PTPUSBBulkContainer usbresp; + + PTP_CNT_INIT(usbresp); + /* read response, it should never be longer than sizeof(usbresp) */ + ret=params->read_func((unsigned char *)&usbresp, + sizeof(usbresp), params->data); + + if (ret!=PTP_RC_OK) { + ret = PTP_ERROR_IO; + } else + if (dtoh16(usbresp.type)!=PTP_USB_CONTAINER_RESPONSE) { + ret = PTP_ERROR_RESP_EXPECTED; + } else + if (dtoh16(usbresp.code)!=resp->Code) { + ret = dtoh16(usbresp.code); + } + if (ret!=PTP_RC_OK) { +/* ptp_error (params, + "PTP: request code 0x%04x getting resp error 0x%04x", + resp->Code, ret);*/ + return ret; + } + /* build an appropriate PTPContainer */ + resp->Code=dtoh16(usbresp.code); + resp->SessionID=params->session_id; + resp->Transaction_ID=dtoh32(usbresp.trans_id); + resp->Param1=dtoh32(usbresp.payload.params.param1); + resp->Param2=dtoh32(usbresp.payload.params.param2); + resp->Param3=dtoh32(usbresp.payload.params.param3); + resp->Param4=dtoh32(usbresp.payload.params.param4); + resp->Param5=dtoh32(usbresp.payload.params.param5); + return ret; +} + +/* major PTP functions */ + +/* Transaction data phase description */ +#define PTP_DP_NODATA 0x0000 /* no data phase */ +#define PTP_DP_SENDDATA 0x0001 /* sending data */ +#define PTP_DP_GETDATA 0x0002 /* receiving data */ +#define PTP_DP_DATA_MASK 0x00ff /* data phase mask */ + +/* Number of PTP Request phase parameters */ +#define PTP_RQ_PARAM0 0x0000 /* zero parameters */ +#define PTP_RQ_PARAM1 0x0100 /* one parameter */ +#define PTP_RQ_PARAM2 0x0200 /* two parameters */ +#define PTP_RQ_PARAM3 0x0300 /* three parameters */ +#define PTP_RQ_PARAM4 0x0400 /* four parameters */ +#define PTP_RQ_PARAM5 0x0500 /* five parameters */ + +/** + * ptp_transaction: + * params: PTPParams* + * PTPContainer* ptp - general ptp container + * uint16_t flags - lower 8 bits - data phase description + * unsigned int sendlen - senddata phase data length + * char** data - send or receive data buffer pointer + * + * Performs PTP transaction. ptp is a PTPContainer with appropriate fields + * filled in (i.e. operation code and parameters). It's up to caller to do + * so. + * The flags decide whether the transaction has a data phase and what is its + * direction (send or receive). + * If transaction is sending data the sendlen should contain its length in + * bytes, otherwise it's ignored. + * The data should contain an address of a pointer to data going to be sent + * or is filled with such a pointer address if data are received depending + * od dataphase direction (send or received) or is beeing ignored (no + * dataphase). + * The memory for a pointer should be preserved by the caller, if data are + * beeing retreived the appropriate amount of memory is beeing allocated + * (the caller should handle that!). + * + * Return values: Some PTP_RC_* code. + * Upon success PTPContainer* ptp contains PTP Response Phase container with + * all fields filled in. + **/ +static uint16_t +ptp_transaction (PTPParams* params, PTPContainer* ptp, + uint16_t flags, unsigned int sendlen, char** data) +{ + if ((params==NULL) || (ptp==NULL)) + return PTP_ERROR_BADPARAM; + + ptp->Transaction_ID=params->transaction_id++; + ptp->SessionID=params->session_id; + /* send request */ + CHECK_PTP_RC(params->sendreq_func (params, ptp)); + /* is there a dataphase? */ + switch (flags&PTP_DP_DATA_MASK) { + case PTP_DP_SENDDATA: + CHECK_PTP_RC(params->senddata_func(params, ptp, + (unsigned char*)*data, sendlen)); + break; + case PTP_DP_GETDATA: + CHECK_PTP_RC(params->getdata_func(params, ptp, + (unsigned char**)data)); + break; + case PTP_DP_NODATA: + break; + default: + return PTP_ERROR_BADPARAM; + } + /* get response */ + CHECK_PTP_RC(params->getresp_func(params, ptp)); + return PTP_RC_OK; +} + +/* Enets handling functions */ + +/* PTP Events wait for or check mode */ +#define PTP_EVENT_CHECK 0x0000 /* waits for */ +#define PTP_EVENT_CHECK_FAST 0x0001 /* checks */ + +#define CHECK_INT(usbevent, size) { \ + switch(wait) { \ + case PTP_EVENT_CHECK: \ + result+=params->check_int_func((unsigned char*)&usbevent+result, \ + size-result, params->data); \ + break; \ + case PTP_EVENT_CHECK_FAST: \ + result+=params->check_int_fast_func((unsigned char*)&usbevent+result, \ + size-result, params->data); \ + break; \ + default: \ + return PTP_ERROR_BADPARAM; \ + }\ + } + + +static inline uint16_t +ptp_usb_event (PTPParams* params, PTPContainer* event, int wait) +{ + int result=0, size=0; + static PTPUSBEventContainer usbevent; + + PTP_CNT_INIT(usbevent); + + if ((params==NULL) || (event==NULL)) + return PTP_ERROR_BADPARAM; + + + CHECK_INT(usbevent, PTP_USB_INT_PACKET_LEN); + if (result<0) + return PTP_ERROR_IO; + size=dtoh32(usbevent.length); + while (resultCode=dtoh16(usbevent.code); + event->SessionID=params->session_id; + event->Transaction_ID=dtoh32(usbevent.trans_id); + event->Param1=dtoh32(usbevent.param1); + event->Param2=dtoh32(usbevent.param2); + event->Param3=dtoh32(usbevent.param3); + + return PTP_RC_OK; +} + +uint16_t +ptp_usb_event_check (PTPParams* params, PTPContainer* event) { + + ptp_debug(params,"PTP: Checking for Event"); + return ptp_usb_event (params, event, PTP_EVENT_CHECK_FAST); +} + +uint16_t +ptp_usb_event_wait (PTPParams* params, PTPContainer* event) { + + ptp_debug(params,"PTP: Waiting for Event"); + return ptp_usb_event (params, event, PTP_EVENT_CHECK); +} + +/** + * PTP operation functions + * + * all ptp_ functions should take integer parameters + * in host byte order! + **/ + + +/** + * ptp_getdeviceinfo: + * params: PTPParams* + * + * Gets device info dataset and fills deviceinfo structure. + * + * Return values: Some PTP_RC_* code. + **/ +uint16_t +ptp_getdeviceinfo (PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + char* di=NULL; + + ptp_debug(params,"PTP: Obtaining DeviceInfo"); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetDeviceInfo; + ptp.Nparam=0; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &di); + if (ret == PTP_RC_OK) ptp_unpack_DI(params, di, deviceinfo); + free(di); + return ret; +} + + +/** + * ptp_opensession: + * params: PTPParams* + * session - session number + * + * Establishes a new session. + * + * Return values: Some PTP_RC_* code. + **/ +uint16_t +ptp_opensession (PTPParams* params, uint32_t session) +{ + uint16_t ret; + PTPContainer ptp; + + ptp_debug(params,"PTP: Opening session 0x%08x", session); + + /* SessonID field of the operation dataset should always + be set to 0 for OpenSession request! */ + params->session_id=0x00000000; + /* TransactionID should be set to 0 also! */ + params->transaction_id=0x0000000; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_OpenSession; + ptp.Param1=session; + ptp.Nparam=1; + ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); + /* now set the global session id to current session number */ + params->session_id=session; + return ret; +} + +/** + * ptp_closesession: + * params: PTPParams* + * + * Closes session. + * + * Return values: Some PTP_RC_* code. + **/ +uint16_t +ptp_closesession (PTPParams* params) +{ + PTPContainer ptp; + + ptp_debug(params,"PTP: Closing session"); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CloseSession; + ptp.Nparam=0; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +/** + * ptp_getststorageids: + * params: PTPParams* + * + * Gets array of StorageiDs and fills the storageids structure. + * + * Return values: Some PTP_RC_* code. + **/ +uint16_t +ptp_getstorageids (PTPParams* params, PTPStorageIDs* storageids) +{ + uint16_t ret; + PTPContainer ptp; + char* sids=NULL; + + ptp_debug(params,"PTP: Obtaining StorageIDs"); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetStorageIDs; + ptp.Nparam=0; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &sids); + if (ret == PTP_RC_OK) ptp_unpack_SIDs(params, sids, storageids); + free(sids); + return ret; +} + +/** + * ptp_getststorageinfo: + * params: PTPParams* + * storageid - StorageID + * + * Gets StorageInfo dataset of desired storage and fills storageinfo + * structure. + * + * Return values: Some PTP_RC_* code. + **/ +uint16_t +ptp_getstorageinfo (PTPParams* params, uint32_t storageid, + PTPStorageInfo* storageinfo) +{ + uint16_t ret; + PTPContainer ptp; + char* si=NULL; + + ptp_debug(params,"PTP: Obtaining StorageInfo for storage 0x%08x", + storageid); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetStorageInfo; + ptp.Param1=storageid; + ptp.Nparam=1; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &si); + if (ret == PTP_RC_OK) ptp_unpack_SI(params, si, storageinfo); + free(si); + return ret; +} + +/** + * ptp_getobjecthandles: + * params: PTPParams* + * storage - StorageID + * objectformatcode - ObjectFormatCode (optional) + * associationOH - ObjectHandle of Association for + * wich a list of children is desired + * (optional) + * objecthandles - pointer to structute + * + * Fills objecthandles with structure returned by device. + * + * Return values: Some PTP_RC_* code. + **/ +uint16_t +ptp_getobjecthandles (PTPParams* params, uint32_t storage, + uint32_t objectformatcode, uint32_t associationOH, + PTPObjectHandles* objecthandles) +{ + uint16_t ret; + PTPContainer ptp; + char* oh=NULL; + + ptp_debug(params,"PTP: Obtaining ObjectHandles"); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetObjectHandles; + ptp.Param1=storage; + ptp.Param2=objectformatcode; + ptp.Param3=associationOH; + ptp.Nparam=3; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &oh); + if (ret == PTP_RC_OK) ptp_unpack_OH(params, oh, objecthandles); + free(oh); + return ret; +} + +/** + * ptp_ptp_getobjectinfo: + * params: PTPParams* + * handle - object Handler + * objectinfo - pointer to PTPObjectInfo structure + * + * Fills objectinfo structure with appropriate data of object given by + * hander. + * + * Return values: Some PTP_RC_* code. + **/ +uint16_t +ptp_getobjectinfo (PTPParams* params, uint32_t handle, + PTPObjectInfo* objectinfo) +{ + uint16_t ret; + PTPContainer ptp; + char* oi=NULL; + + ptp_debug(params,"PTP: Obtaining ObjectInfo for object 0x%08x", + handle); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetObjectInfo; + ptp.Param1=handle; + ptp.Nparam=1; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &oi); + if (ret == PTP_RC_OK) ptp_unpack_OI(params, oi, objectinfo); + free(oi); + return ret; +} + +uint16_t +ptp_getobject (PTPParams* params, uint32_t handle, char** object) +{ + PTPContainer ptp; + + ptp_debug(params,"PTP: Downloading Object 0x%08x", + handle); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetObject; + ptp.Param1=handle; + ptp.Nparam=1; + return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object); +} + +uint16_t +ptp_getthumb (PTPParams* params, uint32_t handle, char** object) +{ + PTPContainer ptp; + + ptp_debug(params,"PTP: Downloading Thumbnail from object 0x%08x", + handle); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetThumb; + ptp.Param1=handle; + ptp.Nparam=1; + return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object); +} + +/** + * ptp_deleteobject: + * params: PTPParams* + * handle - object handle + * ofc - object format code (optional) + * + * Deletes desired objects. + * + * Return values: Some PTP_RC_* code. + **/ +uint16_t +ptp_deleteobject (PTPParams* params, uint32_t handle, + uint32_t ofc) +{ + PTPContainer ptp; + + ptp_debug(params,"PTP: Deleting Object 0x%08x", handle); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_DeleteObject; + ptp.Param1=handle; + ptp.Param2=ofc; + ptp.Nparam=2; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +/** + * ptp_sendobjectinfo: + * params: PTPParams* + * uint32_t* store - destination StorageID on Responder + * uint32_t* parenthandle - Parent ObjectHandle on responder + * uint32_t* handle - see Return values + * PTPObjectInfo* objectinfo- ObjectInfo that is to be sent + * + * Sends ObjectInfo of file that is to be sent via SendFileObject. + * + * Return values: Some PTP_RC_* code. + * Upon success : uint32_t* store - Responder StorageID in which + * object will be stored + * uint32_t* parenthandle- Responder Parent ObjectHandle + * in which the object will be stored + * uint32_t* handle - Responder's reserved ObjectHandle + * for the incoming object + **/ +uint16_t +ptp_sendobjectinfo (PTPParams* params, uint32_t* store, + uint32_t* parenthandle, uint32_t* handle, + PTPObjectInfo* objectinfo) +{ + uint16_t ret; + PTPContainer ptp; + char* oidata=NULL; + uint32_t size; + + ptp_debug(params,"PTP: Sending ObjectInfo; parent object 0x%08x", + *parenthandle); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_SendObjectInfo; + ptp.Param1=*store; + ptp.Param2=*parenthandle; + ptp.Nparam=2; + + size=ptp_pack_OI(params, objectinfo, &oidata); + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &oidata); + free(oidata); + *store=ptp.Param1; + *parenthandle=ptp.Param2; + *handle=ptp.Param3; + return ret; +} + +/** + * ptp_sendobject: + * params: PTPParams* + * char* object - contains the object that is to be sent + * uint32_t size - object size + * + * Sends object to Responder. + * + * Return values: Some PTP_RC_* code. + * + */ +uint16_t +ptp_sendobject (PTPParams* params, char* object, uint32_t size) +{ + PTPContainer ptp; + + ptp_debug(params,"PTP: Sending Object of size %u", size); + + PTP_CNT_INIT(ptp); + + ptp.Code=PTP_OC_SendObject; + ptp.Nparam=0; + + return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &object); +} + + +/** + * ptp_initiatecapture: + * params: PTPParams* + * storageid - destination StorageID on Responder + * ofc - object format code + * + * Causes device to initiate the capture of one or more new data objects + * according to its current device properties, storing the data into store + * indicated by storageid. If storageid is 0x00000000, the object(s) will + * be stored in a store that is determined by the capturing device. + * The capturing of new data objects is an asynchronous operation. + * + * Return values: Some PTP_RC_* code. + **/ + +uint16_t +ptp_initiatecapture (PTPParams* params, uint32_t storageid, + uint32_t ofc) +{ + PTPContainer ptp; + + ptp_debug(params,"PTP: Initiating Capture"); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_InitiateCapture; + ptp.Param1=storageid; + ptp.Param2=ofc; + ptp.Nparam=2; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +uint16_t +ptp_getdevicepropdesc (PTPParams* params, uint16_t propcode, + PTPDevicePropDesc* devicepropertydesc) +{ + PTPContainer ptp; + uint16_t ret; + char* dpd=NULL; + + ptp_debug(params, "PTP: Obtaining Device Property Description for property 0x%04x", propcode); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetDevicePropDesc; + ptp.Param1=propcode; + ptp.Nparam=1; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpd); + if (ret == PTP_RC_OK) ptp_unpack_DPD(params, dpd, devicepropertydesc); + free(dpd); + return ret; +} + + +uint16_t +ptp_getdevicepropvalue (PTPParams* params, uint16_t propcode, + void** value, uint16_t datatype) +{ + PTPContainer ptp; + uint16_t ret; + char* dpv=NULL; + + ptp_debug(params, "PTP: Obtaining Device Property Value for property 0x%04x", propcode); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_GetDevicePropValue; + ptp.Param1=propcode; + ptp.Nparam=1; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpv); + if (ret == PTP_RC_OK) ptp_unpack_DPV(params, dpv, value, datatype); + free(dpv); + return ret; +} + +uint16_t +ptp_setdevicepropvalue (PTPParams* params, uint16_t propcode, + void* value, uint16_t datatype) +{ + PTPContainer ptp; + uint16_t ret; + uint32_t size; + char* dpv=NULL; + + ptp_debug(params, "PTP: Setting Device Property Value for property 0x%04x", propcode); + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_SetDevicePropValue; + ptp.Param1=propcode; + ptp.Nparam=1; + size=ptp_pack_DPV(params, value, &dpv, datatype); + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &dpv); + free(dpv); + return ret; +} + +/** + * ptp_ek_sendfileobjectinfo: + * params: PTPParams* + * uint32_t* store - destination StorageID on Responder + * uint32_t* parenthandle - Parent ObjectHandle on responder + * uint32_t* handle - see Return values + * PTPObjectInfo* objectinfo- ObjectInfo that is to be sent + * + * Sends ObjectInfo of file that is to be sent via SendFileObject. + * + * Return values: Some PTP_RC_* code. + * Upon success : uint32_t* store - Responder StorageID in which + * object will be stored + * uint32_t* parenthandle- Responder Parent ObjectHandle + * in which the object will be stored + * uint32_t* handle - Responder's reserved ObjectHandle + * for the incoming object + **/ +uint16_t +ptp_ek_sendfileobjectinfo (PTPParams* params, uint32_t* store, + uint32_t* parenthandle, uint32_t* handle, + PTPObjectInfo* objectinfo) +{ + uint16_t ret; + PTPContainer ptp; + char* oidata=NULL; + uint32_t size; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_EK_SendFileObjectInfo; + ptp.Param1=*store; + ptp.Param2=*parenthandle; + ptp.Nparam=2; + + size=ptp_pack_OI(params, objectinfo, &oidata); + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &oidata); + free(oidata); + *store=ptp.Param1; + *parenthandle=ptp.Param2; + *handle=ptp.Param3; + return ret; +} + +/** + * ptp_ek_sendfileobject: + * params: PTPParams* + * char* object - contains the object that is to be sent + * uint32_t size - object size + * + * Sends object to Responder. + * + * Return values: Some PTP_RC_* code. + * + */ +uint16_t +ptp_ek_sendfileobject (PTPParams* params, char* object, uint32_t size) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_EK_SendFileObject; + ptp.Nparam=0; + + return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &object); +} + +/************************************************************************* + * + * Canon PTP extensions support + * + * (C) Nikolai Kopanygin 2003 + * + *************************************************************************/ + + +/** + * ptp_canon_getobjectsize: + * params: PTPParams* + * uint32_t handle - ObjectHandle + * uint32_t p2 - Yet unknown parameter, + * value 0 works. + * + * Gets form the responder the size of the specified object. + * + * Return values: Some PTP_RC_* code. + * Upon success : uint32_t* size - The object size + * uint32_t rp2 - Yet unknown parameter + * + **/ +uint16_t +ptp_canon_getobjectsize (PTPParams* params, uint32_t handle, uint32_t p2, + uint32_t* size, uint32_t* rp2) +{ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_GetObjectSize; + ptp.Param1=handle; + ptp.Param2=p2; + ptp.Nparam=2; + ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); + *size=ptp.Param1; + *rp2=ptp.Param2; + return ret; +} + +/** + * ptp_canon_startshootingmode: + * params: PTPParams* + * + * Starts shooting session. It emits a StorageInfoChanged + * event via the interrupt pipe and pushes the StorageInfoChanged + * and CANON_CameraModeChange events onto the event stack + * (see operation PTP_OC_CANON_CheckEvent). + * + * Return values: Some PTP_RC_* code. + * + **/ +uint16_t +ptp_canon_startshootingmode (PTPParams* params) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_StartShootingMode; + ptp.Nparam=0; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +/** + * ptp_canon_endshootingmode: + * params: PTPParams* + * + * This operation is observed after pressing the Disconnect + * button on the Remote Capture app. It emits a StorageInfoChanged + * event via the interrupt pipe and pushes the StorageInfoChanged + * and CANON_CameraModeChange events onto the event stack + * (see operation PTP_OC_CANON_CheckEvent). + * + * Return values: Some PTP_RC_* code. + * + **/ +uint16_t +ptp_canon_endshootingmode (PTPParams* params) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_EndShootingMode; + ptp.Nparam=0; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +/** + * ptp_canon_viewfinderon: + * params: PTPParams* + * + * Prior to start reading viewfinder images, one must call this operation. + * Supposedly, this operation affects the value of the CANON_ViewfinderMode + * property. + * + * Return values: Some PTP_RC_* code. + * + **/ +uint16_t +ptp_canon_viewfinderon (PTPParams* params) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_ViewfinderOn; + ptp.Nparam=0; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +/** + * ptp_canon_viewfinderoff: + * params: PTPParams* + * + * Before changing the shooting mode, or when one doesn't need to read + * viewfinder images any more, one must call this operation. + * Supposedly, this operation affects the value of the CANON_ViewfinderMode + * property. + * + * Return values: Some PTP_RC_* code. + * + **/ +uint16_t +ptp_canon_viewfinderoff (PTPParams* params) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_ViewfinderOff; + ptp.Nparam=0; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +/** + * ptp_canon_reflectchanges: + * params: PTPParams* + * uint32_t p1 - Yet unknown parameter, + * value 7 works + * + * Make viewfinder reflect changes. + * There is a button for this operation in the Remote Capture app. + * What it does exactly I don't know. This operation is followed + * by the CANON_GetChanges(?) operation in the log. + * + * Return values: Some PTP_RC_* code. + * + **/ +uint16_t +ptp_canon_reflectchanges (PTPParams* params, uint32_t p1) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_ReflectChanges; + ptp.Param1=p1; + ptp.Nparam=1; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + + +/** + * ptp_canon_checkevent: + * params: PTPParams* + * + * The camera has a FIFO stack, in which it accumulates events. + * Partially these events are communicated also via the USB interrupt pipe + * according to the PTP USB specification, partially not. + * This operation returns from the device a block of data, empty, + * if the event stack is empty, or filled with an event's data otherwise. + * The event is removed from the stack in the latter case. + * The Remote Capture app sends this command to the camera all the time + * of connection, filling with it the gaps between other operations. + * + * Return values: Some PTP_RC_* code. + * Upon success : PTPUSBEventContainer* event - is filled with the event data + * if any + * int *isevent - returns 1 in case of event + * or 0 otherwise + **/ +uint16_t +ptp_canon_checkevent (PTPParams* params, PTPUSBEventContainer* event, int* isevent) +{ + uint16_t ret; + PTPContainer ptp; + char *evdata = NULL; + + *isevent=0; + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_CheckEvent; + ptp.Nparam=0; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &evdata); + if (evdata!=NULL) { + if (ret == PTP_RC_OK) { + ptp_unpack_EC(params, evdata, event); + *isevent=1; + } + free(evdata); + } + return ret; +} + + +/** + * ptp_canon_focuslock: + * + * This operation locks the focus. It is followed by the CANON_GetChanges(?) + * operation in the log. + * It affects the CANON_MacroMode property. + * + * params: PTPParams* + * + * Return values: Some PTP_RC_* code. + * + **/ +uint16_t +ptp_canon_focuslock (PTPParams* params) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_FocusLock; + ptp.Nparam=0; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +/** + * ptp_canon_focusunlock: + * + * This operation unlocks the focus. It is followed by the CANON_GetChanges(?) + * operation in the log. + * It sets the CANON_MacroMode property value to 1 (where it occurs in the log). + * + * params: PTPParams* + * + * Return values: Some PTP_RC_* code. + * + **/ +uint16_t +ptp_canon_focusunlock (PTPParams* params) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_FocusUnlock; + ptp.Nparam=0; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +/** + * ptp_canon_initiatecaptureinmemory: + * + * This operation starts the image capture according to the current camera + * settings. When the capture has happened, the camera emits a CaptureComplete + * event via the interrupt pipe and pushes the CANON_RequestObjectTransfer, + * CANON_DeviceInfoChanged and CaptureComplete events onto the event stack + * (see operation CANON_CheckEvent). From the CANON_RequestObjectTransfer + * event's parameter one can learn the just captured image's ObjectHandle. + * The image is stored in the camera's own RAM. + * On the next capture the image will be overwritten! + * + * params: PTPParams* + * + * Return values: Some PTP_RC_* code. + * + **/ +uint16_t +ptp_canon_initiatecaptureinmemory (PTPParams* params) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_InitiateCaptureInMemory; + ptp.Nparam=0; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +/** + * ptp_canon_getpartialobject: + * + * This operation is used to read from the device a data + * block of an object from a specified offset. + * + * params: PTPParams* + * uint32_t handle - the handle of the requested object + * uint32_t offset - the offset in bytes from the beginning of the object + * uint32_t size - the requested size of data block to read + * uint32_t pos - 1 for the first block, 2 - for a block in the middle, + * 3 - for the last block + * + * Return values: Some PTP_RC_* code. + * char **block - the pointer to the block of data read + * uint32_t* readnum - the number of bytes read + * + **/ +uint16_t +ptp_canon_getpartialobject (PTPParams* params, uint32_t handle, + uint32_t offset, uint32_t size, + uint32_t pos, char** block, + uint32_t* readnum) +{ + uint16_t ret; + PTPContainer ptp; + char *data=NULL; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_GetPartialObject; + ptp.Param1=handle; + ptp.Param2=offset; + ptp.Param3=size; + ptp.Param4=pos; + ptp.Nparam=4; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data); + if (ret==PTP_RC_OK) { + *block=data; + *readnum=ptp.Param1; + } + return ret; +} + +/** + * ptp_canon_getviewfinderimage: + * + * This operation can be used to read the image which is currently + * in the camera's viewfinder. The image size is 320x240, format is JPEG. + * Of course, prior to calling this operation, one must turn the viewfinder + * on with the CANON_ViewfinderOn command. + * Invoking this operation many times, one can get live video from the camera! + * + * params: PTPParams* + * + * Return values: Some PTP_RC_* code. + * char **image - the pointer to the read image + * unit32_t *size - the size of the image in bytes + * + **/ +uint16_t +ptp_canon_getviewfinderimage (PTPParams* params, char** image, uint32_t* size) +{ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_GetViewfinderImage; + ptp.Nparam=0; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, image); + if (ret==PTP_RC_OK) *size=ptp.Param1; + return ret; +} + +/** + * ptp_canon_getchanges: + * + * This is an interesting operation, about the effect of which I am not sure. + * This command is called every time when a device property has been changed + * with the SetDevicePropValue operation, and after some other operations. + * This operation reads the array of Device Properties which have been changed + * by the previous operation. + * Probably, this operation is even required to make those changes work. + * + * params: PTPParams* + * + * Return values: Some PTP_RC_* code. + * uint16_t** props - the pointer to the array of changed properties + * uint32_t* propnum - the number of elements in the *props array + * + **/ +uint16_t +ptp_canon_getchanges (PTPParams* params, uint16_t** props, uint32_t* propnum) +{ + uint16_t ret; + PTPContainer ptp; + char* data=NULL; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_GetChanges; + ptp.Nparam=0; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data); + if (ret == PTP_RC_OK) + *propnum=ptp_unpack_uint16_t_array(params,data,0,props); + free(data); + return ret; +} + +/** + * ptp_canon_getfolderentries: + * + * This command reads a specified object's record in a device's filesystem, + * or the records of all objects belonging to a specified folder (association). + * + * params: PTPParams* + * uint32_t store - StorageID, + * uint32_t p2 - Yet unknown (0 value works OK) + * uint32_t parent - Parent Object Handle + * # If Parent Object Handle is 0xffffffff, + * # the Parent Object is the top level folder. + * uint32_t handle - Object Handle + * # If Object Handle is 0, the records of all objects + * # belonging to the Parent Object are read. + * # If Object Handle is not 0, only the record of this + * # Object is read. + * + * Return values: Some PTP_RC_* code. + * PTPCANONFolderEntry** entries - the pointer to the folder entry array + * uint32_t* entnum - the number of elements of the array + * + **/ +uint16_t +ptp_canon_getfolderentries (PTPParams* params, uint32_t store, uint32_t p2, + uint32_t parent, uint32_t handle, + PTPCANONFolderEntry** entries, uint32_t* entnum) +{ + uint16_t ret; + PTPContainer ptp; + char *data = NULL; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CANON_GetFolderEntries; + ptp.Param1=store; + ptp.Param2=p2; + ptp.Param3=parent; + ptp.Param4=handle; + ptp.Nparam=4; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data); + if (ret == PTP_RC_OK) { + int i; + *entnum=ptp.Param1; + *entries=calloc(*entnum, sizeof(PTPCANONFolderEntry)); + if (*entries!=NULL) { + for(i=0; i<(*entnum); i++) + ptp_unpack_Canon_FE(params, + data+i*PTP_CANON_FolderEntryLen, + &((*entries)[i]) ); + } else { + ret=PTP_ERROR_IO; /* Cannot allocate memory */ + } + } + free(data); + return ret; +} + + +/* Nikon extension code */ + +uint16_t +ptp_nikon_setcontrolmode (PTPParams* params, uint32_t mode) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_NIKON_SetControlMode; + ptp.Param1=mode; + ptp.Nparam=1; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +uint16_t +ptp_nikon_directcapture (PTPParams* params, uint32_t unknown) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_NIKON_DirectCapture; + ptp.Param1=unknown; /* as of yet unknown parameter */ + ptp.Nparam=1; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + +uint16_t +ptp_nikon_checkevent (PTPParams* params, PTPUSBEventContainer** event, uint16_t* evnum) +{ + uint16_t ret; + PTPContainer ptp; + char *evdata = NULL; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_NIKON_CheckEvent; + ptp.Nparam=0; + + ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &evdata); + if (ret == PTP_RC_OK) ptp_nikon_unpack_EC(params, evdata, event, evnum); + free (evdata); + return ret; +} + +uint16_t +ptp_nikon_keepalive (PTPParams* params) +{ + + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_NIKON_KeepAlive; + ptp.Nparam=0; + return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); +} + + + + +/* Non PTP protocol functions */ +/* devinfo testing functions */ + +int +ptp_operation_issupported(PTPParams* params, uint16_t operation) +{ + int i=0; + + for (;ideviceinfo.OperationsSupported_len;i++) { + if (params->deviceinfo.OperationsSupported[i]==operation) + return 1; + } + return 0; +} + + +/* ptp structures feeing functions */ + +void +ptp_free_devicepropdesc(PTPDevicePropDesc* dpd) +{ + uint16_t i; + + free(dpd->FactoryDefaultValue); + free(dpd->CurrentValue); + switch (dpd->FormFlag) { + case PTP_DPFF_Range: + free (dpd->FORM.Range.MinimumValue); + free (dpd->FORM.Range.MaximumValue); + free (dpd->FORM.Range.StepSize); + break; + case PTP_DPFF_Enumeration: + for (i=0;iFORM.Enum.NumberOfValues;i++) + free(dpd->FORM.Enum.SupportedValue[i]); + free(dpd->FORM.Enum.SupportedValue); + } +} + +/* report PTP errors */ + +void +ptp_perror(PTPParams* params, uint16_t error) { + + int i; + /* PTP error descriptions */ + static struct { + uint16_t error; + const char *txt; + } ptp_errors[] = { + {PTP_RC_Undefined, N_("PTP: Undefined Error")}, + {PTP_RC_OK, N_("PTP: OK!")}, + {PTP_RC_GeneralError, N_("PTP: General Error")}, + {PTP_RC_SessionNotOpen, N_("PTP: Session Not Open")}, + {PTP_RC_InvalidTransactionID, N_("PTP: Invalid Transaction ID")}, + {PTP_RC_OperationNotSupported, N_("PTP: Operation Not Supported")}, + {PTP_RC_ParameterNotSupported, N_("PTP: Parameter Not Supported")}, + {PTP_RC_IncompleteTransfer, N_("PTP: Incomplete Transfer")}, + {PTP_RC_InvalidStorageId, N_("PTP: Invalid Storage ID")}, + {PTP_RC_InvalidObjectHandle, N_("PTP: Invalid Object Handle")}, + {PTP_RC_DevicePropNotSupported, N_("PTP: Device Prop Not Supported")}, + {PTP_RC_InvalidObjectFormatCode, N_("PTP: Invalid Object Format Code")}, + {PTP_RC_StoreFull, N_("PTP: Store Full")}, + {PTP_RC_ObjectWriteProtected, N_("PTP: Object Write Protected")}, + {PTP_RC_StoreReadOnly, N_("PTP: Store Read Only")}, + {PTP_RC_AccessDenied, N_("PTP: Access Denied")}, + {PTP_RC_NoThumbnailPresent, N_("PTP: No Thumbnail Present")}, + {PTP_RC_SelfTestFailed, N_("PTP: Self Test Failed")}, + {PTP_RC_PartialDeletion, N_("PTP: Partial Deletion")}, + {PTP_RC_StoreNotAvailable, N_("PTP: Store Not Available")}, + {PTP_RC_SpecificationByFormatUnsupported, + N_("PTP: Specification By Format Unsupported")}, + {PTP_RC_NoValidObjectInfo, N_("PTP: No Valid Object Info")}, + {PTP_RC_InvalidCodeFormat, N_("PTP: Invalid Code Format")}, + {PTP_RC_UnknownVendorCode, N_("PTP: Unknown Vendor Code")}, + {PTP_RC_CaptureAlreadyTerminated, + N_("PTP: Capture Already Terminated")}, + {PTP_RC_DeviceBusy, N_("PTP: Device Busy")}, + {PTP_RC_InvalidParentObject, N_("PTP: Invalid Parent Object")}, + {PTP_RC_InvalidDevicePropFormat, N_("PTP: Invalid Device Prop Format")}, + {PTP_RC_InvalidDevicePropValue, N_("PTP: Invalid Device Prop Value")}, + {PTP_RC_InvalidParameter, N_("PTP: Invalid Parameter")}, + {PTP_RC_SessionAlreadyOpened, N_("PTP: Session Already Opened")}, + {PTP_RC_TransactionCanceled, N_("PTP: Transaction Canceled")}, + {PTP_RC_SpecificationOfDestinationUnsupported, + N_("PTP: Specification Of Destination Unsupported")}, + + {PTP_ERROR_IO, N_("PTP: I/O error")}, + {PTP_ERROR_BADPARAM, N_("PTP: Error: bad parameter")}, + {PTP_ERROR_DATA_EXPECTED, N_("PTP: Protocol error: data expected")}, + {PTP_ERROR_RESP_EXPECTED, N_("PTP: Protocol error: response expected")}, + {0, NULL} + }; + static struct { + uint16_t error; + const char *txt; + } ptp_errors_EK[] = { + {PTP_RC_EK_FilenameRequired, N_("PTP EK: Filename Required")}, + {PTP_RC_EK_FilenameConflicts, N_("PTP EK: Filename Conflicts")}, + {PTP_RC_EK_FilenameInvalid, N_("PTP EK: Filename Invalid")}, + {0, NULL} + }; + static struct { + uint16_t error; + const char *txt; + } ptp_errors_NIKON[] = { + {PTP_RC_NIKON_PropertyReadOnly, N_("PTP NIKON: Property Read Only")}, + {0, NULL} + }; + + for (i=0; ptp_errors[i].txt!=NULL; i++) + if (ptp_errors[i].error == error){ + ptp_error(params, ptp_errors[i].txt); + return; + } + + /*if (error|PTP_RC_EXTENSION_MASK==PTP_RC_EXTENSION)*/ + switch (params->deviceinfo.VendorExtensionID) { + case PTP_VENDOR_EASTMAN_KODAK: + for (i=0; ptp_errors_EK[i].txt!=NULL; i++) + if (ptp_errors_EK[i].error==error) { + ptp_error(params, ptp_errors_EK[i].txt); + return; + } + break; + case PTP_VENDOR_NIKON: + for (i=0; ptp_errors_NIKON[i].txt!=NULL; i++) + if (ptp_errors_NIKON[i].error==error) { + ptp_error(params, ptp_errors_NIKON[i].txt); + return; + } + break; + } + + ptp_error(params, "PTP: Error 0x%04x", error); + +} + +/* return DataType description */ + +const char* +ptp_get_datatype_name(PTPParams* params, uint16_t dt) +{ + int i; + /* Data Types */ + static struct { + uint16_t dt; + const char *txt; + } ptp_datatypes[] = { + {PTP_DTC_UNDEF, N_("UndefinedType")}, + {PTP_DTC_INT8, N_("INT8")}, + {PTP_DTC_UINT8, N_("UINT8")}, + {PTP_DTC_INT16, N_("INT16")}, + {PTP_DTC_UINT16, N_("UINT16")}, + {PTP_DTC_INT32, N_("INT32")}, + {PTP_DTC_UINT32, N_("UINT32")}, + {PTP_DTC_INT64, N_("INT64")}, + {PTP_DTC_UINT64, N_("UINT64")}, + {PTP_DTC_INT128, N_("INT128")}, + {PTP_DTC_UINT128, N_("UINT128")}, + {PTP_DTC_AINT8, N_("ArrayINT8")}, + {PTP_DTC_AUINT8, N_("ArrayUINT8")}, + {PTP_DTC_AINT16, N_("ArrayINT16")}, + {PTP_DTC_AUINT16, N_("ArrayUINT16")}, + {PTP_DTC_AINT32, N_("ArrayINT32")}, + {PTP_DTC_AUINT32, N_("ArrayUINT32")}, + {PTP_DTC_AINT64, N_("ArrayINT64")}, + {PTP_DTC_AUINT64, N_("ArrayUINT64")}, + {PTP_DTC_AINT128, N_("ArrayINT128")}, + {PTP_DTC_AUINT128, N_("ArrayUINT128")}, + {PTP_DTC_STR, N_("String")}, + {0,NULL} + }; + + for (i=0; ptp_datatypes[i].txt!=NULL; i++) + if (ptp_datatypes[i].dt == dt){ + return (ptp_datatypes[i].txt); + } + + return NULL; +} + +/* return ptp operation name */ + +const char* +ptp_get_operation_name(PTPParams* params, uint16_t oc) +{ + int i; + /* Operation Codes */ + static struct { + uint16_t oc; + const char *txt; + } ptp_operations[] = { + {PTP_OC_Undefined, N_("UndefinedOperation")}, + {PTP_OC_GetDeviceInfo, N_("GetDeviceInfo")}, + {PTP_OC_OpenSession, N_("OpenSession")}, + {PTP_OC_CloseSession, N_("CloseSession")}, + {PTP_OC_GetStorageIDs, N_("GetStorageIDs")}, + {PTP_OC_GetStorageInfo, N_("GetStorageInfo")}, + {PTP_OC_GetNumObjects, N_("GetNumObjects")}, + {PTP_OC_GetObjectHandles, N_("GetObjectHandles")}, + {PTP_OC_GetObjectInfo, N_("GetObjectInfo")}, + {PTP_OC_GetObject, N_("GetObject")}, + {PTP_OC_GetThumb, N_("GetThumb")}, + {PTP_OC_DeleteObject, N_("DeleteObject")}, + {PTP_OC_SendObjectInfo, N_("SendObjectInfo")}, + {PTP_OC_SendObject, N_("SendObject")}, + {PTP_OC_InitiateCapture, N_("InitiateCapture")}, + {PTP_OC_FormatStore, N_("FormatStore")}, + {PTP_OC_ResetDevice, N_("ResetDevice")}, + {PTP_OC_SelfTest, N_("SelfTest")}, + {PTP_OC_SetObjectProtection, N_("SetObjectProtection")}, + {PTP_OC_PowerDown, N_("PowerDown")}, + {PTP_OC_GetDevicePropDesc, N_("GetDevicePropDesc")}, + {PTP_OC_GetDevicePropValue, N_("GetDevicePropValue")}, + {PTP_OC_SetDevicePropValue, N_("SetDevicePropValue")}, + {PTP_OC_ResetDevicePropValue, N_("ResetDevicePropValue")}, + {PTP_OC_TerminateOpenCapture, N_("TerminateOpenCapture")}, + {PTP_OC_MoveObject, N_("MoveObject")}, + {PTP_OC_CopyObject, N_("CopyObject")}, + {PTP_OC_GetPartialObject, N_("GetPartialObject")}, + {PTP_OC_InitiateOpenCapture, N_("InitiateOpenCapture")}, + {0,NULL} + }; + static struct { + uint16_t oc; + const char *txt; + } ptp_operations_EK[] = { + {PTP_OC_EK_SendFileObjectInfo, N_("EK SendFileObjectInfo")}, + {PTP_OC_EK_SendFileObject, N_("EK SendFileObject")}, + {0,NULL} + }; + static struct { + uint16_t oc; + const char *txt; + } ptp_operations_CANON[] = { + {PTP_OC_CANON_GetObjectSize, N_("CANON GetObjectSize")}, + {PTP_OC_CANON_StartShootingMode,N_("CANON StartShootingMode")}, + {PTP_OC_CANON_EndShootingMode, N_("CANON EndShootingMode")}, + {PTP_OC_CANON_ViewfinderOn, N_("CANON ViewfinderOn")}, + {PTP_OC_CANON_ViewfinderOff, N_("CANON ViewfinderOff")}, + {PTP_OC_CANON_ReflectChanges, N_("CANON ReflectChanges")}, + {PTP_OC_CANON_CheckEvent, N_("CANON CheckEvent")}, + {PTP_OC_CANON_FocusLock, N_("CANON FocusLock")}, + {PTP_OC_CANON_FocusUnlock, N_("CANON FocusUnlock")}, + {PTP_OC_CANON_InitiateCaptureInMemory, + N_("CANON InitiateCaptureInMemory")}, + {PTP_OC_CANON_GetPartialObject, N_("CANON GetPartialObject")}, + {PTP_OC_CANON_GetViewfinderImage, + N_("CANON GetViewfinderImage")}, + {PTP_OC_CANON_GetChanges, N_("CANON GetChanges")}, + {PTP_OC_CANON_GetFolderEntries, N_("CANON GetFolderEntries")}, + {0,NULL} + }; + static struct { + uint16_t oc; + const char *txt; + } ptp_operations_NIKON[] = { + {PTP_OC_NIKON_DirectCapture, N_("NIKON DirectCapture")}, + {PTP_OC_NIKON_SetControlMode, N_("NIKON SetControlMode")}, + {PTP_OC_NIKON_CheckEvent, N_("NIKON Check Event")}, + {PTP_OC_NIKON_KeepAlive, N_("NIKON Keep Alive (?)")}, + {0,NULL} + }; + + switch (params->deviceinfo.VendorExtensionID) { + case PTP_VENDOR_EASTMAN_KODAK: + for (i=0; ptp_operations_EK[i].txt!=NULL; i++) + if (ptp_operations_EK[i].oc==oc) + return (ptp_operations_EK[i].txt); + break; + + case PTP_VENDOR_CANON: + for (i=0; ptp_operations_CANON[i].txt!=NULL; i++) + if (ptp_operations_CANON[i].oc==oc) + return (ptp_operations_CANON[i].txt); + break; + case PTP_VENDOR_NIKON: + for (i=0; ptp_operations_NIKON[i].txt!=NULL; i++) + if (ptp_operations_NIKON[i].oc==oc) + return (ptp_operations_NIKON[i].txt); + break; + } + for (i=0; ptp_operations[i].txt!=NULL; i++) + if (ptp_operations[i].oc == oc){ + return (ptp_operations[i].txt); + } + + return NULL; +} + + +/****** CHDK interface ******/ + +int ptp_chdk_shutdown_hard(PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=2; + ptp.Param1=PTP_CHDK_Shutdown; + ptp.Param2=0; + ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); + if ( ret != 0x2ff ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + return 1; +} + +int ptp_chdk_shutdown_soft(PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=2; + ptp.Param1=PTP_CHDK_Shutdown; + ptp.Param2=1; + ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + return 1; +} + +int ptp_chdk_reboot(PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=2; + ptp.Param1=PTP_CHDK_Shutdown; + ptp.Param2=2; + ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); + if ( ret != 0x2ff ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + return 1; +} + +int ptp_chdk_reboot_fw_update(char *path, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=2; + ptp.Param1=PTP_CHDK_Shutdown; + ptp.Param2=3; + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(path), &path); + if ( ret != 0x2ff ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + return 1; +} + +char* ptp_chdk_get_memory(int start, int num, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + char *buf = NULL; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=3; + ptp.Param1=PTP_CHDK_GetMemory; + ptp.Param2=start; + ptp.Param3=num; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + free(buf); + return NULL; + } + return buf; +} + +int ptp_chdk_set_memory_long(int addr, int val, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=3; + ptp.Param1=PTP_CHDK_SetMemoryLong; + ptp.Param2=addr; + ptp.Param3=val; + ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + return 1; +} + +int ptp_chdk_call(int *args, int size, int *ret, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t r; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_CallFunction; + r=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size*sizeof(int), (char **) &args); + if ( r != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",r); + return 0; + } + if ( ret ) + { + *ret = ptp.Param1; + } + return 1; +} + +int* ptp_chdk_get_propcase(int start, int num, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + char *buf = NULL; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=3; + ptp.Param1=PTP_CHDK_GetPropCase; + ptp.Param2=start; + ptp.Param3=num; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + free(buf); + return NULL; + } + return (int *) buf; +} + +char* ptp_chdk_get_paramdata(int start, int num, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + char *buf = NULL; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=3; + ptp.Param1=PTP_CHDK_GetParamData; + ptp.Param2=start; + ptp.Param3=num; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + free(buf); + return NULL; + } + return buf; +} + +int ptp_chdk_upload(char *local_fn, char *remote_fn, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + char *buf = NULL; + FILE *f; + int s,l; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_UploadFile; + + f = fopen(local_fn,"rb"); + if ( f == NULL ) + { + ptp_error(params,"could not open file \'%s\'",local_fn); + return 0; + } + + fseek(f,0,SEEK_END); + s = ftell(f); + fseek(f,0,SEEK_SET); + + l = strlen(remote_fn); + buf = malloc(4+l+s); + memcpy(buf,&l,4); + memcpy(buf+4,remote_fn,l); + fread(buf+4+l,1,s,f); + + fclose(f); + + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, 4+l+s, &buf); + + free(buf); + + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + return 1; +} + +int ptp_chdk_download(char *remote_fn, char *local_fn, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + char *buf = NULL; + FILE *f; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_TempData; + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(remote_fn), &remote_fn); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_DownloadFile; + + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + + f = fopen(local_fn,"wb"); + if ( f == NULL ) + { + ptp_error(params,"could not open file \'%s\'",local_fn); + free(buf); + return 0; + } + + fwrite(buf,1,ptp.Param1,f); + fclose(f); + + free(buf); + + return 1; +} + +int ptp_chdk_switch_mode(int mode, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=2; + ptp.Param1=PTP_CHDK_SwitchMode; + ptp.Param2=mode; + ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + return 1; +} + +int ptp_chdk_exec_lua(char *script, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t r; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_ExecuteLUA; + r=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(script)+1, &script); + if ( r != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",r); + return 0; + } + return 1; +} + diff --git a/tools/ptpcam/ptp.h b/tools/ptpcam/ptp.h new file mode 100644 index 00000000..3db3da7a --- /dev/null +++ b/tools/ptpcam/ptp.h @@ -0,0 +1,918 @@ +/* ptp.h + * + * Copyright (C) 2001-2004 Mariusz Woloszyn + * + * This file is part of libptp2. + * + * libptp2 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. + * + * libptp2 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 libptp2; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PTP_H__ +#define __PTP_H__ + +#include +#include +#include "libptp-endian.h" + +/* PTP datalayer byteorder */ + +#define PTP_DL_BE 0xF0 +#define PTP_DL_LE 0x0F + +/* PTP request/response/event general PTP container (transport independent) */ + +struct _PTPContainer { + uint16_t Code; + uint32_t SessionID; + uint32_t Transaction_ID; + /* params may be of any type of size less or equal to uint32_t */ + uint32_t Param1; + uint32_t Param2; + uint32_t Param3; + /* events can only have three parameters */ + uint32_t Param4; + uint32_t Param5; + /* the number of meaningfull parameters */ + uint8_t Nparam; +}; +typedef struct _PTPContainer PTPContainer; + +/* PTP USB Bulk-Pipe container */ +/* USB bulk max max packet length for high speed endpoints */ +#define PTP_USB_BULK_HS_MAX_PACKET_LEN 512 +#define PTP_USB_BULK_HDR_LEN (2*sizeof(uint32_t)+2*sizeof(uint16_t)) +#define PTP_USB_BULK_PAYLOAD_LEN (PTP_USB_BULK_HS_MAX_PACKET_LEN-PTP_USB_BULK_HDR_LEN) +#define PTP_USB_BULK_REQ_LEN (PTP_USB_BULK_HDR_LEN+5*sizeof(uint32_t)) + +struct _PTPUSBBulkContainer { + uint32_t length; + uint16_t type; + uint16_t code; + uint32_t trans_id; + union { + struct { + uint32_t param1; + uint32_t param2; + uint32_t param3; + uint32_t param4; + uint32_t param5; + } params; + unsigned char data[PTP_USB_BULK_PAYLOAD_LEN]; + } payload; +}; +typedef struct _PTPUSBBulkContainer PTPUSBBulkContainer; + +#define PTP_USB_INT_PACKET_LEN 8 + +/* PTP USB Asynchronous Event Interrupt Data Format */ +struct _PTPUSBEventContainer { + uint32_t length; + uint16_t type; + uint16_t code; + uint32_t trans_id; + uint32_t param1; + uint32_t param2; + uint32_t param3; +}; +typedef struct _PTPUSBEventContainer PTPUSBEventContainer; + + +/* USB container types */ + +#define PTP_USB_CONTAINER_UNDEFINED 0x0000 +#define PTP_USB_CONTAINER_COMMAND 0x0001 +#define PTP_USB_CONTAINER_DATA 0x0002 +#define PTP_USB_CONTAINER_RESPONSE 0x0003 +#define PTP_USB_CONTAINER_EVENT 0x0004 + +/* Vendor IDs */ +#define PTP_VENDOR_EASTMAN_KODAK 0x00000001 +#define PTP_VENDOR_SEIKO_EPSON 0x00000002 +#define PTP_VENDOR_AGILENT 0x00000003 +#define PTP_VENDOR_POLAROID 0x00000004 +#define PTP_VENDOR_AGFA_GEVAERT 0x00000005 +#define PTP_VENDOR_MICROSOFT 0x00000006 +#define PTP_VENDOR_EQUINOX 0x00000007 +#define PTP_VENDOR_VIEWQUEST 0x00000008 +#define PTP_VENDOR_STMICROELECTRONICS 0x00000009 +#define PTP_VENDOR_NIKON 0x0000000A +#define PTP_VENDOR_CANON 0x0000000B + +/* Operation Codes */ + +#define PTP_OC_Undefined 0x1000 +#define PTP_OC_GetDeviceInfo 0x1001 +#define PTP_OC_OpenSession 0x1002 +#define PTP_OC_CloseSession 0x1003 +#define PTP_OC_GetStorageIDs 0x1004 +#define PTP_OC_GetStorageInfo 0x1005 +#define PTP_OC_GetNumObjects 0x1006 +#define PTP_OC_GetObjectHandles 0x1007 +#define PTP_OC_GetObjectInfo 0x1008 +#define PTP_OC_GetObject 0x1009 +#define PTP_OC_GetThumb 0x100A +#define PTP_OC_DeleteObject 0x100B +#define PTP_OC_SendObjectInfo 0x100C +#define PTP_OC_SendObject 0x100D +#define PTP_OC_InitiateCapture 0x100E +#define PTP_OC_FormatStore 0x100F +#define PTP_OC_ResetDevice 0x1010 +#define PTP_OC_SelfTest 0x1011 +#define PTP_OC_SetObjectProtection 0x1012 +#define PTP_OC_PowerDown 0x1013 +#define PTP_OC_GetDevicePropDesc 0x1014 +#define PTP_OC_GetDevicePropValue 0x1015 +#define PTP_OC_SetDevicePropValue 0x1016 +#define PTP_OC_ResetDevicePropValue 0x1017 +#define PTP_OC_TerminateOpenCapture 0x1018 +#define PTP_OC_MoveObject 0x1019 +#define PTP_OC_CopyObject 0x101A +#define PTP_OC_GetPartialObject 0x101B +#define PTP_OC_InitiateOpenCapture 0x101C +/* Eastman Kodak extension Operation Codes */ +#define PTP_OC_EK_SendFileObjectInfo 0x9005 +#define PTP_OC_EK_SendFileObject 0x9006 +/* Canon extension Operation Codes */ +#define PTP_OC_CANON_GetObjectSize 0x9001 +#define PTP_OC_CANON_StartShootingMode 0x9008 +#define PTP_OC_CANON_EndShootingMode 0x9009 +#define PTP_OC_CANON_ViewfinderOn 0x900B +#define PTP_OC_CANON_ViewfinderOff 0x900C +#define PTP_OC_CANON_ReflectChanges 0x900D +#define PTP_OC_CANON_CheckEvent 0x9013 +#define PTP_OC_CANON_FocusLock 0x9014 +#define PTP_OC_CANON_FocusUnlock 0x9015 +#define PTP_OC_CANON_InitiateCaptureInMemory 0x901A +#define PTP_OC_CANON_GetPartialObject 0x901B +#define PTP_OC_CANON_GetViewfinderImage 0x901d +#define PTP_OC_CANON_GetChanges 0x9020 +#define PTP_OC_CANON_GetFolderEntries 0x9021 +/* Nikon extensiion Operation Codes */ +#define PTP_OC_NIKON_DirectCapture 0x90C0 +#define PTP_OC_NIKON_SetControlMode 0x90C2 +#define PTP_OC_NIKON_CheckEvent 0x90C7 +#define PTP_OC_NIKON_KeepAlive 0x90C8 +/* CHDK extension */ +#define PTP_OC_CHDK 0x9999 + + +/* Proprietary vendor extension operations mask */ +#define PTP_OC_EXTENSION_MASK 0xF000 +#define PTP_OC_EXTENSION 0x9000 + +/* Response Codes */ + +#define PTP_RC_Undefined 0x2000 +#define PTP_RC_OK 0x2001 +#define PTP_RC_GeneralError 0x2002 +#define PTP_RC_SessionNotOpen 0x2003 +#define PTP_RC_InvalidTransactionID 0x2004 +#define PTP_RC_OperationNotSupported 0x2005 +#define PTP_RC_ParameterNotSupported 0x2006 +#define PTP_RC_IncompleteTransfer 0x2007 +#define PTP_RC_InvalidStorageId 0x2008 +#define PTP_RC_InvalidObjectHandle 0x2009 +#define PTP_RC_DevicePropNotSupported 0x200A +#define PTP_RC_InvalidObjectFormatCode 0x200B +#define PTP_RC_StoreFull 0x200C +#define PTP_RC_ObjectWriteProtected 0x200D +#define PTP_RC_StoreReadOnly 0x200E +#define PTP_RC_AccessDenied 0x200F +#define PTP_RC_NoThumbnailPresent 0x2010 +#define PTP_RC_SelfTestFailed 0x2011 +#define PTP_RC_PartialDeletion 0x2012 +#define PTP_RC_StoreNotAvailable 0x2013 +#define PTP_RC_SpecificationByFormatUnsupported 0x2014 +#define PTP_RC_NoValidObjectInfo 0x2015 +#define PTP_RC_InvalidCodeFormat 0x2016 +#define PTP_RC_UnknownVendorCode 0x2017 +#define PTP_RC_CaptureAlreadyTerminated 0x2018 +#define PTP_RC_DeviceBusy 0x2019 +#define PTP_RC_InvalidParentObject 0x201A +#define PTP_RC_InvalidDevicePropFormat 0x201B +#define PTP_RC_InvalidDevicePropValue 0x201C +#define PTP_RC_InvalidParameter 0x201D +#define PTP_RC_SessionAlreadyOpened 0x201E +#define PTP_RC_TransactionCanceled 0x201F +#define PTP_RC_SpecificationOfDestinationUnsupported 0x2020 +/* Eastman Kodak extension Response Codes */ +#define PTP_RC_EK_FilenameRequired 0xA001 +#define PTP_RC_EK_FilenameConflicts 0xA002 +#define PTP_RC_EK_FilenameInvalid 0xA003 + +/* NIKON extension Response Codes */ +#define PTP_RC_NIKON_PropertyReadOnly 0xA005 + +/* Proprietary vendor extension response code mask */ +#define PTP_RC_EXTENSION_MASK 0xF000 +#define PTP_RC_EXTENSION 0xA000 + +/* libptp2 extended ERROR codes */ +#define PTP_ERROR_IO 0x02FF +#define PTP_ERROR_DATA_EXPECTED 0x02FE +#define PTP_ERROR_RESP_EXPECTED 0x02FD +#define PTP_ERROR_BADPARAM 0x02FC + +/* PTP Event Codes */ + +#define PTP_EC_Undefined 0x4000 +#define PTP_EC_CancelTransaction 0x4001 +#define PTP_EC_ObjectAdded 0x4002 +#define PTP_EC_ObjectRemoved 0x4003 +#define PTP_EC_StoreAdded 0x4004 +#define PTP_EC_StoreRemoved 0x4005 +#define PTP_EC_DevicePropChanged 0x4006 +#define PTP_EC_ObjectInfoChanged 0x4007 +#define PTP_EC_DeviceInfoChanged 0x4008 +#define PTP_EC_RequestObjectTransfer 0x4009 +#define PTP_EC_StoreFull 0x400A +#define PTP_EC_DeviceReset 0x400B +#define PTP_EC_StorageInfoChanged 0x400C +#define PTP_EC_CaptureComplete 0x400D +#define PTP_EC_UnreportedStatus 0x400E +/* Canon extension Event Codes */ +#define PTP_EC_CANON_DeviceInfoChanged 0xC008 +#define PTP_EC_CANON_RequestObjectTransfer 0xC009 +#define PTP_EC_CANON_CameraModeChanged 0xC00C + +/* Nikon extension Event Codes */ +#define PTP_EC_NIKON_ObjectReady 0xC101 +#define PTP_EC_NIKON_CaptureOverflow 0xC102 + +/* PTP device info structure (returned by GetDevInfo) */ + +struct _PTPDeviceInfo { + uint16_t StaqndardVersion; + uint32_t VendorExtensionID; + uint16_t VendorExtensionVersion; + char *VendorExtensionDesc; + uint16_t FunctionalMode; + uint32_t OperationsSupported_len; + uint16_t *OperationsSupported; + uint32_t EventsSupported_len; + uint16_t *EventsSupported; + uint32_t DevicePropertiesSupported_len; + uint16_t *DevicePropertiesSupported; + uint32_t CaptureFormats_len; + uint16_t *CaptureFormats; + uint32_t ImageFormats_len; + uint16_t *ImageFormats; + char *Manufacturer; + char *Model; + char *DeviceVersion; + char *SerialNumber; +}; +typedef struct _PTPDeviceInfo PTPDeviceInfo; + +/* PTP storageIDs structute (returned by GetStorageIDs) */ + +struct _PTPStorageIDs { + uint32_t n; + uint32_t *Storage; +}; +typedef struct _PTPStorageIDs PTPStorageIDs; + +/* PTP StorageInfo structure (returned by GetStorageInfo) */ +struct _PTPStorageInfo { + uint16_t StorageType; + uint16_t FilesystemType; + uint16_t AccessCapability; + uint64_t MaxCapability; + uint64_t FreeSpaceInBytes; + uint32_t FreeSpaceInImages; + char *StorageDescription; + char *VolumeLabel; +}; +typedef struct _PTPStorageInfo PTPStorageInfo; + +/* PTP objecthandles structure (returned by GetObjectHandles) */ + +struct _PTPObjectHandles { + uint32_t n; + uint32_t *Handler; +}; +typedef struct _PTPObjectHandles PTPObjectHandles; + +#define PTP_HANDLER_SPECIAL 0xffffffff +#define PTP_HANDLER_ROOT 0x00000000 + + +/* PTP objectinfo structure (returned by GetObjectInfo) */ + +struct _PTPObjectInfo { + uint32_t StorageID; + uint16_t ObjectFormat; + uint16_t ProtectionStatus; + uint32_t ObjectCompressedSize; + uint16_t ThumbFormat; + uint32_t ThumbCompressedSize; + uint32_t ThumbPixWidth; + uint32_t ThumbPixHeight; + uint32_t ImagePixWidth; + uint32_t ImagePixHeight; + uint32_t ImageBitDepth; + uint32_t ParentObject; + uint16_t AssociationType; + uint32_t AssociationDesc; + uint32_t SequenceNumber; + char *Filename; + time_t CaptureDate; + time_t ModificationDate; + char *Keywords; +}; +typedef struct _PTPObjectInfo PTPObjectInfo; + +/* max ptp string length INCLUDING terminating null character */ + +#define PTP_MAXSTRLEN 255 + +/* PTP Object Format Codes */ + +/* ancillary formats */ +#define PTP_OFC_Undefined 0x3000 +#define PTP_OFC_Association 0x3001 +#define PTP_OFC_Script 0x3002 +#define PTP_OFC_Executable 0x3003 +#define PTP_OFC_Text 0x3004 +#define PTP_OFC_HTML 0x3005 +#define PTP_OFC_DPOF 0x3006 +#define PTP_OFC_AIFF 0x3007 +#define PTP_OFC_WAV 0x3008 +#define PTP_OFC_MP3 0x3009 +#define PTP_OFC_AVI 0x300A +#define PTP_OFC_MPEG 0x300B +#define PTP_OFC_ASF 0x300C +#define PTP_OFC_QT 0x300D /* guessing */ +/* image formats */ +#define PTP_OFC_EXIF_JPEG 0x3801 +#define PTP_OFC_TIFF_EP 0x3802 +#define PTP_OFC_FlashPix 0x3803 +#define PTP_OFC_BMP 0x3804 +#define PTP_OFC_CIFF 0x3805 +#define PTP_OFC_Undefined_0x3806 0x3806 +#define PTP_OFC_GIF 0x3807 +#define PTP_OFC_JFIF 0x3808 +#define PTP_OFC_PCD 0x3809 +#define PTP_OFC_PICT 0x380A +#define PTP_OFC_PNG 0x380B +#define PTP_OFC_Undefined_0x380C 0x380C +#define PTP_OFC_TIFF 0x380D +#define PTP_OFC_TIFF_IT 0x380E +#define PTP_OFC_JP2 0x380F +#define PTP_OFC_JPX 0x3810 +/* Eastman Kodak extension ancillary format */ +#define PTP_OFC_EK_M3U 0xb002 + + +/* PTP Association Types */ + +#define PTP_AT_Undefined 0x0000 +#define PTP_AT_GenericFolder 0x0001 +#define PTP_AT_Album 0x0002 +#define PTP_AT_TimeSequence 0x0003 +#define PTP_AT_HorizontalPanoramic 0x0004 +#define PTP_AT_VerticalPanoramic 0x0005 +#define PTP_AT_2DPanoramic 0x0006 +#define PTP_AT_AncillaryData 0x0007 + +/* PTP Protection Status */ + +#define PTP_PS_NoProtection 0x0000 +#define PTP_PS_ReadOnly 0x0001 + +/* PTP Storage Types */ + +#define PTP_ST_Undefined 0x0000 +#define PTP_ST_FixedROM 0x0001 +#define PTP_ST_RemovableROM 0x0002 +#define PTP_ST_FixedRAM 0x0003 +#define PTP_ST_RemovableRAM 0x0004 + +/* PTP FilesystemType Values */ + +#define PTP_FST_Undefined 0x0000 +#define PTP_FST_GenericFlat 0x0001 +#define PTP_FST_GenericHierarchical 0x0002 +#define PTP_FST_DCF 0x0003 + +/* PTP StorageInfo AccessCapability Values */ + +#define PTP_AC_ReadWrite 0x0000 +#define PTP_AC_ReadOnly 0x0001 +#define PTP_AC_ReadOnly_with_Object_Deletion 0x0002 + +/* Property Describing Dataset, Range Form */ + +struct _PTPPropDescRangeForm { + void * MinimumValue; + void * MaximumValue; + void * StepSize; +}; +typedef struct _PTPPropDescRangeForm PTPPropDescRangeForm; + +/* Property Describing Dataset, Enum Form */ + +struct _PTPPropDescEnumForm { + uint16_t NumberOfValues; + void ** SupportedValue; +}; +typedef struct _PTPPropDescEnumForm PTPPropDescEnumForm; + +/* Device Property Describing Dataset (DevicePropDesc) */ + +struct _PTPDevicePropDesc { + uint16_t DevicePropertyCode; + uint16_t DataType; + uint8_t GetSet; + void * FactoryDefaultValue; + void * CurrentValue; + uint8_t FormFlag; + union { + PTPPropDescEnumForm Enum; + PTPPropDescRangeForm Range; + } FORM; +}; +typedef struct _PTPDevicePropDesc PTPDevicePropDesc; + +/* Canon filesystem's folder entry Dataset */ + +#define PTP_CANON_FilenameBufferLen 13 +#define PTP_CANON_FolderEntryLen sizeof(PTPCANONFolderEntry) + +struct _PTPCANONFolderEntry { + uint32_t ObjectHandle; + uint16_t ObjectFormatCode; + uint8_t Flags; + uint32_t ObjectSize; + time_t Time; + char Filename[PTP_CANON_FilenameBufferLen]; +}; +typedef struct _PTPCANONFolderEntry PTPCANONFolderEntry; + +/* DataType Codes */ + +#define PTP_DTC_UNDEF 0x0000 +#define PTP_DTC_INT8 0x0001 +#define PTP_DTC_UINT8 0x0002 +#define PTP_DTC_INT16 0x0003 +#define PTP_DTC_UINT16 0x0004 +#define PTP_DTC_INT32 0x0005 +#define PTP_DTC_UINT32 0x0006 +#define PTP_DTC_INT64 0x0007 +#define PTP_DTC_UINT64 0x0008 +#define PTP_DTC_INT128 0x0009 +#define PTP_DTC_UINT128 0x000A +#define PTP_DTC_AINT8 0x4001 +#define PTP_DTC_AUINT8 0x4002 +#define PTP_DTC_AINT16 0x4003 +#define PTP_DTC_AUINT16 0x4004 +#define PTP_DTC_AINT32 0x4005 +#define PTP_DTC_AUINT32 0x4006 +#define PTP_DTC_AINT64 0x4007 +#define PTP_DTC_AUINT64 0x4008 +#define PTP_DTC_AINT128 0x4009 +#define PTP_DTC_AUINT128 0x400A +#define PTP_DTC_STR 0xFFFF + +/* Device Properties Codes */ + +#define PTP_DPC_Undefined 0x5000 +#define PTP_DPC_BatteryLevel 0x5001 +#define PTP_DPC_FunctionalMode 0x5002 +#define PTP_DPC_ImageSize 0x5003 +#define PTP_DPC_CompressionSetting 0x5004 +#define PTP_DPC_WhiteBalance 0x5005 +#define PTP_DPC_RGBGain 0x5006 +#define PTP_DPC_FNumber 0x5007 +#define PTP_DPC_FocalLength 0x5008 +#define PTP_DPC_FocusDistance 0x5009 +#define PTP_DPC_FocusMode 0x500A +#define PTP_DPC_ExposureMeteringMode 0x500B +#define PTP_DPC_FlashMode 0x500C +#define PTP_DPC_ExposureTime 0x500D +#define PTP_DPC_ExposureProgramMode 0x500E +#define PTP_DPC_ExposureIndex 0x500F +#define PTP_DPC_ExposureBiasCompensation 0x5010 +#define PTP_DPC_DateTime 0x5011 +#define PTP_DPC_CaptureDelay 0x5012 +#define PTP_DPC_StillCaptureMode 0x5013 +#define PTP_DPC_Contrast 0x5014 +#define PTP_DPC_Sharpness 0x5015 +#define PTP_DPC_DigitalZoom 0x5016 +#define PTP_DPC_EffectMode 0x5017 +#define PTP_DPC_BurstNumber 0x5018 +#define PTP_DPC_BurstInterval 0x5019 +#define PTP_DPC_TimelapseNumber 0x501A +#define PTP_DPC_TimelapseInterval 0x501B +#define PTP_DPC_FocusMeteringMode 0x501C +#define PTP_DPC_UploadURL 0x501D +#define PTP_DPC_Artist 0x501E +#define PTP_DPC_CopyrightInfo 0x501F + +/* Proprietary vendor extension device property mask */ +#define PTP_DPC_EXTENSION_MASK 0xF000 +#define PTP_DPC_EXTENSION 0xD000 + +/* Vendor Extensions device property codes */ + +/* Eastman Kodak extension device property codes */ +#define PTP_DPC_EK_ColorTemperature 0xD001 +#define PTP_DPC_EK_DateTimeStampFormat 0xD002 +#define PTP_DPC_EK_BeepMode 0xD003 +#define PTP_DPC_EK_VideoOut 0xD004 +#define PTP_DPC_EK_PowerSaving 0xD005 +#define PTP_DPC_EK_UI_Language 0xD006 +/* Canon extension device property codes */ +#define PTP_DPC_CANON_BeepMode 0xD001 +#define PTP_DPC_CANON_ViewfinderMode 0xD003 +#define PTP_DPC_CANON_ImageQuality 0xD006 +#define PTP_DPC_CANON_D007 0xD007 +#define PTP_DPC_CANON_ImageSize 0xD008 +#define PTP_DPC_CANON_FlashMode 0xD00A +#define PTP_DPC_CANON_TvAvSetting 0xD00C +#define PTP_DPC_CANON_MeteringMode 0xD010 +#define PTP_DPC_CANON_MacroMode 0xD011 +#define PTP_DPC_CANON_FocusingPoint 0xD012 +#define PTP_DPC_CANON_WhiteBalance 0xD013 +#define PTP_DPC_CANON_ISOSpeed 0xD01C +#define PTP_DPC_CANON_Aperture 0xD01D +#define PTP_DPC_CANON_ShutterSpeed 0xD01E +#define PTP_DPC_CANON_ExpCompensation 0xD01F +#define PTP_DPC_CANON_D029 0xD029 +#define PTP_DPC_CANON_Zoom 0xD02A +#define PTP_DPC_CANON_SizeQualityMode 0xD02C +#define PTP_DPC_CANON_FlashMemory 0xD031 +#define PTP_DPC_CANON_CameraModel 0xD032 +#define PTP_DPC_CANON_CameraOwner 0xD033 +#define PTP_DPC_CANON_UnixTime 0xD034 +#define PTP_DPC_CANON_ViewfinderOutput 0xD036 +#define PTP_DPC_CANON_RealImageWidth 0xD039 +#define PTP_DPC_CANON_PhotoEffect 0xD040 +#define PTP_DPC_CANON_AssistLight 0xD041 +#define PTP_DPC_CANON_D045 0xD045 + +/* Nikon extension device property codes */ +#define PTP_DPC_NIKON_ShootingBank 0xD010 +#define PTP_DPC_NIKON_ShootingBankNameA 0xD011 +#define PTP_DPC_NIKON_ShootingBankNameB 0xD012 +#define PTP_DPC_NIKON_ShootingBankNameC 0xD013 +#define PTP_DPC_NIKON_ShootingBankNameD 0xD014 +#define PTP_DPC_NIKON_RawCompression 0xD016 +#define PTP_DPC_NIKON_WhiteBalanceAutoBias 0xD017 +#define PTP_DPC_NIKON_WhiteBalanceTungstenBias 0xD018 +#define PTP_DPC_NIKON_WhiteBalanceFlourescentBias 0xD019 +#define PTP_DPC_NIKON_WhiteBalanceDaylightBias 0xD01A +#define PTP_DPC_NIKON_WhiteBalanceFlashBias 0xD01B +#define PTP_DPC_NIKON_WhiteBalanceCloudyBias 0xD01C +#define PTP_DPC_NIKON_WhiteBalanceShadeBias 0xD01D +#define PTP_DPC_NIKON_WhiteBalanceColorTemperature 0xD01E +#define PTP_DPC_NIKON_ImageSharpening 0xD02A +#define PTP_DPC_NIKON_ToneCompensation 0xD02B +#define PTP_DPC_NIKON_ColorMode 0xD02C +#define PTP_DPC_NIKON_HueAdjustment 0xD02D +#define PTP_DPC_NIKON_NonCPULensDataFocalLength 0xD02E +#define PTP_DPC_NIKON_NonCPULensDataMaximumAperture 0xD02F +#define PTP_DPC_NIKON_CSMMenuBankSelect 0xD040 +#define PTP_DPC_NIKON_MenuBankNameA 0xD041 +#define PTP_DPC_NIKON_MenuBankNameB 0xD042 +#define PTP_DPC_NIKON_MenuBankNameC 0xD043 +#define PTP_DPC_NIKON_MenuBankNameD 0xD044 +#define PTP_DPC_NIKON_A1AFCModePriority 0xD048 +#define PTP_DPC_NIKON_A2AFSModePriority 0xD049 +#define PTP_DPC_NIKON_A3GroupDynamicAF 0xD04A +#define PTP_DPC_NIKON_A4AFActivation 0xD04B +#define PTP_DPC_NIKON_A5FocusAreaIllumManualFocus 0xD04C +#define PTP_DPC_NIKON_FocusAreaIllumContinuous 0xD04D +#define PTP_DPC_NIKON_FocusAreaIllumWhenSelected 0xD04E +#define PTP_DPC_NIKON_FocusAreaWrap 0xD04F +#define PTP_DPC_NIKON_A7VerticalAFON 0xD050 +#define PTP_DPC_NIKON_ISOAuto 0xD054 +#define PTP_DPC_NIKON_B2ISOStep 0xD055 +#define PTP_DPC_NIKON_EVStep 0xD056 +#define PTP_DPC_NIKON_B4ExposureCompEv 0xD057 +#define PTP_DPC_NIKON_ExposureCompensation 0xD058 +#define PTP_DPC_NIKON_CenterWeightArea 0xD059 +#define PTP_DPC_NIKON_AELockMode 0xD05E +#define PTP_DPC_NIKON_AELAFLMode 0xD05F +#define PTP_DPC_NIKON_MeterOff 0xD062 +#define PTP_DPC_NIKON_SelfTimer 0xD063 +#define PTP_DPC_NIKON_MonitorOff 0xD064 +#define PTP_DPC_NIKON_D1ShootingSpeed 0xD068 +#define PTP_DPC_NIKON_D2MaximumShots 0xD069 +#define PTP_DPC_NIKON_D3ExpDelayMode 0xD06A +#define PTP_DPC_NIKON_LongExposureNoiseReduction 0xD06B +#define PTP_DPC_NIKON_FileNumberSequence 0xD06C +#define PTP_DPC_NIKON_D6ControlPanelFinderRearControl 0xD06D +#define PTP_DPC_NIKON_ControlPanelFinderViewfinder 0xD06E +#define PTP_DPC_NIKON_D7Illumination 0xD06F +#define PTP_DPC_NIKON_E1FlashSyncSpeed 0xD074 +#define PTP_DPC_NIKON_FlashShutterSpeed 0xD075 +#define PTP_DPC_NIKON_E3AAFlashMode 0xD076 +#define PTP_DPC_NIKON_E4ModelingFlash 0xD077 +#define PTP_DPC_NIKON_BracketSet 0xD078 +#define PTP_DPC_NIKON_E6ManualModeBracketing 0xD079 +#define PTP_DPC_NIKON_BracketOrder 0xD07A +#define PTP_DPC_NIKON_E8AutoBracketSelection 0xD07B +#define PTP_DPC_NIKON_BracketingSet 0xD07C + +#define PTP_DPC_NIKON_F1CenterButtonShootingMode 0xD080 +#define PTP_DPC_NIKON_CenterButtonPlaybackMode 0xD081 +#define PTP_DPC_NIKON_F2Multiselector 0xD082 +#define PTP_DPC_NIKON_F3PhotoInfoPlayback 0xD083 +#define PTP_DPC_NIKON_F4AssignFuncButton 0xD084 +#define PTP_DPC_NIKON_F5CustomizeCommDials 0xD085 +#define PTP_DPC_NIKON_ReverseCommandDial 0xD086 +#define PTP_DPC_NIKON_ApertureSetting 0xD087 +#define PTP_DPC_NIKON_MenusAndPlayback 0xD088 +#define PTP_DPC_NIKON_F6ButtonsAndDials 0xD089 +#define PTP_DPC_NIKON_NoCFCard 0xD08A +#define PTP_DPC_NIKON_ImageCommentString 0xD090 +#define PTP_DPC_NIKON_ImageCommentAttach 0xD091 +#define PTP_DPC_NIKON_ImageRotation 0xD092 +#define PTP_DPC_NIKON_Bracketing 0xD0C0 +#define PTP_DPC_NIKON_ExposureBracketingIntervalDist 0xD0C1 +#define PTP_DPC_NIKON_BracketingProgram 0xD0C2 +#define PTP_DPC_NIKON_WhiteBalanceBracketStep 0xD0C4 +#define PTP_DPC_NIKON_LensID 0xD0E0 +#define PTP_DPC_NIKON_FocalLengthMin 0xD0E3 +#define PTP_DPC_NIKON_FocalLengthMax 0xD0E4 +#define PTP_DPC_NIKON_MaxApAtMinFocalLength 0xD0E5 +#define PTP_DPC_NIKON_MaxApAtMaxFocalLength 0xD0E6 +#define PTP_DPC_NIKON_ExposureTime 0xD100 +#define PTP_DPC_NIKON_ACPower 0xD101 +#define PTP_DPC_NIKON_MaximumShots 0xD103 +#define PTP_DPC_NIKON_AFLLock 0xD104 +#define PTP_DPC_NIKON_AutoExposureLock 0xD105 +#define PTP_DPC_NIKON_AutoFocusLock 0xD106 +#define PTP_DPC_NIKON_AutofocusLCDTopMode2 0xD107 +#define PTP_DPC_NIKON_AutofocusArea 0xD108 +#define PTP_DPC_NIKON_LightMeter 0xD10A +#define PTP_DPC_NIKON_CameraOrientation 0xD10E +#define PTP_DPC_NIKON_ExposureApertureLock 0xD111 +#define PTP_DPC_NIKON_BeepOff 0xD160 +#define PTP_DPC_NIKON_AutofocusMode 0xD161 +#define PTP_DPC_NIKON_AFAssist 0xD163 +#define PTP_DPC_NIKON_PADVPMode 0xD164 +#define PTP_DPC_NIKON_ImageReview 0xD165 +#define PTP_DPC_NIKON_AFAreaIllumination 0xD166 +#define PTP_DPC_NIKON_FlashMode 0xD167 +#define PTP_DPC_NIKON_FlashCommanderMode 0xD168 +#define PTP_DPC_NIKON_FlashSign 0xD169 +#define PTP_DPC_NIKON_GridDisplay 0xD16C +#define PTP_DPC_NIKON_FlashModeManualPower 0xD16D +#define PTP_DPC_NIKON_FlashModeCommanderPower 0xD16E +#define PTP_DPC_NIKON_RemoteTimeout 0xD16B +#define PTP_DPC_NIKON_GridDisplay 0xD16C +#define PTP_DPC_NIKON_BracketingIncrement 0xD190 +#define PTP_DPC_NIKON_LowLight 0xD1B0 +#define PTP_DPC_NIKON_FlashOpen 0xD1C0 +#define PTP_DPC_NIKON_FlashCharged 0xD1C1 +#define PTP_DPC_NIKON_FlashExposureCompensation 0xD126 +#define PTP_DPC_NIKON_CSMMenu 0xD180 +#define PTP_DPC_NIKON_OptimizeImage 0xD140 +#define PTP_DPC_NIKON_Saturation 0xD142 + +/* Device Property Form Flag */ + +#define PTP_DPFF_None 0x00 +#define PTP_DPFF_Range 0x01 +#define PTP_DPFF_Enumeration 0x02 + +/* Device Property GetSet type */ +#define PTP_DPGS_Get 0x00 +#define PTP_DPGS_GetSet 0x01 + +/* Glue stuff starts here */ + +typedef struct _PTPParams PTPParams; + +/* raw write functions */ +typedef short (* PTPIOReadFunc) (unsigned char *bytes, unsigned int size, + void *data); +typedef short (* PTPIOWriteFunc)(unsigned char *bytes, unsigned int size, + void *data); +/* + * This functions take PTP oriented arguments and send them over an + * appropriate data layer doing byteorder conversion accordingly. + */ +typedef uint16_t (* PTPIOSendReq) (PTPParams* params, PTPContainer* req); +typedef uint16_t (* PTPIOSendData) (PTPParams* params, PTPContainer* ptp, + unsigned char *data, unsigned int size); +typedef uint16_t (* PTPIOGetResp) (PTPParams* params, PTPContainer* resp); +typedef uint16_t (* PTPIOGetData) (PTPParams* params, PTPContainer* ptp, + unsigned char **data); +/* debug functions */ +typedef void (* PTPErrorFunc) (void *data, const char *format, va_list args); +typedef void (* PTPDebugFunc) (void *data, const char *format, va_list args); + +struct _PTPParams { + /* data layer byteorder */ + uint8_t byteorder; + + /* Data layer IO functions */ + PTPIOReadFunc read_func; + PTPIOWriteFunc write_func; + PTPIOReadFunc check_int_func; + PTPIOReadFunc check_int_fast_func; + + /* Custom IO functions */ + PTPIOSendReq sendreq_func; + PTPIOSendData senddata_func; + PTPIOGetResp getresp_func; + PTPIOGetData getdata_func; + PTPIOGetResp event_check; + PTPIOGetResp event_wait; + + /* Custom error and debug function */ + PTPErrorFunc error_func; + PTPDebugFunc debug_func; + + /* Data passed to above functions */ + void *data; + + /* ptp transaction ID */ + uint32_t transaction_id; + /* ptp session ID */ + uint32_t session_id; + + /* internal structures used by ptp driver */ + PTPObjectHandles handles; + PTPObjectInfo * objectinfo; + PTPDeviceInfo deviceinfo; +}; + +/* last, but not least - ptp functions */ +uint16_t ptp_usb_sendreq (PTPParams* params, PTPContainer* req); +uint16_t ptp_usb_senddata (PTPParams* params, PTPContainer* ptp, + unsigned char *data, unsigned int size); +uint16_t ptp_usb_getresp (PTPParams* params, PTPContainer* resp); +uint16_t ptp_usb_getdata (PTPParams* params, PTPContainer* ptp, + unsigned char **data); +uint16_t ptp_usb_event_check (PTPParams* params, PTPContainer* event); +uint16_t ptp_usb_event_wait (PTPParams* params, PTPContainer* event); + +uint16_t ptp_getdeviceinfo (PTPParams* params, PTPDeviceInfo* deviceinfo); + +uint16_t ptp_opensession (PTPParams *params, uint32_t session); +uint16_t ptp_closesession (PTPParams *params); + +uint16_t ptp_getstorageids (PTPParams* params, PTPStorageIDs* storageids); +uint16_t ptp_getstorageinfo (PTPParams* params, uint32_t storageid, + PTPStorageInfo* storageinfo); + +uint16_t ptp_getobjecthandles (PTPParams* params, uint32_t storage, + uint32_t objectformatcode, + uint32_t associationOH, + PTPObjectHandles* objecthandles); + +uint16_t ptp_getobjectinfo (PTPParams *params, uint32_t handle, + PTPObjectInfo* objectinfo); + +uint16_t ptp_getobject (PTPParams *params, uint32_t handle, + char** object); +uint16_t ptp_getthumb (PTPParams *params, uint32_t handle, + char** object); + +uint16_t ptp_deleteobject (PTPParams* params, uint32_t handle, + uint32_t ofc); + +uint16_t ptp_sendobjectinfo (PTPParams* params, uint32_t* store, + uint32_t* parenthandle, uint32_t* handle, + PTPObjectInfo* objectinfo); +uint16_t ptp_sendobject (PTPParams* params, char* object, + uint32_t size); + +uint16_t ptp_initiatecapture (PTPParams* params, uint32_t storageid, + uint32_t ofc); + +uint16_t ptp_getdevicepropdesc (PTPParams* params, uint16_t propcode, + PTPDevicePropDesc *devicepropertydesc); +uint16_t ptp_getdevicepropvalue (PTPParams* params, uint16_t propcode, + void** value, uint16_t datatype); +uint16_t ptp_setdevicepropvalue (PTPParams* params, uint16_t propcode, + void* value, uint16_t datatype); + + +uint16_t ptp_ek_sendfileobjectinfo (PTPParams* params, uint32_t* store, + uint32_t* parenthandle, uint32_t* handle, + PTPObjectInfo* objectinfo); +uint16_t ptp_ek_sendfileobject (PTPParams* params, char* object, + uint32_t size); + +/* Canon PTP extensions */ + +uint16_t ptp_canon_getobjectsize (PTPParams* params, uint32_t handle, + uint32_t p2, uint32_t* size, uint32_t* rp2); + +uint16_t ptp_canon_startshootingmode (PTPParams* params); +uint16_t ptp_canon_endshootingmode (PTPParams* params); + +uint16_t ptp_canon_viewfinderon (PTPParams* params); +uint16_t ptp_canon_viewfinderoff (PTPParams* params); + +uint16_t ptp_canon_reflectchanges (PTPParams* params, uint32_t p1); +uint16_t ptp_canon_checkevent (PTPParams* params, + PTPUSBEventContainer* event, int* isevent); +uint16_t ptp_canon_focuslock (PTPParams* params); +uint16_t ptp_canon_focusunlock (PTPParams* params); +uint16_t ptp_canon_initiatecaptureinmemory (PTPParams* params); +uint16_t ptp_canon_getpartialobject (PTPParams* params, uint32_t handle, + uint32_t offset, uint32_t size, + uint32_t pos, char** block, + uint32_t* readnum); +uint16_t ptp_canon_getviewfinderimage (PTPParams* params, char** image, + uint32_t* size); +uint16_t ptp_canon_getchanges (PTPParams* params, uint16_t** props, + uint32_t* propnum); +uint16_t ptp_canon_getfolderentries (PTPParams* params, uint32_t store, + uint32_t p2, uint32_t parenthandle, + uint32_t handle, + PTPCANONFolderEntry** entries, + uint32_t* entnum); + +/* Nikon extensions */ +uint16_t ptp_nikon_setcontrolmode (PTPParams* params, uint32_t mode); +uint16_t ptp_nikon_directcapture (PTPParams* params, uint32_t unknown); +uint16_t ptp_nikon_checkevent (PTPParams* params, + PTPUSBEventContainer** event, uint16_t* evnum); +uint16_t ptp_nikon_keepalive (PTPParams* params); + + +/* Non PTP protocol functions */ +int ptp_operation_issupported (PTPParams* params, uint16_t operation); +int ptp_property_issupported (PTPParams* params, uint16_t property); + +void ptp_free_devicepropdesc (PTPDevicePropDesc* dpd); +void ptp_perror (PTPParams* params, uint16_t error); +const char* +ptp_get_datatype_name (PTPParams* params, uint16_t dt); +const char* +ptp_get_operation_name (PTPParams* params, uint16_t oc); +const char* +ptp_prop_getname (PTPParams* params, uint16_t dpc); + +/* Properties handling functions */ +const char* ptp_prop_getdesc (PTPParams* params, PTPDevicePropDesc *dpd, + void *val); +const char* ptp_prop_getdescbystring + (PTPParams* params,PTPDevicePropDesc *dpd, + const char *strval); + +const char * ptp_prop_tostr (PTPParams* params, PTPDevicePropDesc *dpd, + void *val); +uint16_t ptp_prop_getcodebyname (PTPParams* params, char* propname); +const char* ptp_prop_getvalbyname + (PTPParams* params, char* name, uint16_t dpc); + +enum { + PTP_CHDK_Shutdown = 0, // param2 is 0 (hard), 1 (soft), 2 (reboot) or 3 (reboot fw update) + // if param2 == 3, then filename of fw update is send as data (empty for default) + PTP_CHDK_GetMemory, // param2 is base address (not NULL; circumvent by taking 0xFFFFFFFF and size+1) + // param3 is size (in bytes) + // return data is memory block + PTP_CHDK_SetMemoryLong, // param2 is address + // param3 is value + PTP_CHDK_CallFunction, // data is array of function pointer and (long) arguments (max: 10 args) + // return param1 is return value + PTP_CHDK_GetPropCase, // param2 is base id + // param3 is number of properties + // return data is array of longs + PTP_CHDK_GetParamData, // param2 is base id + // param3 is number of parameters + // return data is sequence of strings prefixed by their length (as long) + PTP_CHDK_TempData, // data is data to be stored for later + PTP_CHDK_UploadFile, // data is 4-byte length of filename, followed by filename and contents + PTP_CHDK_DownloadFile, // preceded by PTP_CHDK_TempData with filename + // return data are file contents + PTP_CHDK_SwitchMode, // param2 is 0 (playback) or 1 (record) + PTP_CHDK_ExecuteLUA, // data is script to be executed +} ptp_chdk_command; + +int ptp_chdk_shutdown_hard(PTPParams* params, PTPDeviceInfo* deviceinfo); +int ptp_chdk_shutdown_soft(PTPParams* params, PTPDeviceInfo* deviceinfo); +int ptp_chdk_reboot(PTPParams* params, PTPDeviceInfo* deviceinfo); +int ptp_chdk_reboot_fw_update(char *path, PTPParams* params, PTPDeviceInfo* deviceinfo); +char* ptp_chdk_get_memory(int start, int num, PTPParams* params, PTPDeviceInfo* deviceinfo); +int ptp_chdk_set_memory_long(int addr, int val, PTPParams* params, PTPDeviceInfo* deviceinfo); +int ptp_chdk_call(int *args, int size, int *ret, PTPParams* params, PTPDeviceInfo* deviceinfo); +int* ptp_chdk_get_propcase(int start, int num, PTPParams* params, PTPDeviceInfo* deviceinfo); +char* ptp_chdk_get_paramdata(int start, int num, PTPParams* params, PTPDeviceInfo* deviceinfo); +int ptp_chdk_upload(char *local_fn, char *remote_fn, PTPParams* params, PTPDeviceInfo* deviceinfo); +int ptp_chdk_download(char *remote_fn, char *local_fn, PTPParams* params, PTPDeviceInfo* deviceinfo); +int ptp_chdk_switch_mode(int mode, PTPParams* params, PTPDeviceInfo* deviceinfo); +int ptp_chdk_exec_lua(char *script, PTPParams* params, PTPDeviceInfo* deviceinfo); + + +#endif /* __PTP_H__ */ diff --git a/tools/ptpcam/ptpcam.c b/tools/ptpcam/ptpcam.c new file mode 100644 index 00000000..b529d0cb --- /dev/null +++ b/tools/ptpcam/ptpcam.c @@ -0,0 +1,2781 @@ +/* ptpcam.c + * + * Copyright (C) 2001-2005 Mariusz Woloszyn + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "ptp.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include + +#ifdef WIN32 +#define usleep(usec) Sleep((usec)/1000) +#define sleep(sec) Sleep(sec) +#endif + +#ifdef ENABLE_NLS +# include +# undef _ +# define _(String) dgettext (GETTEXT_PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + +#include "ptpcam.h" + +/* some defines comes here */ + +/* USB interface class */ +#ifndef USB_CLASS_PTP +#define USB_CLASS_PTP 6 +#endif + +/* USB control message data phase direction */ +#ifndef USB_DP_HTD +#define USB_DP_HTD (0x00 << 7) /* host to device */ +#endif +#ifndef USB_DP_DTH +#define USB_DP_DTH (0x01 << 7) /* device to host */ +#endif + +/* PTP class specific requests */ +#ifndef USB_REQ_DEVICE_RESET +#define USB_REQ_DEVICE_RESET 0x66 +#endif +#ifndef USB_REQ_GET_DEVICE_STATUS +#define USB_REQ_GET_DEVICE_STATUS 0x67 +#endif + +/* USB Feature selector HALT */ +#ifndef USB_FEATURE_HALT +#define USB_FEATURE_HALT 0x00 +#endif + +/* OUR APPLICATION USB URB (2MB) ;) */ +#define PTPCAM_USB_URB 2097152 + +#define USB_TIMEOUT 5000 +#define USB_CAPTURE_TIMEOUT 20000 + +/* one global variable (yes, I know it sucks) */ +short verbose=0; +/* the other one, it sucks definitely ;) */ +int ptpcam_usb_timeout = USB_TIMEOUT; + +/* we need it for a proper signal handling :/ */ +PTPParams* globalparams; + + +void +usage() +{ + printf("USAGE: ptpcam [OPTION]\n\n"); +} + +void +help() +{ + printf("USAGE: ptpcam [OPTION]\n\n"); + printf("Options:\n" + " --bus=BUS-NUMBER USB bus number\n" + " --dev=DEV-NUMBER USB assigned device number\n" + " -r, --reset Reset the device\n" + " -l, --list-devices List all PTP devices\n" + " -i, --info Show device info\n" + " -o, --list-operations List supported operations\n" + " -p, --list-properties List all PTP device properties\n" + " " + "(e.g. focus mode, focus distance, etc.)\n" + " -s, --show-property=NUMBER Display property details " + "(or set its value,\n" + " if used in conjunction with --val)\n" + " --set-property=NUMBER Set property value (--val required)\n" + " --set=PROP-NAME Set property by name (abbreviations allowed)\n" + " --val=VALUE Property value (numeric for --set-property and\n" + " string or numeric for --set)\n" + " --show-all-properties Show all properties values\n" + " --show-unknown-properties Show unknown properties values\n" + " -L, --list-files List all files\n" + " -g, --get-file=HANDLE Get file by given handler\n" + " -G, --get-all-files Get all files\n" + " --overwrite Force file overwrite while saving" + "to disk\n" + " -d, --delete-object=HANDLE Delete object (file) by given handle\n" + " -D, --delete-all-files Delete all files form camera\n" + " -c, --capture Initiate capture\n" + " --nikon-ic, --nic Initiate Nikon Direct Capture (no download!)\n" + " --nikon-dc, --ndc Initiate Nikon Direct Capture and download\n" + " --loop-capture=N Perform N times capture/get/delete\n" + " -f, --force Talk to non PTP devices\n" + " -v, --verbose Be verbose (print more debug)\n" + " -h, --help Print this help message\n" + "\n"); +} + +void +ptpcam_siginthandler(int signum) +{ + PTP_USB* ptp_usb=(PTP_USB *)globalparams->data; + struct usb_device *dev=usb_device(ptp_usb->handle); + + if (signum==SIGINT) + { + /* hey it's not that easy though... but at least we can try! */ + printf("Got SIGINT, trying to clean up and close...\n"); + usleep(5000); + close_camera (ptp_usb, globalparams, dev); + exit (-1); + } +} + +static short +ptp_read_func (unsigned char *bytes, unsigned int size, void *data) +{ + int result=-1; + PTP_USB *ptp_usb=(PTP_USB *)data; + int toread=0; + signed long int rbytes=size; + + do { + bytes+=toread; + if (rbytes>PTPCAM_USB_URB) + toread = PTPCAM_USB_URB; + else + toread = rbytes; + result=USB_BULK_READ(ptp_usb->handle, ptp_usb->inep,(char *)bytes, toread,ptpcam_usb_timeout); + /* sometimes retry might help */ + if (result==0) + result=USB_BULK_READ(ptp_usb->handle, ptp_usb->inep,(char *)bytes, toread,ptpcam_usb_timeout); + if (result < 0) + break; + rbytes-=PTPCAM_USB_URB; + } while (rbytes>0); + + if (result >= 0) { + return (PTP_RC_OK); + } + else + { + if (verbose) perror("usb_bulk_read"); + return PTP_ERROR_IO; + } +} + +static short +ptp_write_func (unsigned char *bytes, unsigned int size, void *data) +{ + int result; + PTP_USB *ptp_usb=(PTP_USB *)data; + + result=USB_BULK_WRITE(ptp_usb->handle,ptp_usb->outep,(char *)bytes,size,ptpcam_usb_timeout); + if (result >= 0) + return (PTP_RC_OK); + else + { + if (verbose) perror("usb_bulk_write"); + return PTP_ERROR_IO; + } +} + +/* XXX this one is suposed to return the number of bytes read!!! */ +static short +ptp_check_int (unsigned char *bytes, unsigned int size, void *data) +{ + int result; + PTP_USB *ptp_usb=(PTP_USB *)data; + + result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)bytes,size,ptpcam_usb_timeout); + if (result==0) + result=USB_BULK_READ(ptp_usb->handle, ptp_usb->intep,(char *)bytes,size,ptpcam_usb_timeout); + if (verbose>2) fprintf (stderr, "USB_BULK_READ returned %i, size=%i\n", result, size); + + if (result >= 0) { + return result; + } else { + if (verbose) perror("ptp_check_int"); + return result; + } +} + + +void +ptpcam_debug (void *data, const char *format, va_list args); +void +ptpcam_debug (void *data, const char *format, va_list args) +{ + if (verbose<2) return; + vfprintf (stderr, format, args); + fprintf (stderr,"\n"); + fflush(stderr); +} + +void +ptpcam_error (void *data, const char *format, va_list args); +void +ptpcam_error (void *data, const char *format, va_list args) +{ +/* if (!verbose) return; */ + vfprintf (stderr, format, args); + fprintf (stderr,"\n"); + fflush(stderr); +} + + + +void +init_ptp_usb (PTPParams* params, PTP_USB* ptp_usb, struct usb_device* dev) +{ + usb_dev_handle *device_handle; + + params->write_func=ptp_write_func; + params->read_func=ptp_read_func; + params->check_int_func=ptp_check_int; + params->check_int_fast_func=ptp_check_int; + params->error_func=ptpcam_error; + params->debug_func=ptpcam_debug; + params->sendreq_func=ptp_usb_sendreq; + params->senddata_func=ptp_usb_senddata; + params->getresp_func=ptp_usb_getresp; + params->getdata_func=ptp_usb_getdata; + params->data=ptp_usb; + params->transaction_id=0; + params->byteorder = PTP_DL_LE; + + if ((device_handle=usb_open(dev))){ + if (!device_handle) { + perror("usb_open()"); + exit(0); + } + ptp_usb->handle=device_handle; + usb_set_configuration(device_handle, dev->config->bConfigurationValue); + usb_claim_interface(device_handle, + dev->config->interface->altsetting->bInterfaceNumber); + } + globalparams=params; +} + +void +clear_stall(PTP_USB* ptp_usb) +{ + uint16_t status=0; + int ret; + + /* check the inep status */ + ret=usb_get_endpoint_status(ptp_usb,ptp_usb->inep,&status); + if (ret<0) perror ("inep: usb_get_endpoint_status()"); + /* and clear the HALT condition if happend */ + else if (status) { + printf("Resetting input pipe!\n"); + ret=usb_clear_stall_feature(ptp_usb,ptp_usb->inep); + /*usb_clear_halt(ptp_usb->handle,ptp_usb->inep); */ + if (ret<0)perror ("usb_clear_stall_feature()"); + } + status=0; + + /* check the outep status */ + ret=usb_get_endpoint_status(ptp_usb,ptp_usb->outep,&status); + if (ret<0) perror ("outep: usb_get_endpoint_status()"); + /* and clear the HALT condition if happend */ + else if (status) { + printf("Resetting output pipe!\n"); + ret=usb_clear_stall_feature(ptp_usb,ptp_usb->outep); + /*usb_clear_halt(ptp_usb->handle,ptp_usb->outep); */ + if (ret<0)perror ("usb_clear_stall_feature()"); + } + + /*usb_clear_halt(ptp_usb->handle,ptp_usb->intep); */ +} + +void +close_usb(PTP_USB* ptp_usb, struct usb_device* dev) +{ + //clear_stall(ptp_usb); + usb_release_interface(ptp_usb->handle, + dev->config->interface->altsetting->bInterfaceNumber); + usb_reset(ptp_usb->handle); + usb_close(ptp_usb->handle); +} + + +struct usb_bus* +init_usb() +{ + usb_init(); + usb_find_busses(); + usb_find_devices(); + return (usb_get_busses()); +} + +/* + find_device() returns the pointer to a usb_device structure matching + given busn, devicen numbers. If any or both of arguments are 0 then the + first matching PTP device structure is returned. +*/ +struct usb_device* +find_device (int busn, int devicen, short force); +struct usb_device* +find_device (int busn, int devn, short force) +{ + struct usb_bus *bus; + struct usb_device *dev; + + bus=init_usb(); + for (; bus; bus = bus->next) + for (dev = bus->devices; dev; dev = dev->next) + if (dev->config) + if ((dev->config->interface->altsetting->bInterfaceClass== + USB_CLASS_PTP)||force) + if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB) + { + int curbusn, curdevn; + + curbusn=strtol(bus->dirname,NULL,10); + curdevn=strtol(dev->filename,NULL,10); + + if (devn==0) { + if (busn==0) return dev; + if (curbusn==busn) return dev; + } else { + if ((busn==0)&&(curdevn==devn)) return dev; + if ((curbusn==busn)&&(curdevn==devn)) return dev; + } + } + return NULL; +} + +void +find_endpoints(struct usb_device *dev, int* inep, int* outep, int* intep); +void +find_endpoints(struct usb_device *dev, int* inep, int* outep, int* intep) +{ + int i,n; + struct usb_endpoint_descriptor *ep; + + ep = dev->config->interface->altsetting->endpoint; + n=dev->config->interface->altsetting->bNumEndpoints; + + for (i=0;i1) + fprintf(stderr, "Found inep: 0x%02x\n",*inep); + } + if ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)==0) + { + *outep=ep[i].bEndpointAddress; + if (verbose>1) + fprintf(stderr, "Found outep: 0x%02x\n",*outep); + } + } else if ((ep[i].bmAttributes==USB_ENDPOINT_TYPE_INTERRUPT) && + ((ep[i].bEndpointAddress&USB_ENDPOINT_DIR_MASK)== + USB_ENDPOINT_DIR_MASK)) + { + *intep=ep[i].bEndpointAddress; + if (verbose>1) + fprintf(stderr, "Found intep: 0x%02x\n",*intep); + } + } +} + +int +open_camera (int busn, int devn, short force, PTP_USB *ptp_usb, PTPParams *params, struct usb_device **dev) +{ +#ifdef DEBUG + printf("dev %i\tbus %i\n",devn,busn); +#endif + + *dev=find_device(busn,devn,force); + if (*dev==NULL) { + fprintf(stderr,"could not find any device matching given " + "bus/dev numbers\n"); + return -1; + } + find_endpoints(*dev,&ptp_usb->inep,&ptp_usb->outep,&ptp_usb->intep); + + init_ptp_usb(params, ptp_usb, *dev); + if (ptp_opensession(params,1)!=PTP_RC_OK) { + fprintf(stderr,"ERROR: Could not open session!\n"); + close_usb(ptp_usb, *dev); + return -1; + } + if (ptp_getdeviceinfo(params,¶ms->deviceinfo)!=PTP_RC_OK) { + fprintf(stderr,"ERROR: Could not get device info!\n"); + close_usb(ptp_usb, *dev); + return -1; + } + return 0; +} + +void +close_camera (PTP_USB *ptp_usb, PTPParams *params, struct usb_device *dev) +{ + if (ptp_closesession(params)!=PTP_RC_OK) + fprintf(stderr,"ERROR: Could not close session!\n"); + close_usb(ptp_usb, dev); +} + + +void +list_devices(short force) +{ + struct usb_bus *bus; + struct usb_device *dev; + int found=0; + + + bus=init_usb(); + for (; bus; bus = bus->next) + for (dev = bus->devices; dev; dev = dev->next) { + /* if it's a PTP device try to talk to it */ + if (dev->config) + if ((dev->config->interface->altsetting->bInterfaceClass== + USB_CLASS_PTP)||force) + if (dev->descriptor.bDeviceClass!=USB_CLASS_HUB) + { + PTPParams params; + PTP_USB ptp_usb; + PTPDeviceInfo deviceinfo; + + if (!found){ + printf("\nListing devices...\n"); + printf("bus/dev\tvendorID/prodID\tdevice model\n"); + found=1; + } + + find_endpoints(dev,&ptp_usb.inep,&ptp_usb.outep, + &ptp_usb.intep); + init_ptp_usb(¶ms, &ptp_usb, dev); + + CC(ptp_opensession (¶ms,1), + "Could not open session!\n" + "Try to reset the camera.\n"); + CC(ptp_getdeviceinfo (¶ms, &deviceinfo), + "Could not get device info!\n"); + + printf("%s/%s\t0x%04X/0x%04X\t%s\n", + bus->dirname, dev->filename, + dev->descriptor.idVendor, + dev->descriptor.idProduct, deviceinfo.Model); + + CC(ptp_closesession(¶ms), + "Could not close session!\n"); + close_usb(&ptp_usb, dev); + } + } + if (!found) printf("\nFound no PTP devices\n"); + printf("\n"); +} + +void +show_info (int busn, int devn, short force) +{ + PTPParams params; + PTP_USB ptp_usb; + struct usb_device *dev; + + printf("\nCamera information\n"); + printf("==================\n"); + if (open_camera(busn, devn, force, &ptp_usb, ¶ms, &dev)<0) + return; + printf("Model: %s\n",params.deviceinfo.Model); + printf(" manufacturer: %s\n",params.deviceinfo.Manufacturer); + printf(" serial number: '%s'\n",params.deviceinfo.SerialNumber); + printf(" device version: %s\n",params.deviceinfo.DeviceVersion); + printf(" extension ID: 0x%08lx\n",(long unsigned) + params.deviceinfo.VendorExtensionID); + printf(" extension description: %s\n", + params.deviceinfo.VendorExtensionDesc); + printf(" extension version: 0x%04x\n", + params.deviceinfo.VendorExtensionVersion); + printf("\n"); + close_camera(&ptp_usb, ¶ms, dev); +} + +void +capture_image (int busn, int devn, short force) +{ + PTPParams params; + PTP_USB ptp_usb; + PTPContainer event; + int ExposureTime=0; + struct usb_device *dev; + short ret; + + printf("\nInitiating captue...\n"); + if (open_camera(busn, devn, force, &ptp_usb, ¶ms, &dev)<0) + return; + + if (!ptp_operation_issupported(¶ms, PTP_OC_InitiateCapture)) + { + printf ("Your camera does not support InitiateCapture operation!\nSorry, blame the %s!\n", params.deviceinfo.Manufacturer); + goto out; + } + + /* obtain exposure time in miliseconds */ + if (ptp_property_issupported(¶ms, PTP_DPC_ExposureTime)) + { + PTPDevicePropDesc dpd; + memset(&dpd,0,sizeof(dpd)); + ret=ptp_getdevicepropdesc(¶ms,PTP_DPC_ExposureTime,&dpd); + if (ret==PTP_RC_OK) ExposureTime=(*(int32_t*)(dpd.CurrentValue))/10; + } + + /* adjust USB timeout */ + if (ExposureTime>USB_TIMEOUT) ptpcam_usb_timeout=ExposureTime; + + CR(ptp_initiatecapture (¶ms, 0x0, 0), "Could not capture.\n"); + + ret=ptp_usb_event_wait(¶ms,&event); + if (ret!=PTP_RC_OK) goto err; + if (verbose) printf ("Event received %08x, ret=%x\n", event.Code, ret); + if (event.Code==PTP_EC_CaptureComplete) { + printf ("Camera reported 'capture completed' but the object information is missing.\n"); + goto out; + } + + while (event.Code==PTP_EC_ObjectAdded) { + printf ("Object added 0x%08lx\n", (long unsigned) event.Param1); + if (ptp_usb_event_wait(¶ms, &event)!=PTP_RC_OK) + goto err; + if (verbose) printf ("Event received %08x, ret=%x\n", event.Code, ret); + if (event.Code==PTP_EC_CaptureComplete) { + printf ("Capture completed successfully!\n"); + goto out; + } + } + +err: + printf("Events receiving error. Capture status unknown.\n"); +out: + + ptpcam_usb_timeout=USB_TIMEOUT; + close_camera(&ptp_usb, ¶ms, dev); +} + +void +loop_capture (int busn, int devn, short force, int n, int overwrite) +{ + PTPParams params; + PTP_USB ptp_usb; + PTPContainer event; + struct usb_device *dev; + int file; + PTPObjectInfo oi; + uint32_t handle=0; + char *image; + int ret; + char *filename; + + if (open_camera(busn, devn, force, &ptp_usb, ¶ms, &dev)<0) + return; + + /* capture timeout should be longer */ + ptpcam_usb_timeout=USB_CAPTURE_TIMEOUT; + + printf("Camera: %s\n",params.deviceinfo.Model); + + + /* local loop */ + while (n>0) { + /* capture */ + printf("\nInitiating captue...\n"); + CR(ptp_initiatecapture (¶ms, 0x0, 0),"Could not capture\n"); + n--; + + ret=ptp_usb_event_wait(¶ms,&event); + if (verbose) printf ("Event received %08x, ret=%x\n", event.Code, ret); + if (ret!=PTP_RC_OK) goto err; + if (event.Code==PTP_EC_CaptureComplete) { + printf ("CANNOT DOWNLOAD: got 'capture completed' but the object information is missing.\n"); + goto out; + } + + while (event.Code==PTP_EC_ObjectAdded) { + printf ("Object added 0x%08lx\n",(long unsigned) event.Param1); + handle=event.Param1; + if (ptp_usb_event_wait(¶ms, &event)!=PTP_RC_OK) + goto err; + if (verbose) printf ("Event received %08x, ret=%x\n", event.Code, ret); + if (event.Code==PTP_EC_CaptureComplete) + goto download; + } +download: + + memset(&oi, 0, sizeof(PTPObjectInfo)); + if (verbose) printf ("Downloading: 0x%08lx\n",(long unsigned) handle); + if ((ret=ptp_getobjectinfo(¶ms,handle, &oi))!=PTP_RC_OK){ + fprintf(stderr,"ERROR: Could not get object info\n"); + ptp_perror(¶ms,ret); + if (ret==PTP_ERROR_IO) clear_stall(&ptp_usb); + continue; + } + + if (oi.ObjectFormat == PTP_OFC_Association) + goto out; + filename=(oi.Filename); +#ifdef WIN32 + goto out; +#else + file=open(filename, (overwrite==OVERWRITE_EXISTING?0:O_EXCL)|O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP); +#endif + if (file==-1) { + if (errno==EEXIST) { + printf("Skipping file: \"%s\", file exists!\n",filename); + goto out; + } + perror("open"); + goto out; + } + lseek(file,oi.ObjectCompressedSize-1,SEEK_SET); + ret=write(file,"",1); + if (ret==-1) { + perror("write"); + goto out; + } +#ifndef WIN32 + image=mmap(0,oi.ObjectCompressedSize,PROT_READ|PROT_WRITE,MAP_SHARED, + file,0); + if (image==MAP_FAILED) { + perror("mmap"); + close(file); + goto out; + } +#endif + printf ("Saving file: \"%s\" ",filename); + fflush(NULL); + ret=ptp_getobject(¶ms,handle,&image); + munmap(image,oi.ObjectCompressedSize); + close(file); + if (ret!=PTP_RC_OK) { + printf ("error!\n"); + ptp_perror(¶ms,ret); + if (ret==PTP_ERROR_IO) clear_stall(&ptp_usb); + } else { + /* and delete from camera! */ + printf("is done...\nDeleting from camera.\n"); + CR(ptp_deleteobject(¶ms, handle,0), + "Could not delete object\n"); + printf("Object 0x%08lx (%s) deleted.\n",(long unsigned) handle, oi.Filename); + } +out: + ; + } +err: + + ptpcam_usb_timeout=USB_TIMEOUT; + close_camera(&ptp_usb, ¶ms, dev); +} + +void +nikon_initiate_dc (int busn, int devn, short force) +{ + PTPParams params; + PTP_USB ptp_usb; + struct usb_device *dev; + uint16_t result; + + if (open_camera(busn, devn, force, &ptp_usb, ¶ms, &dev)<0) + return; + + printf("Camera: %s\n",params.deviceinfo.Model); + printf("\nInitiating direct captue...\n"); + + if (params.deviceinfo.VendorExtensionID!=PTP_VENDOR_NIKON) + { + printf ("Your camera is not Nikon!\nDo not buy from %s!\n",params.deviceinfo.Manufacturer); + goto out; + } + + if (!ptp_operation_issupported(¶ms,PTP_OC_NIKON_DirectCapture)) { + printf ("Sorry, your camera dows not support Nikon DirectCapture!\nDo not buy from %s!\n",params.deviceinfo.Manufacturer); + goto out; + } + + /* perform direct capture */ + result=ptp_nikon_directcapture (¶ms, 0xffffffff); + if (result!=PTP_RC_OK) { + ptp_perror(¶ms,result); + fprintf(stderr,"ERROR: Could not capture.\n"); + if (result!=PTP_RC_StoreFull) { + close_camera(&ptp_usb, ¶ms, dev); + return; + } + } + usleep(300*1000); +out: + close_camera(&ptp_usb, ¶ms, dev); + +} + +void +nikon_direct_capture (int busn, int devn, short force, char* filename,int overwrite) +{ + PTPParams params; + PTP_USB ptp_usb; + struct usb_device *dev; + uint16_t result; + uint16_t nevent=0; + PTPUSBEventContainer* events=NULL; + int ExposureTime=0; /* exposure time in miliseconds */ + int BurstNumber=1; + PTPDevicePropDesc dpd; + PTPObjectInfo oi; + int i; + + if (open_camera(busn, devn, force, &ptp_usb, ¶ms, &dev)<0) + return; + + printf("Camera: %s\n",params.deviceinfo.Model); + + if ((result=ptp_getobjectinfo(¶ms,0xffff0001, &oi))==PTP_RC_OK) { + if (filename==NULL) filename=oi.Filename; + save_object(¶ms, 0xffff0001, filename, oi, overwrite); + goto out; + } + + printf("\nInitiating direct captue...\n"); + + if (params.deviceinfo.VendorExtensionID!=PTP_VENDOR_NIKON) + { + printf ("Your camera is not Nikon!\nDo not buy from %s!\n",params.deviceinfo.Manufacturer); + goto out; + } + + if (!ptp_operation_issupported(¶ms,PTP_OC_NIKON_DirectCapture)) { + printf ("Sorry, your camera dows not support Nikon DirectCapture!\nDo not buy from %s!\n",params.deviceinfo.Manufacturer); + goto out; + } + + /* obtain exposure time in miliseconds */ + memset(&dpd,0,sizeof(dpd)); + result=ptp_getdevicepropdesc(¶ms,PTP_DPC_ExposureTime,&dpd); + if (result==PTP_RC_OK) ExposureTime=(*(int32_t*)(dpd.CurrentValue))/10; + + /* obtain burst number */ + memset(&dpd,0,sizeof(dpd)); + result=ptp_getdevicepropdesc(¶ms,PTP_DPC_BurstNumber,&dpd); + if (result==PTP_RC_OK) BurstNumber=*(uint16_t*)(dpd.CurrentValue); +/* + if ((result=ptp_getobjectinfo(¶ms,0xffff0001, &oi))==PTP_RC_OK) + { + if (filename==NULL) filename=oi.Filename; + save_object(¶ms, 0xffff0001, filename, oi, overwrite); + ptp_nikon_keepalive(¶ms); + ptp_nikon_keepalive(¶ms); + ptp_nikon_keepalive(¶ms); + ptp_nikon_keepalive(¶ms); + } +*/ + + /* perform direct capture */ + result=ptp_nikon_directcapture (¶ms, 0xffffffff); + if (result!=PTP_RC_OK) { + ptp_perror(¶ms,result); + fprintf(stderr,"ERROR: Could not capture.\n"); + if (result!=PTP_RC_StoreFull) { + close_camera(&ptp_usb, ¶ms, dev); + return; + } + } + if (BurstNumber>1) printf("Capturing %i frames in burst.\n",BurstNumber); + + /* sleep in case of exposure longer than 1/100 */ + if (ExposureTime>10) { + printf ("sleeping %i miliseconds\n", ExposureTime); + usleep (ExposureTime*1000); + } + + while (BurstNumber>0) { + +#if 0 /* Is this really needed??? */ + ptp_nikon_keepalive(¶ms); +#endif + + result=ptp_nikon_checkevent (¶ms, &events, &nevent); + if (result != PTP_RC_OK) { + fprintf(stderr, "Error checking Nikon events\n"); + ptp_perror(¶ms,result); + goto out; + } + for(i=0;i1) printf("Capturing %i frames in burst.\n",BurstNumber); +#if 0 + /* sleep in case of exposure longer than 1/100 */ + if (ExposureTime>10) { + printf ("sleeping %i miliseconds\n", ExposureTime); + usleep (ExposureTime*1000); + } +#endif + + while (num>0) { + /* perform direct capture */ + result=ptp_nikon_directcapture (¶ms, 0xffffffff); + if (result!=PTP_RC_OK) { + if (result==PTP_ERROR_IO) { + close_camera(&ptp_usb, ¶ms, dev); + return; + } + } + +#if 0 /* Is this really needed??? */ + ptp_nikon_keepalive(¶ms); +#endif + ptp_nikon_keepalive(¶ms); + ptp_nikon_keepalive(¶ms); + ptp_nikon_keepalive(¶ms); + ptp_nikon_keepalive(¶ms); + + result=ptp_nikon_checkevent (¶ms, &events, &nevent); + if (result != PTP_RC_OK) goto out; + + for(i=0;itm_year+1900, tm->tm_mon+1,tm->tm_mday, + tm->tm_hour, tm->tm_min, + oi.Filename); + } + printf("\n"); + close_camera(&ptp_usb, ¶ms, dev); +} + +void +delete_object (int busn, int devn, short force, uint32_t handle) +{ + PTPParams params; + PTP_USB ptp_usb; + struct usb_device *dev; + PTPObjectInfo oi; + + if (open_camera(busn, devn, force, &ptp_usb, ¶ms, &dev)<0) + return; + CR(ptp_getobjectinfo(¶ms,handle,&oi), + "Could not get object info\n"); + CR(ptp_deleteobject(¶ms, handle,0), "Could not delete object\n"); + printf("\nObject 0x%08lx (%s) deleted.\n",(long unsigned) handle, oi.Filename); + close_camera(&ptp_usb, ¶ms, dev); +} + +void +delete_all_files (int busn, int devn, short force) +{ + PTPParams params; + PTP_USB ptp_usb; + struct usb_device *dev; + PTPObjectInfo oi; + uint32_t handle; + int i; + int ret; + + if (open_camera(busn, devn, force, &ptp_usb, ¶ms, &dev)<0) + return; + printf("Camera: %s\n",params.deviceinfo.Model); + CR(ptp_getobjecthandles (¶ms,0xffffffff, 0x000000, 0x000000, + ¶ms.handles),"Could not get object handles\n"); + + for (i=0; idata)); + } else { + printf("is done.\n"); + } +out: + return; +} + +void +get_save_object (PTPParams *params, uint32_t handle, char* filename, int overwrite) +{ + + PTPObjectInfo oi; + int ret; + + memset(&oi, 0, sizeof(PTPObjectInfo)); + if (verbose) + printf ("Handle: 0x%08lx\n",(long unsigned) handle); + if ((ret=ptp_getobjectinfo(params,handle, &oi))!=PTP_RC_OK) { + fprintf(stderr, "Could not get object info\n"); + ptp_perror(params,ret); + if (ret==PTP_ERROR_IO) clear_stall((PTP_USB *)(params->data)); + goto out; + } + if (oi.ObjectFormat == PTP_OFC_Association) + goto out; + if (filename==NULL) filename=(oi.Filename); + + save_object(params, handle, filename, oi, overwrite); +out: + return; + +} + +void +get_file (int busn, int devn, short force, uint32_t handle, char* filename, +int overwrite) +{ + PTPParams params; + PTP_USB ptp_usb; + struct usb_device *dev; + + if (open_camera(busn, devn, force, &ptp_usb, ¶ms, &dev)<0) + return; + printf("Camera: %s\n",params.deviceinfo.Model); + + get_save_object(¶ms, handle, filename, overwrite); + + close_camera(&ptp_usb, ¶ms, dev); + +} + +void +get_all_files (int busn, int devn, short force, int overwrite) +{ + PTPParams params; + PTP_USB ptp_usb; + struct usb_device *dev; + int i; + + if (open_camera(busn, devn, force, &ptp_usb, ¶ms, &dev)<0) + return; + printf("Camera: %s\n",params.deviceinfo.Model); + + CR(ptp_getobjecthandles (¶ms,0xffffffff, 0x000000, 0x000000, + ¶ms.handles),"Could not get object handles\n"); + + for (i=0; ihandle, + USB_DP_DTH|USB_RECIP_ENDPOINT, USB_REQ_GET_STATUS, + USB_FEATURE_HALT, ep, (char *)status, 2, 3000)); +} + +int +usb_clear_stall_feature(PTP_USB* ptp_usb, int ep) +{ + + return (usb_control_msg(ptp_usb->handle, + USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, USB_FEATURE_HALT, + ep, NULL, 0, 3000)); +} + +int +usb_ptp_get_device_status(PTP_USB* ptp_usb, uint16_t* devstatus); +int +usb_ptp_get_device_status(PTP_USB* ptp_usb, uint16_t* devstatus) +{ + return (usb_control_msg(ptp_usb->handle, + USB_DP_DTH|USB_TYPE_CLASS|USB_RECIP_INTERFACE, + USB_REQ_GET_DEVICE_STATUS, 0, 0, + (char *)devstatus, 4, 3000)); +} + +int +usb_ptp_device_reset(PTP_USB* ptp_usb); +int +usb_ptp_device_reset(PTP_USB* ptp_usb) +{ + return (usb_control_msg(ptp_usb->handle, + USB_TYPE_CLASS|USB_RECIP_INTERFACE, + USB_REQ_DEVICE_RESET, 0, 0, NULL, 0, 3000)); +} + +void +reset_device (int busn, int devn, short force); +void +reset_device (int busn, int devn, short force) +{ + PTPParams params; + PTP_USB ptp_usb; + struct usb_device *dev; + uint16_t status; + uint16_t devstatus[2] = {0,0}; + int ret; + +#ifdef DEBUG + printf("dev %i\tbus %i\n",devn,busn); +#endif + dev=find_device(busn,devn,force); + if (dev==NULL) { + fprintf(stderr,"could not find any device matching given " + "bus/dev numbers\n"); + exit(-1); + } + find_endpoints(dev,&ptp_usb.inep,&ptp_usb.outep,&ptp_usb.intep); + + init_ptp_usb(¶ms, &ptp_usb, dev); + + /* get device status (devices likes that regardless of its result)*/ + usb_ptp_get_device_status(&ptp_usb,devstatus); + + /* check the in endpoint status*/ + ret = usb_get_endpoint_status(&ptp_usb,ptp_usb.inep,&status); + if (ret<0) perror ("usb_get_endpoint_status()"); + /* and clear the HALT condition if happend*/ + if (status) { + printf("Resetting input pipe!\n"); + ret=usb_clear_stall_feature(&ptp_usb,ptp_usb.inep); + if (ret<0)perror ("usb_clear_stall_feature()"); + } + status=0; + /* check the out endpoint status*/ + ret = usb_get_endpoint_status(&ptp_usb,ptp_usb.outep,&status); + if (ret<0) perror ("usb_get_endpoint_status()"); + /* and clear the HALT condition if happend*/ + if (status) { + printf("Resetting output pipe!\n"); + ret=usb_clear_stall_feature(&ptp_usb,ptp_usb.outep); + if (ret<0)perror ("usb_clear_stall_feature()"); + } + status=0; + /* check the interrupt endpoint status*/ + ret = usb_get_endpoint_status(&ptp_usb,ptp_usb.intep,&status); + if (ret<0)perror ("usb_get_endpoint_status()"); + /* and clear the HALT condition if happend*/ + if (status) { + printf ("Resetting interrupt pipe!\n"); + ret=usb_clear_stall_feature(&ptp_usb,ptp_usb.intep); + if (ret<0)perror ("usb_clear_stall_feature()"); + } + + /* get device status (now there should be some results)*/ + ret = usb_ptp_get_device_status(&ptp_usb,devstatus); + if (ret<0) + perror ("usb_ptp_get_device_status()"); + else { + if (devstatus[1]==PTP_RC_OK) + printf ("Device status OK\n"); + else + printf ("Device status 0x%04x\n",devstatus[1]); + } + + /* finally reset the device (that clears prevoiusly opened sessions)*/ + ret = usb_ptp_device_reset(&ptp_usb); + if (ret<0)perror ("usb_ptp_device_reset()"); + /* get device status (devices likes that regardless of its result)*/ + usb_ptp_get_device_status(&ptp_usb,devstatus); + + close_usb(&ptp_usb, dev); + +} + +/* main program */ + +int chdk(int busn, int devn, short force); + +int +main(int argc, char ** argv) +{ + int busn=0,devn=0; + int action=0; + short force=0; + int overwrite=SKIP_IF_EXISTS; + uint16_t property=0; + char* value=NULL; + char* propstr=NULL; + uint32_t handle=0; + char *filename=NULL; + int num=0; + /* parse options */ + int option_index = 0,opt; + static struct option loptions[] = { + {"help",0,0,'h'}, + {"bus",1,0,0}, + {"dev",1,0,0}, + {"reset",0,0,'r'}, + {"list-devices",0,0,'l'}, + {"list-files",0,0,'L'}, + {"list-operations",1,0,'o'}, + {"list-properties",0,0,'p'}, + {"show-all-properties",0,0,0}, + {"show-unknown-properties",0,0,0}, + {"show-property",1,0,'s'}, + {"set-property",1,0,'s'}, + {"set",1,0,0}, + {"get-file",1,0,'g'}, + {"get-all-files",0,0,'G'}, + {"capture",0,0,'c'}, + {"nikon-dc",0,0,0}, + {"ndc",0,0,0}, + {"nikon-ic",0,0,0}, + {"nic",0,0,0}, + {"nikon-dc2",0,0,0}, + {"ndc2",0,0,0}, + {"loop-capture",1,0,0}, + {"delete-object",1,0,'d'}, + {"delete-all-files",1,0,'D'}, + {"info",0,0,'i'}, + {"val",1,0,0}, + {"filename",1,0,0}, + {"overwrite",0,0,0}, + {"force",0,0,'f'}, + {"verbose",2,0,'v'}, + {"chdk",0,0,0}, + {0,0,0,0} + }; + + /* register signal handlers */ + signal(SIGINT, ptpcam_siginthandler); + + while(1) { + opt = getopt_long (argc, argv, "LhlcipfroGg:Dd:s:v::", loptions, &option_index); + if (opt==-1) break; + + switch (opt) { + /* set parameters */ + case 0: + if (!(strcmp("chdk",loptions[option_index].name))) + { + action=ACT_CHDK; + } + if (!(strcmp("val",loptions[option_index].name))) + value=strdup(optarg); + if (!(strcmp("filename",loptions[option_index].name))) + filename=strdup(optarg); + if (!(strcmp("overwrite",loptions[option_index].name))) + overwrite=OVERWRITE_EXISTING; + if (!(strcmp("bus",loptions[option_index].name))) + busn=strtol(optarg,NULL,10); + if (!(strcmp("dev",loptions[option_index].name))) + devn=strtol(optarg,NULL,10); + if (!(strcmp("loop-capture",loptions[option_index].name))) + { + action=ACT_LOOP_CAPTURE; + num=strtol(optarg,NULL,10); + } + if (!(strcmp("show-all-properties", loptions[option_index].name))) + action=ACT_SHOW_ALL_PROPERTIES; + if (!(strcmp("show-unknown-properties", loptions[option_index].name))) + action=ACT_SHOW_UNKNOWN_PROPERTIES; + if (!(strcmp("set",loptions[option_index].name))) + { + propstr=strdup(optarg); + action=ACT_SET_PROPBYNAME; + } + if (!strcmp("nikon-dc", loptions[option_index].name) || + !strcmp("ndc", loptions[option_index].name)) + { + action=ACT_NIKON_DC; + } + if (!strcmp("nikon-ic", loptions[option_index].name) || + !strcmp("nic", loptions[option_index].name)) + { + action=ACT_NIKON_IC; + } + if (!strcmp("nikon-dc2", loptions[option_index].name) || + !strcmp("ndc2", loptions[option_index].name)) + { + action=ACT_NIKON_DC2; + } + break; + case 'f': + force=~force; + break; + case 'v': + if (optarg) + verbose=strtol(optarg,NULL,10); + else + verbose=1; + /*printf("VERBOSE LEVEL = %i\n",verbose);*/ + break; + /* actions */ + case 'h': + help(); + break; + case 'r': + action=ACT_DEVICE_RESET; + break; + case 'l': + action=ACT_LIST_DEVICES; + break; + case 'p': + action=ACT_LIST_PROPERTIES; + break; + case 's': + action=ACT_GETSET_PROPERTY; + property=strtol(optarg,NULL,16); + break; + case 'o': + action=ACT_LIST_OPERATIONS; + break; + case 'i': + action=ACT_SHOW_INFO; + break; + case 'c': + action=ACT_CAPTURE; + break; + case 'L': + action=ACT_LIST_FILES; + break; + case 'g': + action=ACT_GET_FILE; + handle=strtol(optarg,NULL,16); + break; + case 'G': + action=ACT_GET_ALL_FILES; + break; + case 'd': + action=ACT_DELETE_OBJECT; + handle=strtol(optarg,NULL,16); + break; + case 'D': + action=ACT_DELETE_ALL_FILES; + case '?': + break; + default: + fprintf(stderr,"getopt returned character code 0%o\n", + opt); + break; + } + } + if (argc==1) { + usage(); + return 0; + } + switch (action) { + case ACT_CHDK: + chdk(busn,devn,force); + break; + case ACT_DEVICE_RESET: + reset_device(busn,devn,force); + break; + case ACT_LIST_DEVICES: + list_devices(force); + break; + case ACT_LIST_PROPERTIES: + list_properties(busn,devn,force); + break; + case ACT_GETSET_PROPERTY: + getset_property(busn,devn,property,value,force); + break; + case ACT_SHOW_INFO: + show_info(busn,devn,force); + break; + case ACT_LIST_OPERATIONS: + list_operations(busn,devn,force); + break; + case ACT_LIST_FILES: + list_files(busn,devn,force); + break; + case ACT_GET_FILE: + get_file(busn,devn,force,handle,filename,overwrite); + break; + case ACT_GET_ALL_FILES: + get_all_files(busn,devn,force,overwrite); + break; + case ACT_CAPTURE: + capture_image(busn,devn,force); + break; + case ACT_DELETE_OBJECT: + delete_object(busn,devn,force,handle); + break; + case ACT_DELETE_ALL_FILES: + delete_all_files(busn,devn,force); + break; + case ACT_LOOP_CAPTURE: + loop_capture (busn,devn,force,num,overwrite); + break; + case ACT_SHOW_ALL_PROPERTIES: + show_all_properties(busn,devn,force,0); + break; + case ACT_SHOW_UNKNOWN_PROPERTIES: + show_all_properties(busn,devn,force,1); + break; + case ACT_SET_PROPBYNAME: + getset_propertybyname(busn,devn,propstr,value,force); + break; + case ACT_NIKON_DC: + nikon_direct_capture(busn,devn,force,filename,overwrite); + break; + case ACT_NIKON_IC: + nikon_initiate_dc (busn,devn,force); + break; + case ACT_NIKON_DC2: + nikon_direct_capture2(busn,devn,force,filename,overwrite); + } + + return 0; + +} + + + + + +static int camera_bus = 0; +static int camera_dev = 0; +static int camera_force = 0; +static PTP_USB ptp_usb; +static PTPParams params; +static struct usb_device *dev; +static int connected = 0; + +static void open_connection() +{ + connected = (0 == open_camera(camera_bus,camera_dev,camera_force,&ptp_usb,¶ms,&dev)); +} + +static void close_connection() +{ + close_camera(&ptp_usb,¶ms,dev); +} + +static void reset_connection() +{ + if ( connected ) + { + close_connection(); + } + open_connection(); +} + +static void print_safe(char *buf, int size) +{ + int i; + for (i=0; i '~' ) + { + printf("."); + } else { + printf("%c",buf[i]); + } + } +} + +static void hexdump(char *buf, unsigned int size, unsigned int offset) +{ + unsigned int i; + char s[16]; + + if ( offset % 16 != 0 ) + { + printf("%08x ",offset); + for (i=0; i<(offset%16); i++) + { + printf(" "); + } + if ( offset % 16 > 8 ) + { + printf(" "); + } + memset(s,' ',offset%16); + } + for (i=0; ; i++, offset++) + { + if ( offset % 16 == 0 ) + { + if ( i > 0 ) + { + printf(" |"); + print_safe(s,16); + printf("|\n"); + } + printf("%08x",offset); + if (i < size) + { + printf(" "); + } + } + if ( offset % 8 == 0 ) + { + printf(" "); + } + if ( i == size ) + { + break; + } + printf("%02x ",(unsigned char) buf[i]); + s[offset%16] = buf[i]; + } + if ( offset % 16 != 0 ) + { + for (i=0; i<16-(offset%16); i++) + { + printf(" "); + } + if ( offset % 16 < 8 ) + { + printf(" "); + } + memset(s+(offset%16),' ',16-(offset%16)); + printf(" |"); + print_safe(s,16); + printf("|\n%08x",offset); + } + printf("\n"); +} + +int chdk(int busn, int devn, short force) +{ + char buf[1024], *s; + + buf[1023] = '\0'; + + camera_bus = busn; + camera_dev = devn; + camera_force = force; + + open_connection(); + + while (1) + { + printf("%s ",connected?"":"< >"); fflush(stdout); + if ( fgets(buf,1023,stdin) == NULL ) + { + printf("\n"); + break; + } + s = buf+strlen(buf)-1; + while ( s >= buf && ( *s == '\n' || *s == '\r' ) ) + { + *s = '\0'; + s--; + } + + if ( !strcmp("q",buf) || !strcmp("quit",buf) ) + { + break; + + } else if ( !strcmp("h",buf) || !strcmp("help",buf) ) + { + printf( + "q quit quit program\n" + "h help list commands\n" + "r reset reconnect to camera\n" + " shutdown-hard shutdown camera (hard)\n" + " shutdown-soft shutdown camera (soft)\n" + " reboot reboot camera\n" + " reboot reboot camera using specified firmware update\n" + " reboot-fi2 reboot camera using default firmware update\n" + "m memory
get byte at address\n" + "m memory
-
get bytes at given range\n" + "m memory
get num bytes at given address\n" + " set
set long value at address\n" + "c call
... call function at address with given arguments\n" + " prop get value of property\n" + " prop - get values in property range\n" + " prop get num values of properties starting at id\n" + " param get value of parameter\n" + " param - get values in parameter range\n" + " param get num values of parameters starting at id\n" + "u upload upload local file to camera\n" + "d download download file from camera\n" + " mode set mode (0=playback,1=record)\n" + " lua execute lua code\n" + ); + + } else if ( !strcmp("r",buf) || !strcmp("reset",buf) ) + { + reset_connection(); + + } else if ( !strcmp("shutdown-hard",buf) ) + { + if ( ptp_chdk_shutdown_hard(¶ms,¶ms.deviceinfo) ) + { + connected = 0; + } + + } else if ( !strcmp("shutdown",buf) ) + { + if ( ptp_chdk_shutdown_soft(¶ms,¶ms.deviceinfo) ) + { + connected = 0; + } + + } else if ( !strcmp("reboot",buf) ) + { + if ( ptp_chdk_reboot(¶ms,¶ms.deviceinfo) ) + { + connected = 0; + sleep(2); + open_connection(); + } + + } else if ( !strcmp("reboot-fi2",buf) ) + { + if ( ptp_chdk_reboot_fw_update("A/PS.FI2",¶ms,¶ms.deviceinfo) ) + { + connected = 0; + sleep(2); + open_connection(); + } + + } else if ( !strncmp("reboot ",buf,7) ) + { + char *s; + if ( (s = strchr(buf,'\r')) != NULL ) + { + *s = '\0'; + } + if ( (s = strchr(buf,'\n')) != NULL ) + { + *s = '\0'; + } + if ( ptp_chdk_reboot_fw_update(buf+7,¶ms,¶ms.deviceinfo) ) + { + connected = 0; + sleep(2); + open_connection(); + } + + } else if ( !strncmp("m ",buf,2) || !strncmp("memory ",buf,7) ) + { + int start; + int end; + char *s; + char *buf2; + + buf2 = strchr(buf,' ')+1; + + if ( (s = strchr(buf2,'-')) != NULL ) + { + *s = '\0'; + start = strtoul(buf2,NULL,0); + end = strtoul(s+1,NULL,0)+1; + } else if ( (s = strchr(buf2,' ')) != NULL ) + { + *s = '\0'; + start = strtoul(buf2,NULL,0); + end = start+strtoul(s+1,NULL,0); + } else { + start = strtoul(buf2,NULL,0); + end = start+1; + } + + if ( (buf2 = ptp_chdk_get_memory(start,end-start,¶ms,¶ms.deviceinfo)) == NULL ) + { + printf("error getting memory\n"); + } else { + hexdump(buf2,end-start,start); + free(buf2); + } + + } else if ( !strncmp("set ",buf,4) ) + { + int addr; + int val; + char *s; + + if ( (s = strchr(buf+4,' ')) == NULL ) + { + printf("invalid arguments\n"); + } else { + *s = '\0'; + addr = strtoul(buf+4,NULL,0); + val = strtoul(s+1,NULL,0); + + if ( !ptp_chdk_set_memory_long(addr,val,¶ms,¶ms.deviceinfo) ) + { + printf("set failed!\n"); + } + } + + } else if ( !strncmp("c ",buf,2) || !strncmp("call ",buf,5) ) + { + int num_args,i,ret; + char *buf2; + int *args; + + buf2 = buf; + num_args = 0; + while ( (buf2 = strchr(buf2,' ')) != NULL ) + { + num_args++; + buf2++; + } + args = malloc(num_args*sizeof(int)); + buf2 = buf; + i = 0; + while ( (buf2 = strchr(buf2,' ')) != NULL ) + { + buf2++; + args[i] = strtoul(buf2,NULL,0); + i++; + } + + if ( !ptp_chdk_call(args,num_args,&ret,¶ms,¶ms.deviceinfo) ) + { + printf("error making call\n"); + } else { + printf("%08x %i\n",ret,ret); + } + free(args); + + } else if ( !strncmp("prop ",buf,5) ) + { + int start; + int end; + char *s; + int *vals; + + if ( (s = strchr(buf+5,'-')) != NULL ) + { + *s = '\0'; + start = strtoul(buf+5,NULL,0); + end = strtoul(s+1,NULL,0)+1; + } else if ( (s = strchr(buf+5,' ')) != NULL ) + { + *s = '\0'; + start = strtoul(buf+5,NULL,0); + end = start+strtoul(s+1,NULL,0); + } else { + start = strtoul(buf+5,NULL,0); + end = start+1; + } + + if ( (vals = ptp_chdk_get_propcase(start,end-start,¶ms,¶ms.deviceinfo)) == NULL ) + { + printf("error getting properties\n"); + } else { + int i; + for (i=start; ilog_on,log->log_level,log->p1,log->p2,log->bufsize); + if ( (data = (int *) ptp_chdk_get_memory(log->p1+0x40,4,¶ms,¶ms.deviceinfo)) == NULL ) + { + printf("error\n"); + } else { + printf("0x%x\n",*data); + if ( (listp = (int *) ptp_chdk_get_memory((*data)+4,4,¶ms,¶ms.deviceinfo)) == NULL ) + { + printf("error\n"); + } else { + printf("0x%x\n",*listp); + liststart = *listp; + while ( 1 ) + { + if ( (list = (struct llist *) ptp_chdk_get_memory(*listp,12,¶ms,¶ms.deviceinfo)) == NULL ) + { + printf("error\n"); + break; + } else { + printf("0x%x %i %i\n",list->next,list->size,list->len); + s = NULL; + if ( list->len > 0 && (s = ptp_chdk_get_memory((*listp)+12,list->len,¶ms,¶ms.deviceinfo)) == NULL ) + { + printf("error\n"); + free(list); + break; + } else { + printf("%s",s); + free(s); + } + *listp = list->next; + free(list); + } + if ( *listp == liststart ) + { + break; + } + } + free(listp); + } + free(data); + } + free(log); + } + + } else if ( !strcmp("upgrade",buf) ) + { + if ( !ptp_chdk_upload("/home/muck/chdk/bin/PS.FI2","A/PS.FI2",¶ms,¶ms.deviceinfo) ) + { + printf("upload failed\n"); + } else { + if ( ptp_chdk_reboot_fw_update("A/PS.FI2",¶ms,¶ms.deviceinfo) ) + { + connected = 0; + sleep(3); + open_connection(); + } else { + printf("reboot failed\n"); + } + } +#endif + } else { + printf("unknown command\n"); + } + } + + if ( connected ) + { + close_connection(); + } + + return 0; +} diff --git a/tools/ptpcam/ptpcam.h b/tools/ptpcam/ptpcam.h new file mode 100644 index 00000000..e2108554 --- /dev/null +++ b/tools/ptpcam/ptpcam.h @@ -0,0 +1,169 @@ +/* ptpcam.h + * + * Copyright (C) 2001-2005 Mariusz Woloszyn + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __PTPCAM_H__ +#define __PTPCAM_H__ + +#ifdef LINUX_OS +#define USB_BULK_READ myusb_bulk_read +#define USB_BULK_WRITE myusb_bulk_write +int myusb_bulk_read(usb_dev_handle *dev, int ep, char *bytes, int size, + int timeout); +int myusb_bulk_write(usb_dev_handle *dev, int ep, char *bytes, int length, + int timeout); +#else +#define USB_BULK_READ usb_bulk_read +#define USB_BULK_WRITE usb_bulk_write +#endif + +/* + * macros + */ + +/* Check value and Return on error */ +#define CR(o,error) { \ + uint16_t result=o; \ + if((result)!=PTP_RC_OK) { \ + ptp_perror(¶ms,result); \ + fprintf(stderr,"ERROR: "error); \ + close_camera(&ptp_usb, ¶ms, dev); \ + return; \ + } \ +} + +/* Check value and Continue on error */ +#define CC(result,error) { \ + if((result)!=PTP_RC_OK) { \ + fprintf(stderr,"ERROR: "error); \ + usb_release_interface(ptp_usb.handle, \ + dev->config->interface->altsetting->bInterfaceNumber); \ + continue; \ + } \ +} + +/* error reporting macro */ +#ifndef ERROR +#define ERROR(error) fprintf(stderr,"ERROR: "error); +#endif + +/* property value printing macros */ +#define PRINT_PROPVAL_DEC(value) \ + print_propval(dpd.DataType, value, \ + PTPCAM_PRINT_DEC) + +#define PRINT_PROPVAL_HEX(value) \ + print_propval(dpd.DataType, value, \ + PTPCAM_PRINT_HEX) + + + + +/* + * defines + */ + +/* requested actions */ +#define ACT_DEVICE_RESET 0x1 +#define ACT_LIST_DEVICES 0x2 +#define ACT_LIST_PROPERTIES 0x3 +#define ACT_LIST_OPERATIONS 0x4 +#define ACT_GETSET_PROPERTY 0x5 +#define ACT_SHOW_INFO 0x6 +#define ACT_LIST_FILES 0x7 +#define ACT_GET_FILE 0x8 +#define ACT_GET_ALL_FILES 0x9 +#define ACT_CAPTURE 0xA +#define ACT_DELETE_OBJECT 0xB +#define ACT_DELETE_ALL_FILES 0xC +#define ACT_LOOP_CAPTURE 0xD +#define ACT_SHOW_ALL_PROPERTIES 0xE +#define ACT_SHOW_UNKNOWN_PROPERTIES 0xF +#define ACT_SET_PROPBYNAME 0x10 + +#define ACT_NIKON_DC 0x101 +#define ACT_NIKON_DC2 0x102 +#define ACT_NIKON_IC 0x103 + +#define ACT_CHDK 0x1337 + +/* printing value type */ +#define PTPCAM_PRINT_HEX 00 +#define PTPCAM_PRINT_DEC 01 + +/* filename overwrite */ +#define OVERWRITE_EXISTING 1 +#define SKIP_IF_EXISTS 0 + + +/* + * structures + */ + +typedef struct _PTP_USB PTP_USB; +struct _PTP_USB { + usb_dev_handle* handle; + int inep; + int outep; + int intep; +}; + +/* + * variables + */ + +/* one global variable */ +extern short verbose; + + +/* + * functions + */ + +void ptpcam_siginthandler(int signum); + +void usage(void); +void help(void); +void list_devices(short force); +void show_info (int busn, int devn, short force); +void list_files (int busn, int devn, short force); +void get_file (int busn, int devn, short force, uint32_t handle, char* filename, int overwrite); +void get_all_files (int busn, int devn, short force, int overwrite); +void capture_image (int busn, int devn, short force); +void nikon_direct_capture (int busn, int devn, short force, char* filename, int overwrite); +void nikon_direct_capture2 (int busn, int devn, short force, char* filename, int overwrite); +void delete_object (int busn, int devn, short force, uint32_t handle); +void delete_all_files (int busn, int devn, short force); +void list_operations (int busn, int devn, short force); +void list_devices(short force); +void list_properties (int dev, int bus, short force); +void loop_capture (int busn, int devn, short force, int n, int overwrite); +void save_object(PTPParams *params, uint32_t handle, char* filename, PTPObjectInfo oi, int overwrite); +void get_save_object (PTPParams *params, uint32_t handle, char* filename, int overwrite); + + +struct usb_bus* init_usb(void); +void close_usb(PTP_USB* ptp_usb, struct usb_device* dev); +void init_ptp_usb (PTPParams*, PTP_USB*, struct usb_device*); +void clear_stall(PTP_USB* ptp_usb); + +int usb_get_endpoint_status(PTP_USB* ptp_usb, int ep, uint16_t* status); +int usb_clear_stall_feature(PTP_USB* ptp_usb, int ep); +int open_camera (int busn, int devn, short force, PTP_USB *ptp_usb, PTPParams *params, struct usb_device **dev); +void close_camera (PTP_USB *ptp_usb, PTPParams *params, struct usb_device *dev); + +#endif /* __PTPCAM_H__ */