---------------------------------------------------------------------------
-                                                                         -
- description of the camera_t class:                                      -
-                                                                         -
-   The camera_t class is a C++ object wrapper for the camera.  This      -
-   should be portable to any platform that understands C++.              -
-                                                                         -
-   The camera_t class is found in camera.h and camera.C                  -
-                                                                         -
---------------------------------------------------------------------------

---------------------------------------------------------------------------
camera_t(port, detect)                                          constructor

purpose: to set up the object with reasonable defaults (called automatically)

port:    the port on which to find the camera; 0 means probe
detect:  the detection scheme to use, 0-4

returns: none

notes:   Default values are supplied for both parameters, but it is still
         recommended that client programs supply values here.

---------------------------------------------------------------------------
~camera_t                                                        destructor

purpose: to shut down the object (called automatically)

args:    none
returns: none

---------------------------------------------------------------------------
get_frame

purpose: get a frame from the camera and return it in a standard format

args:    none

returns: width * height * bpp/8 bytes of image data

notes:   The buffer used for the return value was allocated with new and
         should be removed with delete[]

         Image format depends on the current bpp.  If bpp==24, the return
         format is R G B R G B ... .  If bpp==32, the return format is
         B G - R B G - R ... .  Conversion is left to the calling program;
         see raw32_to_24.

---------------------------------------------------------------------------
set_height(height)
set_width(width)

purpose: validate image dimensions, translate them to hardware dimensions,
         and send them to the camera

height:  the desired image height, in pixels (4 to 480)
width:   the desired image width, in pixels (4 to 640)

returns: -1 on failure, 0 on success

---------------------------------------------------------------------------
set_brightness(brightness)

purpose:    set the camera's hardware brightness value (0 to 254)

brightness: the new brightness level for the camera

returns:    -1 on failure, 0 on success

notes:      When brightness is large, it can be the limiting factor for the
            frame rate.  For the equations to translate the brightness value
            to the shutter speed (in microseconds), see the CQC specs.

            A brightness of 255 enables "bulb mode."  See the Quickcam
            documentation for details.

            Adding 16 to the brightness roughly doubles exposure length
            and thus the observed brightness.

---------------------------------------------------------------------------
set_top(top)
set_left(left)

purpose: set the camera's hardware left and top values

top:     the top scan row for images (1 to 240)
left:    the left scan column for images, divided by 2 (1 to 160)

returns: -1 on failure, 0 on success

notes:   Reasonable values are 1, 11 for the color camera.

---------------------------------------------------------------------------
get_version

purpose: get the camera's version

args:    none

returns: the camera version number, or -1 on failure

notes:   Version numbers 0x00 - 0x0F correspond to b/w cameras; 0x10 - 
         0x1F correspond to color cameras.

         When probing the color camera, the version number of the parallel
         connector is also detected, but it is ignored.

---------------------------------------------------------------------------
set_black_level(black)
set_white_level(white)
set_hue(hue)
set_saturation(saturation)
set_contrast(contrast)

purpose:    miscellaneous hardware settings

black:      the camera's black level (0 to 255)
white:      the camera's white balance level (0 to 255)
hue:        the camera's hue / blue level (0 to 255)
saturation: the camera's color saturation (0 to 255)
contrast:   the camera's contrast (0 to 255)

returns:    -1 on failure, 0 on success

notes:      For details on what these settings are, see the CQC specs.  
            In brief:
              Black level is the amount of black in the image.  White
              balance is the amount of white in the image.  Increasing 
              black and white together increases the contrast.  Hue is 
              the amount of blue in the image and is usually constant
              for each individual camera.  Saturation is the richness of
              color; if it is set too high, the colors "bleed."  Contrast
              supposedly controls the contrast, but it seems to have little
              effect.

            Reasonable defaults are 100, 100, 110, 104, 100 but may vary
            slightly from camera to camera.

---------------------------------------------------------------------------
get_status

purpose:  get the camera's status

args:     none

return:   the camera's status, or -1 on failure

notes:    See the CQC specs for status flags.  In brief:
            0x02  RAM tables should be downloaded
            0x40  busy performing black balance (after set_black_level call)
            0x80  busy (generic)

---------------------------------------------------------------------------
set_speed(speed)

purpose:  set the transfer rate between the camera and the parallel connector

speed:    speed number

returns:  -1 on error, 0 on success

notes:    The actual speed used is 5Mbs / speed.  Connectix says always to
          use a speed of 2, period.  I have experimented with leaving this
          out, and it does not seem to make a difference.

          This speed has no effect on the frame rate observed by the user.

---------------------------------------------------------------------------
set_bpp(bpp)
set_decimation(decimation)
set_port_mode(port_mode)
set_red(red)
set_green(green)
set_blue(blue)

Purpose:    pseudo-interface calls that change only software values

bpp:        desired number of bits per pixel, 24 ("millions" mode) or 32 
            ("billions" mode).  set_bpp() attempts to update the camera's
            width and height so as to preserve the pixel width and height.
decimation: the camera's transfer scale.  If the requested image is 640x480
            and the decimation is 4, the result is 160x120.  decimation may
            be 1, 2, or 4.
port_mode:  which type of port to use, QC_UNI_DIR or QC_BI_DIR.  This is
            auto-detected in the constructor.
red:        software red normalization value (0 to 255)
green:      software green normalization value (0 to 255)
blue:       software blue normalization value (0 to 255)

notes:      The red, green, and blue adjustment values may be 0-255, 
            where 128 means "no change."  The relation is linear.  That is,
            cooked_red_value = raw_red_value * red_scale / 128, etc.

---------------------------------------------------------------------------
get_pix_height
get_pix_width

purpose:  get the logical height or width settings, in pixels

args:     none

returns:  the number of pixels high or wide the resultant image will be

---------------------------------------------------------------------------
get_red
get_green
get_blue

purpose:  inspect the red, green, or blue adjustment settings

args:     none

returns:  red, green, or blue adjustment settings.  See set_red, set_green,
          set_blue.

---------------------------------------------------------------------------
get_bpp
get_decimation
get_brightness
get_white_level
get_black_level
get_top
get_left
get_saturation
get_hue
get_contrast

purpose:  pseudo-inspectors to examine the last value sent to the camera for
          a setting

args:     none

returns:  the last known value for the requested setting.

notes:    These can't be obtained from the camera; the software just 
          remembers them from the last call to set_*.  Unplugging the
          camera will throw all pseudo-inspectors out of sync!

---------------------------------------------------------------------------
get_port_mode

purpose:  inspects the current parallel port mode

args:     none

returns:  QC_BI_DIR or QC_UNI_DIR

---------------------------------------------------------------------------
reset

purpose:  reset the camera

args:     none

returns:  none

notes:    Twiddles pins on the parallel port to attempt to reset the camera.
          This will succeed whether or not a camera is present.  It takes
          2-3 ms, though scheduling delays may make this take 20 ms or more.

          Not all camera settings are reset.  The camera will stop 
          transmitting data and will switch to a uni-directional port.  It
          will not clear any settings like brightness.

---------------------------------------------------------------------------
load_ram_table(table)

purpose:  load a VIDEC compression lookup table

table:    a pointer to the RAM table to load

returns:  -1 on failure, 0 on success

notes:    This function is mostly implemented but does not work yet!


---------------------------------------------------------------------------
-                                                                         -
- description of the imager.C functions:                                  -
-                                                                         -
-   These are all standalone functions, found in imager.h and imager.C    -
-                                                                         -
---------------------------------------------------------------------------

---------------------------------------------------------------------------
write_ppm(output, buffer, width, height)
write_jpeg(output, buffer, width, height, quality)

purpose:  write a 24-bit RAW-format PPM or JPEG image file

output:   the FILE* stream on which to write; write_ppm and write_jpeg do
          not perform fopen or fclose; that's up to the client program
buffer:   an array of unsigned characters representing the image, size
          width * height * 3 bytes
width:    the width of the image, in pixels
height:   the height of the image, in pixels
quality:  JPEG quality (0 to 100).  A good range is between 50 and 75.

returns:  none

---------------------------------------------------------------------------
get_brightness_adj(image, size, &adjustment)

purpose:     find out how much to change the camera's brightness in an 
             attempt to get an image of "acceptable" light levels
             (126 <= mean <= 130)

image:       an array of unsigned characters representing the image
size:        the size of the image buffer in pixels (1/3 of the size in bytes)
&adjustment: returns the amount to increase (but can be negative) the
             camera's brightness setting

returns:     0 to keep adjusting, 1 when no more adjustments are necessary

notes:       Pseudocode for using this function follows:

               int flag = 0
               int adjust
               char *image
               while (!flag) {
                 image = camera.get_frame
                 flag = get_brightness_adjust(image, height*width, adjust)
                 camera.set_brightness(camera.get_brightness + adjust)
               }

             This produces some infinite loops.  Two good safety checks:
             * This process should never have more than 10 iteractions.
             * Define upper and lower bounds that converge as adjustments are
               made.

             This function does not modify the input image.

---------------------------------------------------------------------------
get_rgb_adj(image, size, &red, &green, &blue)

purpose:  get the values for r/b/g necessary to normalize them to 
          "acceptable" values (mean roughly = 128)

image:    unsigned character array representing the image
size:     image size in pixels (width*height) = 1/3 of the size in bytes
red:      red adjustment level, from 0-255, where 128 is "no adjustment"
green:    green adjustment level, same range as red
blue:     blue adjustment level, same range as red

returns:  none

notes:    RGB adjustments should be detected and performed after brightness
          adjustments are complete

          This function does not modify the input image.

---------------------------------------------------------------------------
do_rgb_adj(image, size, red, green, blue)

purpose:  modify the input image using red, green, and blue as RGB adjustment
          levels

image:    unsigned character array that is the image
size:     size of the array in pixels, = 1/3 of the size in bytes
red:      red level to use as an adjustment, 0-255, 128 = no change
green:    green level to use as an adjustment, 0-255, 128 = no change
blue:     blue level to use as an adjustment, 0-255, 128 = no change

returns:  none

notes:    RGB adjustments should be detected and performed after brightness
          adjustments are complete

          This function does modify the input image.

---------------------------------------------------------------------------
raw32_to_24(buffer, width, height, nospecks)

purpose:  convert a 32bpp image ("billions" mode) to a standard 24bpp image
          that is twice as wide and twice as high.

buffer:   32bpp image as an array of unsigned characters
width:    desired eventual width (same as get_pix_width)
height:   desired eventual height (same as get_pix_height)
nospecks: 1 if image should be despeckled as it is converted; 0 if not.
          The default value for this parameter is determined in config.h.

returns:  a 24bpp image as an array of unsigned characters

notes:    The 32bpp array is deallocated using delete[].  The 24bpp array
          is allocated using new, so clients are in charge of 
          deallocating it using delete[].

          32->24 bpp conversions produce some loss but triple the frame rate.

          raw32_to_24 calls despeckle32 before returning if nospecs==1
          despeckle32 cannot be removed from the 32->24 conversion function.

          raw32_to_24 creates a blank or semi-blank border around the right
          and bottom edges.

---------------------------------------------------------------------------
despeckle(image, width, height)

purpose:  to remove the "Xmas lights" effect in low-light pictures while 
          doing as little noticeable damage as possible to the remainder
          of the image

image:    unsigned character array representing a 24bpp image
width:    the width in pixels, from get_pix_width
height:   the height in pixels, from get_pix_height

notes:    Despeckle is very nearly lossless.  It is very rare that one would
          ever wish to disable it.

          For 32bpp images, despeckle32 (a private function) is called.  It
          follows nearly the same logic, but it must be run before the image
          is converted to 24bpp.
