git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@2481 67ed7778-7388-44ab-90cf-0a291f65f57c
621 lines
18 KiB
Plaintext
621 lines
18 KiB
Plaintext
<!doctype linuxdoc system>
|
|
|
|
<!-- LyX 1.1 created this file. For more info see http://www.lyx.org/ -->
|
|
<article>
|
|
<title>
|
|
gPhoto2 Camera Library Developer's Guide
|
|
</title>
|
|
<author>
|
|
Scott Fritzinger
|
|
2000-07-26
|
|
Revision 1
|
|
</author>
|
|
<toc>
|
|
<sect>
|
|
Reverse Engineering the Camera Protocol
|
|
<p>
|
|
The most difficult part for most developers is obtaining the transfer protocol.
|
|
If the OEM's are lucky enough, they will simply provide us with the protocol
|
|
specifications for their cameras and the drivers will be written at no cost
|
|
to them. Most OEM's refuse to do so though, citing trade secrets or company
|
|
policy; this is truly unfortunate in that they have effectively told their
|
|
own customers who use operating systems other than Windows and the Mac that
|
|
they don't want their future business and that they aren't valued customer
|
|
to begin with.
|
|
</p>
|
|
<p>
|
|
When OEM's do not cooperate, the developer is left to determine the protocol
|
|
him/herself through reverse engineering.
|
|
</p>
|
|
<sect1>
|
|
Sniffing the Protocol
|
|
<p>
|
|
What follows are the most common setups for sniffing camera protocol traffic.
|
|
In all setups, a host computer runs the native camera drivers.; typically,
|
|
the Windows serial port drivers are used for reverse engineering. The drivers
|
|
are run through a series of functions that include getting a picture index,
|
|
downloading thumbnails, download full images, deleting images, camera configuration
|
|
options, in addition to any other features a camera might have. During these
|
|
operations, one or more of the following methods are used to capture the communication
|
|
between the host computer and the camera.
|
|
</p>
|
|
<sect2>
|
|
Serial Repeater
|
|
<p>
|
|
A serial repeater consists of the host computer, a computer used as a repeater,
|
|
and the camera. The setup is shown in figure .
|
|
</p>
|
|
<p>
|
|
The repeater runs special software which reads data from one serial port,
|
|
logs the communication, and then outputs the data to the other serial port.
|
|
Data that is from the host computer to the camera and from the camera to the
|
|
host computer is logged sequentially in a single log file. Information logged
|
|
includes hexadecimal data values, direction of the communication, as well as
|
|
time stamps for synchronization. An example sniffer to use for this configuration
|
|
is "sersniff".
|
|
</p>
|
|
<sect2>
|
|
"Y" Serial Cable
|
|
<p>
|
|
To avoid using two computers, a Y serial cable can be used. The "trunk" end
|
|
of the serial cable attaches to the camera's serial transfer cable, while the
|
|
two "branches" plug in to two serial ports on the host computer. Figure shows
|
|
this setup.
|
|
</p>
|
|
<p>
|
|
The camera drivers use one of the serial ports on the host computer, while
|
|
the other port is opened with a hexadecimal monitor application that dumps
|
|
all communications on the port to a file. The downside to this approach is
|
|
the developer would have to determine which sets of data was generated by the
|
|
camera or the host computer. Also, a Y cable would have to be either built
|
|
or purchased from an electronics supply store.
|
|
</p>
|
|
<sect2>
|
|
Virtual Device Driver Hooks
|
|
<p>
|
|
The Windows platform allows virtual device drivers to "hook" into other drivers
|
|
to provide additional functionality or feature enhancements. A combination
|
|
GUI and device driver named PortMon by Systems Internals is a communications
|
|
debugging utility that hooks into the existing Windows serial device driver
|
|
(vcomm.vxd) and logs communications. Figure shows this equipment arrangement.
|
|
</p>
|
|
<p>
|
|
This setup allows the developer to not use any extra hardware by simply
|
|
relying on software. This is perhaps the easiest method for capturing camera
|
|
data.
|
|
</p>
|
|
<sect1>
|
|
Making Sense Out of the Protocol
|
|
<p>
|
|
What follows are some pointers on decoding camera protocols. It uses a
|
|
protocol that isn't really any camera protocol in particular, but should demonstrate
|
|
some commonalities between most camera protocols.
|
|
</p>
|
|
<p>
|
|
<enum>
|
|
<item>
|
|
Cameras like to ping. This is the in the form of an "ACK""
|
|
command that is different for different cameras. Basically, it is usually a
|
|
short packet (probably 1 byte) that is sent both ways in order for the camera
|
|
to know the computer is there or vice versa. It is also sometimes used to wake
|
|
up a camera that has gone into power-save mode. It usually starts out the communications,
|
|
as well as confirms each packet in any sort of "mass" transfer. The
|
|
opposite, a "NAK", is sent to basically say the last packet was not
|
|
received, or an error has occured. Again, this is usually just a single byte
|
|
as well.
|
|
|
|
Example:
|
|
Computer: 01
|
|
Camera : 01
|
|
|
|
The Camera sent an ACK ("01")
|
|
and the Computer responded with an ACK as well.
|
|
<item>
|
|
Transfers are usually in "reverse network order", meaning least
|
|
significant bytes come before most significant bytes. For example, "00 08" should
|
|
actually be reassembled as "08 00".
|
|
<item>
|
|
Most protocols use starting and stopping bytes.
|
|
|
|
Example:
|
|
Computer: 03
|
|
50 00 0f e0 04
|
|
Camera : 03 03 00 3f 03 04
|
|
Computer: 01
|
|
|
|
For this example,
|
|
notice the packets begin with "03" and end with "04" (don't
|
|
pay attention to what is between them). Also notice the Computer sent an "ACK"
|
|
to confirm it got the packet.
|
|
<item>
|
|
Packets usually have a "command" byte, which tells either the
|
|
computer or the camera what to do. Let's say you told the software to retrieve
|
|
the number of pictures, which at the time happened to be "8", and
|
|
you got the following:
|
|
|
|
Computer: 03 01 00 00 00 04
|
|
Camera : 03 01 00 00 08
|
|
04
|
|
Computer: 01
|
|
|
|
In this example, you notice the "03" and "04"
|
|
specifying the start and stop of the packet. Also, you notice the second byte
|
|
in the Computer packet is "01". The camera responds with the above
|
|
packet, and low and behold, you see the number 8 in the same packet. It would
|
|
appear, initially, that the second byte is used as a command byte, and that
|
|
"01" specifies the camera to return the number of pictures. This
|
|
may very well be right, but don't jump into it yet. Make sure you look at a
|
|
bunch of similar situations to confirm this. (Again, notice the "ACK"
|
|
sent by the computer).
|
|
<item>
|
|
Most protocols have a "data size" byte(s) in data packets. Let's
|
|
say that you told the camera to retrieve thumbnail 8 and you get the following:
|
|
|
|
Computer:
|
|
03 02 00 00 08 04
|
|
Camera : 03 02 00 0F (15 bytes) 04
|
|
Computer: 01
|
|
|
|
OK, here's
|
|
a brief breakdown of this transaction:
|
|
|
|
-Looks like the command to retrieve
|
|
a thumbnail is "02" (2nd byte in the computer packet), and that the
|
|
byte that is "08" specifies which thumbnail to return.
|
|
-The camera
|
|
responds with a "02" in the command field, specifying it is returning
|
|
a thumbnail, and then sends "0F", and 15 bytes of data.
|
|
-It looks
|
|
like the byte "0F" specifies how many bytes are after it in the same
|
|
packet. This is a data size byte.
|
|
(Note: this is a simplistic example. No
|
|
thumbnail will only be 15 bytes :) this leads up to the next thing to consider)
|
|
<item>
|
|
Most protocols have an "order" or "counter" byte. This
|
|
is used so that, in large data transfers where the picture may be split up
|
|
into several different packets, the computer knows how to reassemble all the
|
|
data. The entire thumbnail more than likely will not be contained in a single
|
|
packet for logistical reasons, so they break up the data into many different
|
|
packets and give each packet a unique number (or "order" byte). Let's say you
|
|
told your camera to return thumbnail 8 (which is, as mentioned, pretty big),
|
|
and you get the following:
|
|
|
|
Computer: 02 03 00 00 08 03
|
|
Camera : 02 03 00
|
|
0F (15 bytes) 03
|
|
Computer: 01
|
|
Camera : 02 03 01 0F (15 bytes) 03
|
|
Computer:
|
|
01
|
|
Camera : 02 03 02 0F (15 bytes) 03
|
|
Computer: 01
|
|
... 5 more packets and ACKs
|
|
...
|
|
Camera : 02 03 08 09 (9 bytes) 03
|
|
Computer: 01
|
|
|
|
You notice that the 3rd
|
|
byte of each of the camera packets increments with each packet sent from the
|
|
camera. This looks like it is an order (counter) byte. the computer can then
|
|
reassemble the data from all the packets in order to reproduce the image.
|
|
<item>
|
|
Most protocols have some sort of error detection byte(s) at the end of
|
|
the packet. This is usually a simple checksum (summation of bytes), or a CRC
|
|
(a somewhat complex algorithm that reduces the probability of mis-diagnosing
|
|
a packet with errors by magnitudes). These bytes can take into account only
|
|
the data, or maybe the entire packet excluding those error detection bytes.
|
|
If this isn't a known scheme, this winds up being the hardest part of reimplementing
|
|
the protocol. Lets take the above example again, this time we'll add a couple
|
|
bytes on the end for error detection:
|
|
|
|
Computer: 02 03 00 00 08 03
|
|
Camera :
|
|
02 03 00 0F (15 bytes) 0f 02 03
|
|
Computer: 01
|
|
Camera : 02 03 01 0F (15 bytes)
|
|
0e 00 03
|
|
Computer: 02
|
|
Camera : 02 03 01 0F (15 bytes) fa d0 03
|
|
Computer: 01
|
|
Camera
|
|
: 02 03 02 0F (15 bytes) fa d0 03
|
|
Computer: 01
|
|
... 5 more packets and ACKs
|
|
Camera
|
|
: 02 03 08 09 (9 bytes) d7 38 03
|
|
Computer: 01
|
|
|
|
Notice how the error detection
|
|
bytes are usually different for each packet. These may be checksums, or CRC's,
|
|
or something else. Only way to find out really is to try each one, on different
|
|
combinations of packet parts (data, order byte, command byte, etc...) and see
|
|
if you get the same thing. Try this on the shorter packets to make life easier.
|
|
|
|
Look
|
|
at one more thing that sticks out in this transaction: for packet with order
|
|
byte "01", the Computer responded with a "02". and the Camera then resent
|
|
the same packet it just did. This shows that the NAK byte is "02",
|
|
and this could happen because maybe the error detection bytes didn't match
|
|
with the data, or maybe something else happened. either way, the camera resent
|
|
the last packet, and now you know how the camera can recover from transfer
|
|
errors. If you didn't get the packet you were expecting, send the camera a
|
|
NAK and it will resend the same packet again.
|
|
</enum>
|
|
</p><sect>
|
|
Understanding the gPhoto2 Design
|
|
<p>
|
|
The gPhoto2 design is the same three-tiered structure that has worked extremely
|
|
well in the past with other software packages. Here is a listing of the 3 tiers:
|
|
</p>
|
|
<p>
|
|
<itemize>
|
|
<item>
|
|
the camera library
|
|
<item>
|
|
the I/O library
|
|
<item>
|
|
the front-end
|
|
<item>
|
|
the "core"
|
|
</itemize>
|
|
</p><sect1>
|
|
Role of the Camera Library
|
|
<p>
|
|
The camera library is in charge of talking directly with the camera. The
|
|
library uses the gPhoto2 Camera API in order to provide a common access-method
|
|
for the library itself. Being dynamically linked, the libraries are loaded
|
|
at run-time depending on the camera model the end-user would like to access.
|
|
|
|
</p>
|
|
<p>
|
|
In order to provide flexilibity with variations in camera design, there
|
|
are camera "abilities" which list, well, the abilities of each camera model.
|
|
Some camera may support serial port connections only, while others may be able
|
|
to use USB and a serial port. We've run into cameras that don't support thumbnailing
|
|
on the camera so there is an "abilities" field to specify whether or not the
|
|
camera supports thumbnailing. The "abilities" also list other things such as
|
|
supported serial transfer speeds, file deletion, and other functionality.
|
|
</p>
|
|
<p>
|
|
The camera libraries only make functions calls to the I/O library and to
|
|
the gPhoto2 core.
|
|
</p>
|
|
<p>
|
|
There is more information on the specifics of the camera library in section
|
|
3 of this document.
|
|
</p>
|
|
<sect1>
|
|
Role of the I/O Library
|
|
<p>
|
|
The gPhoto2 I/O library is a platform-independent communications library
|
|
that support serial, parallel, USB, firewire, and network connections. It is
|
|
a work-in-progress with a constantly expanding list of supported platforms.
|
|
This library uses the gPhoto2 I/O library API for accessing communications
|
|
devices. It enumerates the devices available on a system, and provides read/write
|
|
access.
|
|
</p>
|
|
<p>
|
|
The camera libraries all use the I/O library for communications with the
|
|
cameras. By doing having all communications go through a single library, the
|
|
camera libraries become as portable as the I/O library. Porting gPhoto2 to
|
|
other platforms become extremely easy.
|
|
</p>
|
|
<p>
|
|
There is more information on the specifics of the I/O library in section
|
|
3 of this document.
|
|
</p>
|
|
<sect1>
|
|
Role of the Front-end
|
|
<p>
|
|
The front-end is the application that the user interacts with. It is usually
|
|
a command-line program, or a graphical point-and-click interface. The front-end
|
|
talks only with the gPhoto2 core in order to retrieve pictures and perform
|
|
other functions with the camera.
|
|
</p>
|
|
<sect1>
|
|
Role of the gPhoto2 Core
|
|
<p>
|
|
The gPhoto2 "core" is the heart of gPhoto2. It provides services to both
|
|
the camera libraries and the front-ends. Most of the services deal with error-checking
|
|
and enumeration of devices (cameras, I/O devices, etc...). The core performs
|
|
validity checking on data passed to/from the front-end or the camera library.
|
|
</p>
|
|
<p>
|
|
You could consider the core a translator/interpreter/spell-checker/army-general
|
|
in the "big picture" of gPhoto2. It does the grunt-work and performs the coordination
|
|
of the other parts.
|
|
</p>
|
|
<sect>
|
|
Implementing the Library
|
|
<p>
|
|
gPhoto2 camera libraries use the gPhoto2 Camera API (CAPI) for implementation.
|
|
Here is a listing of the CAPI functions:
|
|
</p>
|
|
<p>
|
|
camera_id
|
|
</p>
|
|
<p>
|
|
camera_abilities
|
|
</p>
|
|
<p>
|
|
camera_init
|
|
</p>
|
|
<p>
|
|
camera_exit
|
|
</p>
|
|
<p>
|
|
camera_folder_list
|
|
</p>
|
|
<p>
|
|
camera_file_list
|
|
</p>
|
|
<p>
|
|
camera_file_get
|
|
</p>
|
|
<p>
|
|
camera_file_get_preview
|
|
</p>
|
|
<p>
|
|
camera_file_put
|
|
</p>
|
|
<p>
|
|
camera_file_delete
|
|
</p>
|
|
<p>
|
|
camera_config_get
|
|
</p>
|
|
<p>
|
|
camera_config_set
|
|
</p>
|
|
<p>
|
|
camera_capture
|
|
</p>
|
|
<p>
|
|
camera_summary
|
|
</p>
|
|
<p>
|
|
camera_manual
|
|
</p>
|
|
<p>
|
|
camera_about
|
|
|
|
</p>
|
|
<p>
|
|
Section 3.1 details the purpose of each of these functions, while Section
|
|
3.2 discusses how to use the I/O library.
|
|
</p>
|
|
<sect1>
|
|
Camera API
|
|
<p>
|
|
The CAPI provides the full set of functions for doing various tasks with
|
|
the camera. All CAPI functions return either GP_OK for succesful execution
|
|
, or GP_ERROR for a failure of execution
|
|
</p>
|
|
<p>
|
|
What follows is a listing of the functions, including prototypes and data
|
|
exchange:
|
|
</p>
|
|
<sect2>
|
|
camera_id
|
|
<p>
|
|
<bf>Purpose: </bf>Retrieve the unique id for the camera library.
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_id (CameraText *id);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>
|
|
</p>
|
|
<p>
|
|
CameraText *id : unique string to represent the camera library
|
|
|
|
</p>
|
|
<p>
|
|
In order to guarantee that only once instance of the camera library is
|
|
loaded for each instance of the core, the camera library must copy a unique
|
|
string into the "id". Please consult the gPhoto developers to determine which
|
|
string you should use.
|
|
|
|
</p>
|
|
<p>
|
|
<bf>Example:</bf>
|
|
</p>
|
|
<p>
|
|
int camera_id(CameraText *id) {
|
|
</p>
|
|
<p>
|
|
strcpy(id->text, "my-unique-string");
|
|
</p>
|
|
<p>
|
|
return (GP_OK);
|
|
</p>
|
|
<p>
|
|
}
|
|
</p>
|
|
<sect2>
|
|
camera_abilities
|
|
<p>
|
|
<bf>Purpose: </bf>Retrieve the list of supported cameras and the abilities for each
|
|
camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_abilities (CameraAbilitiesList *list);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<p>
|
|
CameraAbilities *abilities : the list of abilities for the supported cameras
|
|
</p>
|
|
<p>
|
|
int *count : the number of
|
|
</p>
|
|
<sect2>
|
|
camera_init
|
|
<p>
|
|
<bf>Purpose: </bf>Initialize the camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_init (Camera *camera, CameraInit *init);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_exit
|
|
<p>
|
|
<bf>Purpose: </bf>Close the camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_exit (Camera *camera);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_file_list
|
|
<p>
|
|
<bf>Purpose: </bf>List the files in a particular folder on the camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_file_list(Camera *camera, CameraList *list, char
|
|
*folder);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_folder_list
|
|
<p>
|
|
<bf>Purpose: </bf>List the subfolders in a particular folder on the camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_folder_list(Camera *camera, CameraList *list, char
|
|
*folder);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_file_get
|
|
<p>
|
|
<bf>Purpose: </bf>Retrieve a file from the camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_file_get (Camera *camera, CameraFile *file, char
|
|
*folder, char *filename);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_file_get_preview
|
|
<p>
|
|
<bf>Purpose: </bf>Retrieve a file's preview from the camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_file_get_preview (Camera *camera, CameraFile *file,
|
|
char *folder, char *filename);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_file_put
|
|
<p>
|
|
<bf>Purpose: </bf>Place (upload) a file to the camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_file_put (Camera *camera, CameraFile *file, char
|
|
*folder);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_file_delete
|
|
<p>
|
|
<bf>Purpose: </bf>Delete a file from the camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_file_delete (Camera *camera, char *folder, char *filename);
|
|
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_config_get
|
|
<p>
|
|
<bf>Purpose: </bf>Retrieve the configuration window.
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_config_get (Camera *camera, CameraWidget *window);
|
|
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_config_set
|
|
<p>
|
|
<bf>Purpose: </bf>Set camera configuration
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_config_set (Camera *camera, CameraSetting *setting,
|
|
int count);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_capture
|
|
<p>
|
|
<bf>Purpose: </bf>Retrieve live data from the camera
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_capture (Camera *camera, CameraFile *file, CameraCaptureInfo
|
|
*info);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_summary
|
|
<p>
|
|
<bf>Purpose: </bf>Retrieve the camera summary information
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_summary (Camera *camera, CameraText *summary);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_manual
|
|
<p>
|
|
<bf>Purpose: </bf>Retrieve the camera user's guide (manual)
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_manual (Camera *camera, CameraText *manual);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect2>
|
|
camera_about
|
|
<p>
|
|
<bf>Purpose: </bf>Retrieve information about the camera library
|
|
</p>
|
|
<p>
|
|
<bf>Prototype: </bf>int camera_about (Camera *camera, CameraText *about);
|
|
</p>
|
|
<p>
|
|
<bf>Arguments: </bf>d
|
|
</p>
|
|
<sect1>
|
|
The gPhoto2 I/O Library
|
|
|
|
|
|
</article>
|