Inhaltsverzeichnis
The Scanning Protocol of the Konica Minolta 1690MF
All contents on this page were obtained through observing the communication between the Windows WIA and TWAIN drivers (using the standard windows scanning wizzart) and the multi-function printer connected on the LAN (using wireshark). The purpose is solely for documentational purposes, so that I will be able to write a proper SANE backend to support this device. I do not have any access to any internal documentation of the device or protocol :( I also did not disassemble the windows driver, just looked at the commands sent over the local network.
Scanner hardware details
The protocol described in this document is used at least by the following devices (other devices might use the same protocol, but I have not had access to any of them):
- KONICA MINOLTA magicolor 1690MF, USB-ID: 0x132b:2098
The following values need to be hardcoded in the driver, There is no command to retrieve those values from the scanner!
type | value | used for |
---|---|---|
optical resolution | 600dpi | top/left/width/height of scan area |
color depth | 1/8bit | calculation of parameter of 0x03 08 command |
ADF | present |
The commands
The scanner uses a binary protocol and reacts to 03 xx xx
commands, which might have additional arguments. Each command sent to the scanner has a fixed size (LAN: 64 bytes, USB: 72 bytes), which is padded with 00
if the command does not use arguments of the full length.
- Byte 1:
03
for scanner commands,04
for LAN communication wrapper (1 byte) - Byte 2: The actual command (1 byte)
- Bytes 3-6: Length n of first argument (4 bytes in little endian!)
- Bytes 7-(n+6): First argument (n bytes)
- Byte2 (n+7)-(n+10): (Optional) Length m of second argument (4 bytes in little endian!)
- Bytes (n+11)-…: (Optional) Second argument (m bytes)
- …
- 4 Bytes: 00 00 00 00 - End of command
Known 03
scanner commands:
Command | meaning |
---|---|
03 08 | Start scan |
03 09 | Poll for error |
03 0a | Stop scan / cleanup |
03 0b | Query image parameters |
03 0c | Scan settings |
03 0d | Get status |
03 0e | Read data |
03 0f | Unknown (Get buttons?) |
03 12 | End of scan |
- LAN packets: exactly 64 bytes, command starts at first byte
- The first 2 bytes of the 64-byte block indicate the command
- Remaining bytes are optionally used for arguments to the command
- USB packets: always 72 bytes, command starts at the 25-th byte!
- The first 24 bytes are mostly 00 (byte 17, i.e. 0x10, is typically
01
) - Bytes 25/26 indicate the command
- Remaining bytes are optionally used for arguments to the command
Typically, only 3/8/16/20 bytes will be used for the command, the remaining bytes of the 64/72 byte blocks are padded with 0x00
.
NOTE: The padded bytes to fill the 64/72-byte blocks are truncated in all commands and sniffs below.
Communication wrapper
- USB: No communication wrapper, only
03 xx xx
commands; basically polling for status with03 09 01
until the scan is initiated.
- LAN: General communication wrapper (using
04 xx xx
commands, which have no fixed data size):
<= 04 00 00 (Some HELO/READY message) => 04 01 00 89 20 (Greeting by computer) <= 04 02 00 (ACK by scanner) [Lots of ''03 xx xx'' commands by computer, response data by scanner] => 04 03 00 (BYE)
USB communication
The device uses endpoint #3 (0x03, OUT) for requests sent to the scanner and endpoint #5 (0x85, IN as bit #7 determines IN/OUT of the endpoint as seen from the host=computer) for data sent by the scanner.
Each command sent to the scanner on endpoint 0x03 is answered on endpoint 0x03 by „00 00 00 00 00 00 00 00“. Similarly, when reading data from endpoint 0x85, the computer first sends „00 00 00 00 00 00 00 00“ to the scanner on endpoing 0x85, after which the data is received. This is the general way USB data transfers work. See for example http://wiki.wireshark.org/USB:
- a 'submit', issued when the USB data transfer begins
- a 'completion' or an 'error', issed after the data transfer completion.
The USB data is present only in one of two events associated with an URB. If the transfer direction is from the host to the device, the data is present in the 'submit' event, otherwise the data is present in the 'completion' event. The amount of data effectively present into the event can be less than the amount of data effectively exchanged.
The completion event for transfers to the scanner and the submit event for transfers from the scanner are always '00 00 00 00 00 00 00 00' and will be neglected in all data sniffs below. The events containing the data seem to have an 8-byte header, too, which is also always null, i.e. '00 00 00 00 00 00 00 00'.
LAN communication (''04'' commands)
The network functionality uses TCP port 4567 on the scanner.
When talking to a network-attached device, the communication is established by special 04 …
commands. If they are successfull, then the usual 03
commands are used for the actual scanner commands. At the end of a session, 04
commands are again used to close the session.
These commands are only used when the scanner is connected via the LAN (not via USB). The data length is not padded and is 3 (or 5) bytes exactly, with no further trailing 00.
Dir. | Cmd | Arguments | Description | |
---|---|---|---|---|
⇐ | 04 | 00 | Status | Welcome message by scanner, Status: 00=OK, 01=BUSY |
⇒ | 04 | 01 | 00 USB-ID | Response by Computer, USB-ID in little endian (e.g. 89 20 for the magicolor 1690MF with USB-ID 132b:2089) |
⇐ | 04 | 02 | ACK | Acknowledgement by scanner, ACK=00 for OK, ACK=01 for NOT OK (e.g. invalid USB-ID sent in 04 01 command) |
⇒ | 04 | 03 | 00 | BYE command sent by the computer to the scanner |
All commands with arguments and responses
03 08: Start scan with given parameters
03 08 (Bytes 1-2) | Initiate the scan with given parameters | ||
---|---|---|---|
04 00 00 00 (Bytes 3-6) | Length arg1 (4 bytes) | ||
Bytes 1-4 (7-10) | arg1: Expected return data size: Lines*BytesPerLine (see below) | ||
01 00 00 00 (Bytes 11-14) | Length arg2 (1 byte) | ||
Byte 1 (15) | Unknown | ||
Response: NONE |
Notes for data size (bytes 7-10):
- Lines: Value from Bits 3-4 of the
03 0b
return value - BytesPerLine: image pixels per line (bits 1-2 of the
03 0b
call) * depth/8 * colors
Typical call:
03 08 04 00 00 00 00 6e 10 00 01 00 00 00 00 ...
03 09: Poll for error
03 09 (Bytes 1-2) | Poll for error | ||
---|---|---|---|
01 00 00 00 (Bytes 3-6) | Length arg1 (1 bytes) | ||
Byte 1 (7) | arg1: Unused? Always 00 | ||
Response: | |||
Byte 1 | Error code | ||
00 … OK |
|||
01 … error (feeder, etc) |
|||
02 … Printer open (front or top door, not ADF!) |
|||
03 … already locked (already scanning, web frontend, communication error occured and waiting for button press etc.) |
|||
USB: 00 00 00 00 00 00 00 00 for OK |
Typical call:
03 09 01 00 ... 01
03 0a: Cancel scan
03 0a (Bytes 1-2) | Cancel a scan | |||
---|---|---|---|---|
00 00 00 00 (Bytes 3-6) | Length arg1 (0 bytes) | |||
Response: NONE |
Typical call:
03 0a 00 00 00 00 ...
This command is sent when either the scan was cancelled manually (i.e. the cancel button in the frontend was pressed), or to reset the printer when an error occured (like a paper jam).
03 0b: Query image parameters
03 0b (Bytes 1-2) | Query image parameters | ||
---|---|---|---|
08 00 00 00 (Bytes 3-6) | Length arg1 (8 bytes) | ||
Bytes 1-8 (7-14) | arg1: Unused? Always 00 | ||
Response: | |||
Byte 1-2 | #pixels returned per line(*), padding to multiples of 512 bytes is included, little endian | ||
Byte 3-4 | #lines returned; y-extent*resolution/600dpi, little endian | ||
Byte 5-6 | image pixel per line; x-extent*resolution/600dpi, little endian | ||
Byte 7-8 | image lines, typically same as byte 3-4 |
(*) E.g. in B/W a value of 0x1000
means 4096 pixel = 512 bytes at 1 bit depth.
In Grayscale a value of 0x0200
means 512 pixel = 512 bytes at 8 bith depth, 0x0600
means 1536 pixel(=bytes).
In Color a value of 0x0a00
means 2560 pixel (i.e. 2560 bytes per color channel at 8 bith depth).
Only the number of pixels given in bytes 5-6 is really used, the remaining pixels returned by the scanner appear to be random memory dump data (i.e. some intermediate data from internal image processing, without any useful purpose).
Typical call:
03 0b 08 00 00 00 00 00 00 00 00 00 00 00 ... 00 10 e5 06 e4 04 e5 06
03 0c: Settings for the scan
03 0c (Bytes 1-2) | Set scan options | ||
---|---|---|---|
11 00 00 00 (Bytes 3-6) | Length arg1 (17 bytes) | ||
Byte 1 (7) | Resolution: (00=150dpi, 01=300dpi, 02=600dpi), 1200dpi/2400dpi not supported (also uses 02) | ||
Byte 2 (8) | Color type: (00=B/W, 02=Grayscale, 03=Color) | ||
Byte 3 (9) | Brightness: 05 =0, 01 =-127, 09 =+127 |
||
Byte 4 (10) | Unknown. Always 'ff' | ||
Byte 5-6 (11-12) | x-Start, little endian, pixel in optical resolution(=600dpi) | ||
Byte 7-8 (13-14) | y-Start, little endian, pixel in optical resolution(=600dpi) | ||
Byte 9-10 (15-16) | x-Extent, little endian, pixel in optical resolution(=600dpi) (1) | ||
Byte 11-12 (17-18) | y-Extent, little endian, pixel in optical resolution(=600dpi) (1) | ||
Byte 13 (19) | Source (00 is flatbed, 01 is ADF) |
||
Bytes 14-17 (20-23) | Unknown. Always 00 00 00 00 ? | ||
Response: NONE |
(1) The x-/y-Extents are given in 600dpi (i.e. optical resolution), but with some additional padding. For example, A4 (21×29.7cm) would be 4960,63×7015,75 pixel, but the actual extent sent to the scanner is 5008×7060. The values are not padded to some multiple of 8, 16 or so! Some reference values:
Format | real size | real pixel | sent pixel | difference | |
---|---|---|---|---|---|
A4 | X | 21cm | 4960.63 | 5008 (0x1390) | +47.37 |
Y | 29.7cm | 7015.75 | 7060 (0x1b94) | +44.25 | |
A6 | X | 10.5cm | 2480.31 | 2528 (0x09e0) | +47.69 |
Y | 14.85cm | 3507.87 | 3544 (0x0dd8) | +36.13 | |
FBF | X | 5112 (0x13f8) | |||
Y | 8412 (0x20dc) |
Typical call:
03 0c 11 00 00 00 00 00 05 ff 00 00 00 00 f8 13 dc 20 00 00 00 00 00
03 0d: Get status?
03 0d (Bytes 1-2) | Get status? | ||
---|---|---|---|
0b 00 00 00 (Bytes 3-6) | Length arg1 (11 bytes) | ||
Bytes 1-11 (7-18) | arg1: Unused? Always 00 | ||
Response: | |||
Byte 1 | Unknown, LAN: always ff, USB: 00 | ||
Byte 2 | ADF status (00=no doc loaded, 01=doc loaded) | ||
Byte 3-11 | Unknown, always 00? |
Typical call:
03 0d 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff 00 00 00 00 00 00 00 00 00 00
Typical response:
LAN: ff 00 00 00 00 00 00 00 00 00 00 USB: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00
03 0e: Read scanned data
03 0b (Bytes 1-2) | Read scanned data | ||
---|---|---|---|
04 00 00 00 (Bytes 3-6) | Length arg1 (4 bytes) | ||
Bytes 1-4 (7-10) | arg1: length of requested data chunk in bytes (should be a multiple of bytes_per_line, typically 0xf000 or 0xfa00 or 0xfe00, i.e. 0xef00=61184 bytes, last request will be shorter) | ||
Response: | |||
Bytes 1-… | Scanned data (format see below) |
Typical call:
03 0e 04 00 00 00 00 fe 00 00 [0xFE00 bytes of scan data sent to computer]
03 0f: Unknown
03 0f (Bytes 1-2) | Unknown | ||
---|---|---|---|
01 00 00 00 (Bytes 3-6) | Length arg1 (1 bytes) | ||
Byte 1 (7) | arg1: Unused? Always 00 | ||
Response: | |||
Byte 1 | Unknown, always 00 |
Typical call:
03 0f 01 00 00 00 00 00
Ilia Sotnikov: function is „Get buttons“
03 12: Unknown
03 12 (Bytes 1-2) | Unknown | ||
---|---|---|---|
0b 00 00 00 (Bytes 3-6) | Length arg1 (11 bytes) | ||
Bytes 1-11 (7-17) | arg1: Unused? Always 00 | ||
Response: | |||
Bytes 1-11 | Unknown, always 00? |
Typical call:
03 12 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Typical response:
LAN: 00 00 00 00 00 00 00 00 00 00 00 USB: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00
Further commands, not (yet?) found with the 1690MF
Ilia Sotnikov has decoded the USB data flow of the BizHub 162/132 and DiMage 1611 devices, which are B/W only and USB only.
03 10: Set button wait
03 10 (Bytes 1-2) | Set button wait | ||
---|---|---|---|
0? 00 00 00 (Bytes 3-6) | Length arg1 (? bytes) | ||
Bytes 7-? | arg1: ? | ||
Response: ? |
Sequence of commands of a typical communication (Pseudo-code)
'⇒' indicates data/command sent to scanner, '⇐' indicated data returned by the scanner (request data packet omitted here!):
Handshake / Opening connection
Scanning operation
Error handling
LAN: Device and capabilities detection via SNMP
The Windows installer apparently employs SNMP to detect network-connected devices. An SNMP broadcast is sent to the address 255.255.255.255, and if SNMP is enabled on the scanner, it will respond properly.
Interesting OIDs (used by the windows driver to detect the device):
- 1.3.6.1.2.1.1.1.0 (SNMPv2-MIB::sysDescr.0) = STRING: KONICA MINOLTA magicolor 1690MF
- 1.3.6.1.2.1.1.2.0 (SNMPv2-MIB::sysObjectID.0) = OID: SNMPv2-SMI::enterprises.18334.1.1.1.1.1.23.1.1
- 1.3.6.1.2.1.2.2.1.6.1 (IF-MIB::ifPhysAddress.1) = STRING: 0:20:6b:cc:6:77
Image format returned by the scanner
The data format is fairly simple: Simply one pixel after each other, one line after each other (without any newline indicators).
There is no image header returned. All image size information must be used from the 03 0b
request call for pixels_per_line and from the argument passed to the 03 08
start scan command for the BytesPerLine value.
The only pitfall is that each line always uses a multiple of 512 bytes (the exact number of data pixels per line is returned in the 03 08
call and needs to be uses, as there is no other obvious way to calculate the value), so some additional bytes are added to pad each line to such a multiple. When passing on the image data to a scanning frontend, one needs to make sure these additional padding pixels are ignored. The following image shows an example of the whole FBF area and the actuall image sent by the scanner (where each line uses at least 512 bytes). Most of the image data sent by the scanner must be ignored:
Black & White, Lineart
The image data for 1-bit B/W is simply a bit-by-bit representation of the scanned data, i.e. 8 pixels per byte, one byte after the other. Each line uses exactly BytesPerLine
bytes (i.e. a multiple of 512 bytes!), where only the first PixelsPerLine bits are used, the rest can and should be ignored.
Grayscale
The image data for 8-bit Grayscale is simply a byte-by-byte representation of the scanned data, i.e. 1 pixel per byte, one byte after the other. Each line uses exactly BytesPerLine
bytes (i.e. a multiple of 512 bytes!), where only the first PixelsPerLine bytes are used, the rest can and should be ignored.
Color
The format of color scans is the same as for Grayscale images, with the only difference that the R/G/B scan data is returned one line after the other (each of them is padded as described above!). So the individual values for the RGB bytes of one pixel are actually scan_pixels_per_line apart in the returned data.
Open questions
- Are the padding bytes useful in any way?
Example communications
- Scans with various settings (only those parts of the communication containing the parameters)