CDJ HID Protocol
Background
Historically, DJ controllers (meaning hardware whose purpose is to communicate with digital DJ Software) have been using MIDI over USB. With increasing complexity, the protocol became a bottleneck for certain applications, causing Hardware-manufacturers to start transmitting data via HID. This allows for comparatively simple mechanisms such as simply serializing the status of controls on the controller into a buffer of fixed format but also creating complex proprietary binary protocols involving data fragmented over multiple HID packets, handshakes, variable-length data, etc.
The PioneerDJ CDJ-2000NXS2 has many different ways to communicate with other devices such as other CDJs or Mixers. One if these methods is using a custom Network Protocol called ProDJLink whose reverse engineering efforts have inspired this project as well.
Protocol primitives
Simple header
Every Packet being sent and received to and from the CDJs shares this common header:
The first byte "deck" uses the more significant nibble to indicate the source/destination deck. It uses 0 for controllers which only have/represent a single deck such as a CDJ and 1-based deck numbers for controllers with multiple decks such as the XDJ-XZ. The "type" byte indicates the type of message being transmitted. This format limits the maximum amount of data transmitted to 62 Bytes which is not sufficient for transmitting larger strings or other binary data such as images. For these purposes, the protocol uses an extended header
Extended Header
Packets with an extended header are able to transmit Bytes (~3.8MB) of data.
L
denotes the number of packets the data following
takes up while I
indicates the index of the packet fragment in the current stream.
Both ushorts encoded in little-endian byte order.
Sysex Extended Header
For packets exchanged via Sysex (such as the DJM-750MK2 and DJM-250MK2), the header has a slightly different format again:
The green 0xf0
is just the sysex start. After which follows an extended
manufacturer ID (likely the one belonging to Pioneer/AlphaTheta). The four bytes
following seem to be the USB Product ID (PID), seemingly followed by the deck
index (0x00
for mixers). Afterwards, the inner data follows which is
terminated by trailing Sysex EOX (0x7F
). Thank you
František Kučera a.k.a. xkucf03 for
their
work on the DJM-250MK2 which helped me spot these differences in the sysex version.
since the PID is 16-bits long (8-bit bytes), but sysex only transmits 7-bit bytes, the 4 4-bit nibbles of the PID are then spaced out over the four 7-bit bytes in the sysex (each nibble occupying the 4 least significant bits). |
TLV Structure
Some parts of the Protocol utilize a TLV structure:
These TLV structures can occur nested (for example in the handshake)
It seems T
only indirectly describes the actual type of data in the buffer. Instead T
indicates what the data is actually used for, which in turn describes the actual
type of the data.
Thanks
An enormous thanks to James Elliot (@brunchboy) from Deep Symmetry for not only creating bytefield-svg which allowed me to create these awesome bytefield diagrams but also for all of his previous research into the ProDJLink Protocol as well as helping me in the setup of this wiki, using bytefield-svg and supplying me with some USB-Captures of the XDJ-XZ. Also thanks to Ard van Breemen for helping out with his in-depth knowledge of the USB protocol. In addition I also want to thank František Kučera for using my research in his effort to bring Linux Support to the DJM-250MK2 and correcting me in his blogpost. I’d also like to thank Ashley Skye for [contributing the Rekordbox vendor Device ID for the DJM-900NXS2](https://github.com/Swiftb0y/CDJHidProtocol/pull/7)