# P.I. Engineering SDK Help

## X-keys XC-DMX512T Data Report

### General Information

The X-keys XC-DMX512T-RJ45 and XC-DMX512T-ST are devices that can transmit user provided data into the DMX512 communication protocol. 2 RJ-45 connectors are provided for outputting and standard daisy chaining of the DMX signal for the XC-DMX512T-RJ45 version and a screw terminal is provided for the XC-DMX512T-ST version. Using the P.I. Engineering SDK samples users can create a software solution to driving their DMX peripherals. In addition the XC-DMX512T-R45 has 8 digital inputs (4 ports with a left and right on each) and the XC-DMX512T-St has 12 digital inputs (6 ports with a left and right on each) to allow for switches to be connected.

VID | 05f3h
XC-DMX512T-RJ45 | 04C9h or 1224
XC-DMX512T-ST | 052Ch or 1324
Consumer Usage Page | 1
Usage Page | 000Ch or 12

PID #1 Endpoints: Consumer Usge Page Input and Output (Hid Usage Page 12, Hid Usage 1), Keyboard (Hid Usage Page 1, Hid Usage 6).

The XC-DMX512T is an Android enabled device. This means the device can be enumerated, read, and written to on Android OS that support host USB, generally 3.1 or higher.

IAB-DMX512T is supported by P.I. Engineering Macroworks 3.1 and X-keys Basic Setup for PC users, P.I. Engineering SDK samples for Microsoft C# Express, VB Express, Microsoft C++ 2010 and Eclipse and Linux.

### X-keys XC-DMX512T Input Report

Report Length: 37 bytes

1a. General Incoming Data for XC-DMX512T-RJ45 Switch Data

This data is returned when new data is detected such as button presses or unit id change. This report can be manually stimulated by sending an output report: Generate Data which is very useful for obtaining the initial state of the device immediately after enumeration.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Bytes 7-37
Constant | Unit ID | Data Type | Jacks 1-4 | Reserved | NumLck, CapsLck, ScrLck | Reserved
0 | <data> | DT | D1 | value | DS | value

DT: Data Type value of 0 or 2 indicates the following data is a General Incoming Data report, 2 if generated by the output report: Generate Data. Data Type value of 214 (0xd6) indicates a Descriptor Data Report, see below. Data Type value of 224 (0xE0) indicates a Custom Data Report, see below.
D1: If using a splitter to read both L and R then for all bits 0 for switch open, 1 for switch closed. If plugging in a mono switch to the jack then the corresponding R will always be closed for that jack. Bit 1=1R, bit 2=1L, bit 3=2R, bit 4=2L, bit 5=3R, bit 6=3L, bit 7=4R, bit 8=4L.
DS: Bit 1=NumLock, bit 2=CapsLock, bit 3=ScrLock.

1b. General Incoming Data for XC-DMX512T-ST Switch Data

This data is returned when new data is detected such as button presses or unit id change. This report can be manually stimulated by sending an output report: Generate Data which is very useful for obtaining the initial state of the device immediately after enumeration.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Bytes 7-37
Constant | Unit ID | Data Type | Jacks 1-4 | Jacks 5-6 | NumLck, CapsLck, ScrLck | Reserved
0 | <data> | DT | D1 | D2 | DS | value

DT: Data Type value of 0 or 2 indicates the following data is a General Incoming Data report, 2 if generated by the output report: Generate Data. Data Type value of 214 (0xd6) indicates a Descriptor Data Report, see below. Data Type value of 224 (0xE0) indicates a Custom Data Report, see below.
D1: If using a splitter to read both L and R then for all bits 0 for switch open, 1 for switch closed. If plugging in a mono switch to the jack then the corresponding R will always be closed for that jack. Bit 1=1R, bit 2=1L, bit 3=2R, bit 4=2L, bit 5=3R, bit 6=3L, bit 7=4R, bit 8=4L.
D2: If using a splitter to read both L and R then for all bits 0 for switch open, 1 for switch closed. If plugging in a mono switch to the jack then the corresponding R will always be closed for that jack. Bit 1=5R, bit 2=5L, bit 3=6R, bit 4=6L, bit 5-8=0.
DS: Bit 1=NumLock, bit 2=CapsLock, bit 3=ScrLock.

2. Descriptor Data

This data is returned after an output report: Request for Descriptor is sent.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 | Byte 8 | Byte 9 | Byte 10 | Byte 11 | Byte 12 | Byte 13 | Byte 14 | Byte 15 | Byte 16 | Byte 17 | Bytes 18-37
Constant | Unit ID | Data Type | Mode | Key mapstart | Layer2 Offset | Constant | Constant | Max Columns | Max Rows | LED State | Version | PID Low | PID Hi | Key mapstart hi | Max Address lo | Max Address hi | Reserved
0 | <data> | 214 | Mode | 32 | 208 | 255 | 255 | 2 | 8 | LEDs | <data> | PIDL | PIDH | 0 | value | value | value

Mode: 0
LEDs: Device has 2 LEDs, this byte tells the current state of the outputs. Bit 7 set means Green LED is on, bit 8 set means Red LED is on.
PIDL: LSB of the Product Identification number or PID.
PIDH: MSB of the Product Identification number or PID.

3. Custom Data

This data is returned after an output report: Generate Custom Data is sent.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 | Bytes Count+5 to 36 | Byte 37
Constant | Unit ID | Data Type | Count of custom bytes to follow | Custom byte 1 | Custom byte 2 | Custom byte 3... | Reserved | Increment
0 | <data> | 224 | Count | B1 | B2 | B3... | value | Increment

Count: Number of custom bytes to follow.
B1: 1st custom byte.
B2: 2nd custom byte.
B3: 3rd custom byte and so on for as many bytes as specified in Count.
Increment: This byte is incremented each time a Custom Data report is sent thus even if 2 identical reports are sent they will both come in even if SuppressDuplicate reports is on.

4. Check Dongle Key

This is received immediately following a Check Dongle Key output report is sent. The four values R0-R3 are required to continue the check. See Dongle Implementation for further details.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 | Bytes 8 to 36
Constant | Unit ID | Data Type | 1st byte returned from hash | 2nd byte returned from hash | 3rd byte returned from hash | 4th byte returned from hash | Reserved
0 | <data> | 193 | R0 | R1 | R2 | R3 | value

R0: Value need for comparison to check for correct dongle key.
R1: Value need for comparison to check for correct dongle key.
R2: Value need for comparison to check for correct dongle key.
R3: Value need for comparison to check for correct dongle key.

### X-keys XC-DMX512T Output Report

The following types of output reports are shown in the summary below. Please be aware that several of these commands result in writing to the device's eeprom which has a limit to the number of writes allowed before it is "burnt out". The manufacturer's specification is 50,000 eeprom writes. Because of this we recommend the commands designated with e be executed rarely and not within timing loops. Note, the first byte listed in this documentation is 0 and represents the report ID. This is not present on some non-PC operating systems. So when sending an output report on Android for example, eliminate this byte.

Report | Format | Description
--- | --- | ---
1 | 0, 179, LEDIndex, State, 0... | Set LED
2 | 0, 189, UnitID, 0... | Set Unit IDe
3 | 0, 214, 0... | Request Descriptor
4 | 0, 177, 0... | Generate Data
5 | 0, 208, Count, 0, B1, B2, B3... | Send DMX
6 | 0, 209, Count, B1, B2, B3..., 0... | Append DMX
7 | 0, 224, Count, B1, B2, B3..., 0... | Generate Custom Data
8 | 0, 195, Version LSB, Version MSB, 0... | Set Version Numbere
9 | 0, 238, 0... | Reboot Device
10 | 0, 201, Modifier, 0, HC1, HC2, HC3, HC4, HC5, HC6, 0... | Keyboard Reflector
11 | 0, 192, K0, K1, K2, K3, 0... | Set Dongle Keye
12 | 0, 193, N0, N1, N2, N3, 0... | Check Dongle Key

eCommand writes to EEPROM, do not perform this command excessively, do not exceed 50,000 writes to EEPROM.

Endpoint: Vendor Defined Usage Page.

Report Length: 36 bytes.

1. Set LED

Send this output report to control the green indicator LED.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Bytes 5-36
Constant | Command | LED Index | LED State | Constant
0 | 179 | LEDIndex | LEDState | 0

LEDIndex: 6 = Green LED.
LEDState: 0 = off, 1 = on.

2. Set Unit ID

Send this output report to set the Unit ID of the device. This is useful if connecting more than one of the same device to the a computer.

Byte 1* | Byte 2 | Byte 3 | Bytes 4-36
Constant | Command | Unit ID (0-255) | Constant
0 | 189 | value | 0

3. Request Descriptor

After sending this output report a Descriptor input report will be generated.

Byte 1* | Byte 2 | Bytes 3-36
Constant | Command | Constant
0 | 214 | 0

4. Generate Data

After sending this output report a General Incoming Data input report will be generated with bit 2 of PS set. This is useful in determining the initial state of the device before any data has changed.

Byte 1* | Byte 2 | Bytes 3-36
Constant | Command | Constant
0 | 177 | 0

5. Send DMX

The DMX bytes must be sent out in blocks of 32 since the size of the IAB-DMX512T's output report length is 36 and there are required prefix bytes. The first block sent, slots 1 to 32 is special as it includes a start byte. Note that the Count includes this start byte. If the desired number of slots is less than 32 the remaining bytes are 0. Typically this output report along with any required Append DMX output reports would be executed continuously usually using a timer.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7... | Bytes (Count+4) to 36
Constant | Command | Count of DMX bytes to follow plus start byte | Start byte | DMX byte 1 | DMX byte 2 | DMX byte 3... | DMX byte or Constant
0 | 208 | Count | 0 | B1 | B2 | B3... | value or 0

Count: Number of bytes to follow. If there are 32 DMX slots to transmit then Count=33.
B1: DMX value for slot 1, 0-255.
B2: DMX value for slot 2, 0-255.
B3: DMX value for slot 3, 0-255 and so on for as many bytes as specified in Count - 1. If less than 32 slots to send then fill remaining bytes with 0.

6. Append DMX

If the desired number of slots is greater than 32 then Append DMX output report(s) must be sent immediately following the Send DMX output report. Since there is no Start byte for this report the user can technically send 33 bytes of DMX data. For simplicity however our samples send the DMX data in blocks of 32 thus the number of times this report must be sent is A=(total number of slots)/32 rounded up to the next integer minus 1 because the first block was sent using Send DMX already. In the table below n=1 to A.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6... | Bytes (Count+4) to 35 | Byte 36
Constant | Command | Count of DMX bytes to follow plus start byte | DMX byte n*32 | DMX byte n*32+1 | DMX byte n*32 +3... | DMX byte or Constant | Constant (if sending in blocks of 32)
0 | 209 | Count | B1 | B2 | B3... | value or 0 | 0

Count: Number of bytes to follow.
B1: DMX value for slot n*32, 0-255. Where n=1, 2, ... 15 max, so B1 could be value for slot 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480
B2: DMX value for slot n*32+1, 0-255. B2 could be 33, 65, 97, etc.
B3: DMX value for slot n*32+2, 0-255 and so on for as many bytes as specified in Count.

Example 1: 12 slots with slot 1 = 10, slot 2 = 20, slot 3 = 30, slot 4 = 40, slot 5 = 50, slot 6 = 60, slot 7 = 70, slot 8 = 80, slot 9 = 90, slot 10 =100, slot 11 = 110 and slot 12 = 120.
This sample has less than 33 slots so it can be transmitted with just one output report:

    C#

    private void timer1_Tick(object sender, EventArgs e)
    {
    	//this timer is running at 50ms intervals

    	for (int j = 0; j < devices[selecteddevice].WriteLength; j++)
        {
            wData[j] = 0; //fill with 0s
        }
        wData[0] = 0;
        wData[1] = 0xd0;
        wData[2] = 13; //12 slots + start byte
        wData[3] = 0;  //start byte
    	wData[4] = 10; //slot 1 value
    	wData[5] = 20; //slot 2 value
    	wData[6] = 30; //slot 3 value
    	wData[7] = 40; //slot 4 value
    	wData[8] = 50; //slot 5 value
    	wData[9] = 60; //slot 6 value
    	wData[10] = 70; //slot 7 value
    	wData[11] = 80; //slot 8 value
    	wData[12] = 90; //slot 9 value
    	wData[13] = 100; //slot 10 value
    	wData[14] = 110; //slot 11 value
    	wData[15] = 120; //slot 12 value
     	int result = 404;
        while (result == 404) { result = devices[selecteddevice].WriteData(wData); }   //data transmitted

    }

Example 2: 140 slots with the value of the slots stored in a byte array called slots[] where slot 1 value is slots[0] and slot 140 value is slots[139]. This sample will require per timer interval the first Send DMX report for slots 1-32 and then 4 subsequent Append DMX reports for slots 33-140.

    C#

    private void timer1_Tick(object sender, EventArgs e)
    {
    	//this timer is running at 50ms intervals

    	for (int j = 0; j < devices[selecteddevice].WriteLength; j++)
        {
            wData[j] = 0; //fill with 0s
        }
        //send the first 32 slots
        wData[0] = 0;
        wData[1] = 0xd0; //Send DMX
        wData[2] = 33; //32 slots + start byte
        wData[3] = 0;  //start byte
    	for (int j=0;j<32;j++)
    	{
    		wData[j+4]=(byte)slots[j]; //slots 1-32
    	}
     	int result = 404;
        while (result == 404) { result = devices[selecteddevice].WriteData(wData); }   //data transmitted

    	//send next block of 32
    	for (int j = 0; j < devices[selecteddevice].WriteLength; j++)
        {
            wData[j] = 0; //fill with 0s
        }
    	wData[0] = 0;
        wData[1] = 0xd1; //Append DMX
        wData[2] = 32; //32 slots
    	for (int j=0;j<32;j++)
    	{
    		wData[j+3]=(byte)slots[j+32]; //slots 33 to 64
    	}
     	int result = 404;
        while (result == 404) { result = devices[selecteddevice].WriteData(wData); }   //data transmitted

    	//send next block of 32
    	for (int j = 0; j < devices[selecteddevice].WriteLength; j++)
        {
            wData[j] = 0; //fill with 0s
        }
    	wData[0] = 0;
        wData[1] = 0xd1; //Append DMX
        wData[2] = 32; //32 slots
    	for (int j=0;j<32;j++)
    	{
    		wData[j+3]=(byte)slots[j+(2*32)]; //slots 65 to 96
    	}
     	int result = 404;
        while (result == 404) { result = devices[selecteddevice].WriteData(wData); }   //data transmitted

    	//send next block of 32
    	for (int j = 0; j < devices[selecteddevice].WriteLength; j++)
        {
            wData[j] = 0; //fill with 0s
        }
    	wData[0] = 0;
        wData[1] = 0xd1; //Append DMX
        wData[2] = 32; //32 slots
    	for (int j=0;j<32;j++)
    	{
    		wData[j+3]=(byte)slots[j+(3*32)]; //slots 97 to 128
    	}
     	int result = 404;
        while (result == 404) { result = devices[selecteddevice].WriteData(wData); }   //data transmitted

    	//send next block of 32
    	for (int j = 0; j < devices[selecteddevice].WriteLength; j++)
        {
            wData[j] = 0; //fill with 0s
        }
    	wData[0] = 0;
        wData[1] = 0xd1; //Append DMX
        wData[2] = 32; //32 slots
    	for (int j=0;j<(140-128);j++)
    	{
    		wData[j+3]=(byte)slots[j+(4*32)]; //slots 129 to 140
    	}
     	int result = 404;
        while (result == 404) { result = devices[selecteddevice].WriteData(wData); }   //data transmitted
    }

7. Generate Custom Data

After sending this output report a Custom Data input report will be generated with Byte 3 set to 224 and the count and custom bytes following.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6... | Bytes (Count+4) to 36
Constant | Command | Count of custom bytes to follow | Custom byte 1 | Custom byte 2 | Custom byte 3... | Constant
0 | 224 | Count | B1 | B2 | B3... | 0

Count: Number of custom bytes to follow.
B1: 1st custom byte.
B2: 2nd custom byte.
B3: 3rd custom byte and so on for as many bytes as specified in Count.

8. Set Version Number

Send this output report to set the Version of the device. This is not the firmware version given in the descriptor but a 2 byte number available on enumeration. The value is "remembered" so if it is changed, using this report, the device must be rebooted. The device can be rebooted by replugging it or by sending the output report : Reboot Device.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Bytes 5-36
Constant | Command | Version LB (0-255) | Version HB (0-255) | Constant
0 | 195 | value | value | 0

9. Reboot Device

Send this output report to reboot the device without having to unplug it. After sending this report the device must be re-enumerated.

Byte 1* | Byte 2 | Bytes 3-36
Constant | Command | Constant
0 | 238 | 0

10. Keyboard Reflector

Sends native keyboard messages.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 | Byte 8 | Byte 9 | Byte 10 | Bytes 11-36
Constant | Command | Modifier | Constant | Hid Code 1 | Hid Code 2 | Hid Code 3 | Hid Code 4 | Hid Code 5 | Hid Code 6 | Constant
0 | 201 | Modifier | 0 | HC1 | HC2 | HC3 | HC4 | HC5 | HC6 | 0

Modifier: Bit 1=Left Ctrl, bit 2=Left Shift, bit 3=Left Alt, bit 4=Left Gui, bit 5=Right Ctrl, bit 6=Right Shift, bit 7=Right Alt, bit 8=Right Gui.
HC1=Hid Code for 1st key down, or 0 to release previous key press in this byte position.
HC2=Hid Code for 2nd key down, or 0 to release previous key press in this byte position.
HC3=Hid Code for 3rd key down, or 0 to release previous key press in this byte position.
HC4=Hid Code for 4th key down, or 0 to release previous key press in this byte position.
HC5=Hid Code for 5th key down, or 0 to release previous key press in this byte position.
HC6=Hid Code for 6th key down, or 0 to release previous key press in this byte position.

11. Set Dongle Key

Sets the user entered key. Remember these numbers as they are required to check for the key. This is intented to be done once by the developer prior to sale. See Dongle Implemenation for more details.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Bytes 7-36
Constant | Command | 1st byte of key | 2nd byte of key | 3rd byte of key | 4th byte of key | Constant
0 | 192 | K0 | K1 | K2 | K3 | 0

K0: 1st byte of user determined dongle key, any number 1-254.
K1: 2nd byte of user determined dongle key, any number 1-254.
K2: 3rd byte of user determined dongle key, any number 1-254.
K3: 4th byte of user determined dongle key, any number 1-254.

12. Check Dongle Key

Checks the key that was entered in Set Dongle Key. This is intented to be done by the developer within their own software to determine if the connected X-keys device is the one they sold to the customer. 4 random bytes along with the actual key are entered into the DongleCheck2() hash function of the Piehid32.dll/PieHid32Net.dll which returns 4 bytes. Then after sending this output report a Check Dongle Key input report will be received containing the same 4 bytes returned from the hash if the key matches. See Dongle Implemenation for more details.

Byte 1* | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Bytes 7-36
Constant | Command | Random number | Random number | Random number | Random number | Constant
0 | 192 | N0 | N1 | N2 | N3 | 0

K0: 1st byte of a random number that was used in the hash, any number 1-254.
K1: 2nd byte of a random number that was used in the hash, any number 1-254.
K2: 3rd byte of a random number that was used in the hash, any number 1-254.
K3: 4th byte of a random number that was used in the hash, any number 1-254.

*This first byte may be omitted on some non-PC operating systems. On these systems the read and write lengths will be 1 byte smaller.

Back to top