The Apple Quicktake 100 serial communication protocol

Connecting

The Quicktake 100 is connected via serial. Once connected, one has to open the lens cover to power on the camera. Unusually enough, the “conversation” is started by the camera, which is the first to send bytes to the computer. The computer signals it is ready to interact by opening the serial port at 9600bps, 8 data bits, 1 stop bit, no parity, and then pulling DTR down. The flow is the following:

  • Camera: sends 7 bytes – I have not yet found a use for them.
  • Computer: replies with {0x5A,0xA5,0x55,0x05,0x00,0x00,0x25,0x80,0x00,0x80,0x02,0x00,0x80}
  • Camera: sends 10 bytes – I have not yet found a use for them.

At this point, the computer is expected to turn Even parity on. It is also at that moment that the computer can renegotiate serial settings like speed, but I have, so far, problems with the exact implementation.

After Even parity is set, a slight delay is needed before continuing:

  • Computer: sends {0x16,0x00,0x00,0x00,0x00,0x00,0x00}. I call it a “separator”, it seems to be a way to tell the camera to reset, or prepare, for another command.
  • Camera: sends {0x00} – an ack. The camera will ack some commands, and a non-zero response means there was an error processing the command. I mostly got 0x02 in case of problems in my commands. Other commands will be “acked” with a direct response.

Getting camera information

The flow for getting the camera information is the following:

  • Computer: sends {0x16,0x28,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x80,0x00}
  • Camera: responds with 128 bytes of data.

In the response data, starting from byte 0, are the following:

  • byte 0x04: Number of pictures taken (8-bit value)
  • byte 0x06: Number of pictures left (in the current quality mode)
  • byte 0x07: Current quality mode (1: 320×240, 2: 640×480)
  • byte 0x10: Current month
  • byte 0x11: Current day of month
  • byte 0x12: Current year (this is also an 8-bit value, so “23” for 2023)
  • byte 0x13: Current hour
  • byte 0x14: Current minute
  • bytes 0x2F to 0x4F: Name of the camera, trailed with spaces to 31 characters, and NULL-terminated

(As an aside, in most commands sent by the computer, bytes 7 to 9 (counting from 0) contain the expected response size, in 24 bits, big-endian format)

Getting a picture

There are two commands to get a picture.

Getting the “header”, basic information about the picture:

It will be needed later. The flow for getting the header is the following:

  • Computer: sends {0x16,0x28,0x00,0x21,0x00,0x00,0x03,0x00,0x00,0x40,0x00}. Byte 0x06 is the picture number, starting from 1 and up to the number of pictures stored in the camera (picture 3 in this example) .
  • Camera: acks with {0x00}
  • Computer: responds with {0x06}
  • Camera: responds with 64 bytes of data.

In the response data, starting from byte 0, are the following:

  • byte 0x04-0x40: the important part of the qtkt header, notably containing:
  • byte 0x08-0x09: Image width, 16-bits, big-endian
  • byte 0x0A-0x0B: Image height, 16-bits, big-endian
  • byte 0x05-0x07: Image size, 24-bytes, big-endian. It will either be 115200 (high quality) or 28800 (standard quality).

Before getting the picture, which will be raw ADPCM-compressed data, it might be useful to prepare the header of the output file, so that tools like dcraw can read and decode them. The qtkt file has the following format:

  • starts with {0x71,0x6B,0x74,0x6B,0x00,0x00,0x00,0x04,0x00,0x00,0x73,0xE4,0x00,0x01}
  • 736 bytes long header
  • byte 0x0E, the last 60 bytes of the camera’s response: the important part of the qtkt header
  • bytes 0x220-0x221: height of the picture (again), 16-bit word, big-endian
  • bytes 0x222-0x223: width of the picture, 16-bit word, big-endian
  • 0x2E0-end of file: the image data

The easiest way to build the header is to write 736 NULL bytes to the output file, rewind, seek, and write the relevant parts. I am unsure if the resulting file is valid for the official, vintage Quicktake software, but it is valid enough for dcraw to decode it correctly.

Getting the picture:

The next command will get the data of the photo. The flow is the following:

  • Computer: sends {0x16,0x28,0x00,0x10,0x00,0x00,0x01,0x00,0x70,0x80,0x00}. Byte 0x06 is the number of the picture, and bytes 0x07-0x09 are the size of the answer we expect, as a 24-bit, big-endian number. It has to match the size of the picture that we learnt in the previous command. (Picture 1 in this example, 0x007080 bytes long)
  • Camera: sends {0x00}
  • Computer: sends {0x06}
  • Camera: send N bytes of data, depending on the picture’s quality (0x7080 or 0x01C200). The data is sent by blocks of 512 bytes, and the computer acks each block by sending {0x06}. At the end of the transfer, the last block will be shorter than 512 bytes (it will be size modulo 512 bytes), and the computer must not send a {0x06} ack at the end of it.

Getting a thumbnail:

It is possible to get a thumbnail version of the picture, but I didn’t make use of them yet, I didn’t investigate the format. It’s a thumbnail of 80×60 pixels and we receive 2400 bytes of data, so I suppose it’s encoded at 4-bits per pixel and should be easy to decode, but I didn’t do it yet. The flow is the same as getting the full picture, and the command is {0x16,0x28,0x00,0x00,0x00,0x00,0x01,0x00,0x09,0x60,0x00}. Byte 0x03 is different, and bytes 0x07-0x09 are 0x000960, which is 2400 bytes.

Deleting all photos on the camera

It is only possible to delete all pictures, but not possible to delete a single one. The flow for deleting all pictures is:

  • Computer: sends {0x16,0x00,0x00,0x00,0x00,0x00,0x00}
  • Computer: sends {0x16,0x00,0x00,0x00,0x00,0x00,0x00} again
  • Computer: sends {0x16,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
  • Camera: sends {0x00}

The computer does not answer that {0x00} ack.

Setting the camera name

It is possible to change the camera’s name in the following way:

  • Computer: sends {0x16,0x2a,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x22,0x00,0x02,0x20,0x43,0x6F,0x6C,0x69,0x6E,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}
  • Camera: acks with {0x00}

The computer does not answer that ack. The new camera name is at byte 0x0D, and must be precisely 32 bytes long (padded with trailing spaces). In this example, the camera name is “Colin “.

Setting the camera time

It is possible to set the camera’s time in the following way:

  • Computer: sends {0x16,0x2A,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x01,0x06,0x00,0x00,0x00,0x00,0x00,0x00}
  • Camera: acks with {0x00}

The computer does not answer that ack. The date and time are encoded in one 8-bit value per field:

  • byte 0x0D: month (1 to 12)
  • byte 0x0E: day
  • byte 0x0F: year (23 for 2023)
  • byte 0x10: hour
  • byte 0x11: minute
  • byte 0x12: second

Final words

There may be errors or omissions in this document. It has been derived from my implementation of the Quicktake 100 serial protocol, so in case of doubts, please check the source code. I will gladly correct this document if needed, and will complete it with other findings, like when I’ll have figured how to negociate the speed.