Start a Conversation

Unsolved

This post is more than 5 years old

12474

October 25th, 2016 16:00

P4317Q, RS232 interface

Has anyone worked with the RS232 interface for the P4317Q monitor? I'm trying to get some basic queries of information working and I seem to be having trouble with the checksum values. The documentation (see below) isn't very clear on how the checksum is calculated and I've tried a couple methods for doing it without 100% success. I'd be interested in hearing if anyone has written any code to interface with the RS232 on this monitor and might be willing to share? Or, if there's a bit more in-depth sample code from Dell on the subject?

Thanks,

Jason

P4317Q RS232 Protocol Document

234 Posts

October 28th, 2016 06:00

Just a guess - the docs give this example message:

Example: Get Monitor Name (Maximum 10 characters)

[From PC to Monitor] = S, 37a, 51a, 02a, EBa, 01a, CHKp

Try using this message instead:

[From PC to Monitor] = S, 37a, 51a, 02a, EBa, 01a, 8Ep

if CHK=8E doesn't work, try E1.

4 Posts

October 28th, 2016 09:00

Thanks for the reply.

I've realized that I can't tell if those values for checksum are valid on the way to the monitor because it doesn't seem to do any checking.  For the 8E value, I can't use the basic XOR method to validate the checksum in the response from the monitor.  I'm not sure how you got E1.  What was the method for arriving at E1?

The following is the entire response I get back from the monitor:

   6f:37:0f:02:00:01:44:65:6c:6c:20:50:34:33:31:37:51:00:0d

As you can see, the checksum on that is 0D, but I can't figure out what method the monitor has used to generate that value.  Simple XOR results in 55.

I would like to figure out how to validate these checksums, but at the end of the day, it seems to not be necessary.  The monitor obviously isn't insisting on them being correct, and my use of the responses doesn't depend on them either.

Thanks!

234 Posts

October 29th, 2016 05:00

The checksum in your reply appears to be the XORed result of the payload excluding the header.

0F:02:00:01:44:65:6C:6C:20:50:34:33:31:37:51:00 = 0D

If that's so, the checksum for the command message would be:

02:EB:01 = E8

December 13th, 2016 08:00

Sorry to hijack your thread but I'm also trying to use the RS232 port to remotely administer my P4317Q and am having trouble.

Did you use a straight-through or null modem cable?

(If using Linux) how did you determine which /dev/ttyS* was being used?

For writing to the serial port, what did you send to the monitor get the monitor name? e.g.:

echo -ne ' S, \x37a, \x51a, \x02a, \xEBa, \x01a' > /dev/ttyS*

How did you go about viewing the response from the monitor? e.g.:

cat -v < /dev/ttyS*

Thanks.

3 Posts

February 4th, 2017 09:00

What are the significance of "S" and "p"?

5 Posts

March 29th, 2017 09:00

S, a, p seem to be some sort of notation in their API documentation, but not used.

They do mention the pinout, but it is non-standard, in that both my workstation and monitor have female DB-9 connectors, which suggests the use of a Null-Modem cable. That is wrong. I got it working with straight cable and a M-M gender changer adapter. Dell, please use Male connectors on future monitors or swap your TX/RX. I tested with firmware M2C103.

There are also many errors and omissions, incorrect lengths, and misleading formats in the documentation, eg:

Example itself implies it will return this: o7????P4317Q

I ran the cmd: 375102eb018e
it returned: o7\0x0f\0x02\0x00\0x01Dell P4317Q\0x00

So much for the "Maximum 10 characters", "Dell P4317Q" is 11.

GetBacklightHours returned LSB first (0x02f6 aka 758 hrs is correct).
6f 37 05 02 00 04 f6 02 f7

PBP sub-inputs are missing, here they are:
01:Mhl1
02:Mhl2
08:DP
10:mDP
40:VGA

Checksum value can be excluded, or simply 00

Extra trailing 00s are safe.

If you get 'Len' incorrect, no response is returned at all.

As per documentation GetPxPSubInput takes no parameters and returns 4 values. In reality, first param is the subinput window: 0-3. Response for fetching top left corner (2) returns 10 (mDP)

sent: 375102eb710200
returned: 6f 37 07 02 00 71 10 00   00 00 64

Errors look like: 6f 37 03 02 ff 71 8f  (trying to get subwindow > 3)

I planned on creating a whole Java program to query / set arbitrary CMDs, but based on the inaccuracies in this document, that will be a painful process.

Here are two bash scripts I made instead.


#!/bin/bash
# This script enables quadsplit PBP and sets each subinput
# on my system, DP1 = mDP, DP2 = DP, both connected to workstation
# uses xrandr to set the resolution of my workstation to 1920x2160
# reference guide: dell-p4317q-monitor_reference guide_rs232_api_en-us.pdf

export DISPLAY=:0

#SetPxPMode |  Head0 Head1 Len R/W Cmd Data Chksum
echo -ne '\x37\x51\x02\xea\x70\x08\x00' > /dev/ttyUSB0

# set DP on bottom left
echo -ne '\x37\x51\x03\xea\x71\x01\x08\x00' > /dev/ttyUSB0
sleep 3
# set VGA on bottom right
echo -ne '\x37\x51\x03\xea\x71\x00\x40\x00' > /dev/ttyUSB0
sleep 3
# set mDP on top left
echo -ne '\x37\x51\x03\xea\x71\x02\x10\x00' > /dev/ttyUSB0
sleep 3
# set MHL1 on top right
echo -ne '\x37\x51\x03\xea\x71\x03\x01\x00' > /dev/ttyUSB0
sleep 3

# set MHL2 on top right
# echo -ne '\x37\x51\x03\xea\x71\x03\x02\x00' > /dev/ttyUSB0

chvt 7
sleep 3
xrandr --auto
xrandr --output DP1 --mode 1920x1080
xrandr --output DP2 --mode 1920x1080
xrandr --output DP2 --below DP1


#!/bin/bash
# This script disables any PBP settings, and sets mDP to 4k
# on my system, DP1 = mDP, DP2 = DP, both connected
# reference guide: dell-p4317q-monitor_reference guide_rs232_api_en-us.pdf

export DISPLAY=:0

# disable quadsplit (Dell resets input to VGA, even with autoselect off)
echo -ne '\x37\x51\x02\xea\x70\x00\x00' > /dev/ttyUSB0
sleep 3

# set primary input to mDP
echo -ne '\x37\x51\x03\xea\x62\x10\x00\x00' > /dev/ttyUSB0
sleep 3

# force 4k resolution on mDP, disable DP
xrandr --auto
xrandr --output DP1 --mode 3840x2160
xrandr --output DP2 --off


Hope that helps you fine folks. This is an amazing monitor, even though the API is frustrating, the control via RS-232 is great.

5 Posts

March 31st, 2017 14:00

Seems like the update to M2C104 broke the API.

from my notes:

---
the LED works though! proves the checksum is not needed, even for set operation
375103ea210000 turned off the LED
375103ea210100 turned on the LED
---

no longer works :(

3 Posts

April 10th, 2017 14:00

Thanks kevinf28.  Tried the commands you posted earlier and for the first time saw anything from my monitor, yay!  Once that worked, I suspect one thing that might have gone wrong earlier is that I was testing with commands that were failing silently (like polling for the asset tag)?  Hard to say.

But I should note that I was seeing some strange behaviors where some responses were being buffered (I'm not sure whether that was in the computer or monitor).  And the some of the commands I tried playing with were not following the documented format, particularly the length field.

So, naturally I updated to 104 and things stopped working.  More interesting is that the monitor started responding to every command, both sets and gets.  And it's even giving response codes for why things are failing.

At this point, I'm only seeing 02 (parameter errors) and 01 (timeout).  Seems like something of an improvement.  I suspect that it might actually be checking the checksums.  Time to write a quite parser and play around with potential checksums.

4 Posts

April 10th, 2017 17:00

The following is the python program I put together to query and set values in the monitor.  It's not super beautiful, but it works well.  You likely will need to change the name of the serial port in the  p4317q_handle_command function.  Also, it relies on PySerial, so you need that, too.

I've been using it for several months now and it has served well.  I haven't upgraded to the 104 firmware, either.  Not sure I'll do that if it breaks everything.  :)

#!/usr/bin/python

import sys

import struct

import serial

import binascii

debug=False

CMD_HEADER=bytearray([0x37, 0x51])

CMD_READ=0xEB

CMD_WRITE=0xEA

# Only get commands have a response.

RSP_HEADER=bytearray([0x6F, 0x37])

RSP_REPLY_CODE=0x02

def print_debug(message):

   "Debug print message"

   if (debug == True):

       print message

def print_usage():

   "Print program usage"

   print sys.argv[0] + " usage:"

   print sys.argv[0] + "{get|set|reset} {command} [parameter]"

   print ""

   print "get   - Retrieves information from the monitor"

   print "set   - Sets a value in the monitor"

   print "reset - Resets a monitor capability"

   print ""

   print " parameter is required only for set commands"

   print ""

   print "get commands:"

   print "    assettag, monitorname, monitorserial, backlighthours"

   print "    powerstate, powerled, powerusb"

   print "    brightness, contrast, aspectratio, sharpness"

   print "    inputcolorformat, colorpresetcaps, colorpreset, customcolor"

   print "    autoselect, videoinputcaps, videoinput"

   print "    pxpmode, pxpsubinput, pxplocation"

   print "    osdtransparency, osdlanguage, osdtimer, osdbuttonlock"

   print "    versionfirmware, ddcci, lcdconditioning"

   print ""

   print "set commands:"

   print "    powerstate, powerled, powerusb"

   print "    brightness, contrast, aspectratio, sharpness"

   print "    inputcolorformat, colorpreset, customcolor"

   print "    autoselect, videoinput"

   print "       Video Input Names:"

   print "           vga, dp, mdp, hdmi1, hdmi2"

   print "    pxpmode, pxpsubinput, pxplocation"

   print "       PxP modes:"

   print "           4k:        3840x2160 full screen"

   print "           smallPip:  3840x2160 full screen (primary video input)"

   print "                      small inset picture-in-picture"

   print "           bigPip:    3840x2160 full screen (primary video input)"

   print "                      large inset picture-in-picture"

   print "           4x4:       four 1920x1080 panes"

   print "           1x2:       one 3840x1080 window over 2x 1920x1080"

   print "           2x1:       one 1920x2160 window right of 2x 1920x1080"

   print "           SxS:       two 1920x2160 panes"

   print "       PiP Locations:"

   print "           topRight, topLeft, bottomRight, bottomLeft"

   print "    osdtransparency, osdlanguage, osdtimer, osdbuttonlock"

   print "       OSD Languages:"

   print "           english, spanish, french, german, portugese,"

   print "           russian, chinese, japanese"

   print "    ddcci, lcdconditioning"

   print ""

   print "reset commands:"

   print "    power, color, osd, factory"

def dump_info():

   commands = ["monitorname", "monitorserial", "backlighthours", "powerstate", "powerled", "powerusb", "brightness", "contrast", "aspectratio", "sharpness", "inputcolorformat", "colorpresetcaps", "colorpreset", "customcolor", "autoselect", "videoinputcaps", "videoinput", "pxpmode", "pxpsubinput", "pxplocation", "osdtransparency", "osdlanguage", "osdtimer", "osdbuttonlock", "versionfirmware", "ddcci", "lcdconditioning"]

   for command in commands:

       if (command == "pxpsubinput"):

           for index in range(0,4):

               p4317q_handle_command("get", command, index)

       else:

           param = None

           if (command == "customcolor"):

               param = 0

           p4317q_handle_command("get", command, param)

def p4317q_hex_format(message):

   "Create a hex-ascii string representation of message"

   hex = binascii.b2a_hex(message)

   formatted_hex = ':'.join(hex[i:i+2] for i in range(0, len(hex), 2))

   return formatted_hex

def p4317q_checksum(message, begin, length):

   "Calculate the single byte checksum of the input data"

   total = 0 #x58^length

   for index in range(begin,begin+length):

       #total += message[index]

       total ^= message[index]

       #total &= 0xFF

       print_debug("DB:  total ^ 0x" + p4317q_hex_format(bytearray([message[index]])) + " = 0x" + p4317q_hex_format(bytearray([total&0xff])))

   total &= 0xFF

   print_debug("DB:  " + str(total)+ " 0x" + p4317q_hex_format(bytearray([total])))

   # Compute 2's complement of the sum.  Comment out if this isn't needed

   #total = (~total+1) & 0xFF

   print_debug("DB:  " + str(total)+ " 0x" + p4317q_hex_format(bytearray([total])))

   return total

#0x6E, 0x51, 0x02, 0xEB, 0x01, D7p

def p4317q_build_command(action, value, param):

   "Build a command to be sent to the monitor.  Assumed that param is a bytearray of the correct length"

   cmd_tag = (ACTIONS_MAP[action])[value]

   cmd_len = (ACTIONS_MAP[action])[value+"_len"]

   print_debug("DEBUG:  Param is [" + str(param) + "].  Type is [" + str(type(param)) + "].")

   command = CMD_HEADER + bytearray([cmd_len])

   if (action == "set"):

       cmd_act = CMD_WRITE

       command = command + bytearray([cmd_act]) + bytearray([cmd_tag])

       if (isinstance(param, bytearray)):

           command += param

       else:

           command += bytearray([param])

   else:

       cmd_act = CMD_READ

       command = command + bytearray([cmd_act]) + bytearray([cmd_tag])

       if (param is not None): command += bytearray([param])

   # compute the checksum and add that to the end

   checksum = p4317q_checksum(command, 2, cmd_len+1)

   command = command + bytearray([checksum])

   return command

def p4317q_send_command(ser_port, command):

   ser_port.write(command)

def p4317q_parse_response(response, command):

   response_data = bytearray(response)

   hex = p4317q_hex_format(bytearray([command]))

   print_debug("Parsing response.  Expecting command [" + hex + "].")

   print_debug("Response data:\n    " + p4317q_hex_format(response_data))

   print_debug("Verifying checksum.")

   ckdata = bytearray([len(response_data)-1]) + response_data

   #chksum = p4317q_checksum(response_data,0,len(response_data)-1)

   chksum = p4317q_checksum(ckdata,0,len(ckdata)-1)

   if (chksum != response_data[len(response_data)-1]):

       print_debug("ERROR.  CheckSum does not verify.  Calculated == " + p4317q_hex_format(bytearray([chksum])) + ".")

       # Checksum verification doesn't seem to matter (or work)

       return None

   else:

       print_debug("Checksum verified.")

   if (response_data[0] != RSP_REPLY_CODE):

       print "ERROR.  Reply code incorrect."

       return None

   print_debug("Result code = " + p4317q_hex_format(bytearray([response_data[1]])))

   # Probably could do with some operation on the result code here...

   if (response_data[2] != command):

       print_debug("DEBUG " + str(response_data[2]) + " == " + str(command) + ".")

       print "ERROR.  Received incorrect command response."

       return None

   else:

       print_debug("Command response is correct.")

   print_debug("Response Data:        " + p4317q_hex_format(response_data[3:-1]))

   if (command in (CMD_G_MONITOR_NAME_C, CMD_G_ASSET_TAG_C, CMD_G_MONITOR_SERIAL_C, CMD_G_VERSION_FIRMWARE_C)):

       print_debug("ASCII Response Data:  " + response_data[3:-1])

   print_debug("Done parsing.")

   return response_data[3:-1]

def p4317q_read_response(ser_port):

   # Read 2 bytes, make sure they're == RSP_HEADER

   resp_header = ser_port.read(2)

   print_debug("DEBUG:  Response header received has " + str(len(resp_header)) + " bytes.")

   print_debug("DEBUG:  Received response header = [" + p4317q_hex_format(resp_header) + "]")

   print_debug("DEBUG:  Expected response header = [" + p4317q_hex_format(RSP_HEADER) + "]")

   if (ord(resp_header[0]) != RSP_HEADER[0]):

       print_debug(str(ord(resp_header[0])) + " == " + str(RSP_HEADER[0]))

       print_debug("DEBUG:  1st byte of response header does not match " + p4317q_hex_format(RSP_HEADER))

       return None

   if (ord(resp_header[1]) != RSP_HEADER[1]):

       print_debug("DEBUG:  2nd byte of response header does not match " + p4317q_hex_format(RSP_HEADER))

       return None

   # Read 1 byte of len

   resp_len = ord(ser_port.read(1))

   print_debug("DEBUG:  Received data length of " + str(resp_len))

   # Read resp_len+1 bytes (message + checksum)

   response = ser_port.read(resp_len+1)

   return response

def p4317q_handle_command(action, command, param):

   cmd = p4317q_build_command(action, command, param)

   print_debug("DEBUG:  Command:  [" + p4317q_hex_format(cmd) + "]")

   port = serial.Serial("/dev/cu.usbserial")

   p4317q_send_command(port, cmd)

   response = p4317q_read_response(port)

   port.close()

   if (response is not None):

       print_debug("Response = [" + p4317q_hex_format(response) + "]")

       parsedResponse = p4317q_parse_response(response, (ACTIONS_MAP[action])[command])

   if (parsedResponse is not None and action == "get"):

       format_response(command, parsedResponse, param)

def format_response(command, response, param):

   if   (command == "assettag"):

       print ""

   elif (command == "monitorname"):

       print "Monitor Name         = " + str(response)

   elif (command == "monitorserial"):

       print "Monitor Serial #     = " + str(response)

   elif (command == "backlighthours"):

       print "Backlight Hours      = " + str(struct.unpack("

   elif (command == "powerstate"):

       print "Power State          = " + ("ON" if response[0]==1 else "OFF")

   elif (command == "powerled"):

       print "Power LED            = " + ("ON" if response[0]==1 else "OFF")

   elif (command == "powerusb"):

       print "Power USB            = " + ("ON" if response[0]==1 else "OFF")

   elif (command == "brightness"):

       print "Brightness           = " + str(response[0])

   elif (command == "contrast"):

       print "Contrast             = " + str(response[0])

   elif (command == "aspectratio"):

       ratios = { v: k for k, v in aspect_ratios.items() }

       print "Aspect Ratio         = " + ratios[response[0]]

   elif (command == "sharpness"):

       print "Sharpness            = " + str(response[0])

   elif (command == "inputcolorformat"):

       formats = { v: k for k, v in input_color_formats.items() }

       print "Input Color Format   = " + formats[response[0]]

   elif (command == "colorpresetcaps"):

       print "Color Preset Caps    = " + p4317q_hex_format(response)

   elif (command == "colorpreset"):

       print "Color Preset         = " + color_preset_inv[struct.unpack("

   elif (command == "customcolor"):

       print "Custom Color [R:G:B] = [" + str(response[0]) + ":" + str(response[1]) + ":" + str(response[2]) + "]"

   elif (command == "autoselect"):

       print "Input Auto Select    = " + ("ON" if response[0]==1 else "OFF")

   elif (command == "videoinputcaps"):

       print "Video Input Caps     = " + p4317q_hex_format(response)

   elif (command == "videoinput"):

       inputs = { v[0]: k for k, v in pxp_input.items() }

       print "Video Input          = " + inputs[int(response[0])]

   elif (command == "pxpmode"):

       modes = { v: k for k, v in pxp_mode.items() }

       print "PxP/PiP Mode         = " + modes[response[0]]

   elif (command == "pxpsubinput"):

       inputs = { v[0]: k for k, v in pxp_input.items() }

       print "PxP/PiP Sub Input[" + str(param+1) + "] = " + inputs[int(response[0])]

   elif (command == "pxplocation"):

       locations = { v: k for k, v in pxp_locations.items() }

       print "PiP Window Location  = " + locations[int(response[0])]

   elif (command == "osdtransparency"):

       print "OSD Transparency     = " + str(response[0])

   elif (command == "osdlanguage"):

       languages = { v: k for k, v in osd_language.items() }

       print "OSD Language         = " + languages[int(response[0])]

   elif (command == "osdtimer"):

       print "OSD Timer            = " + str(response[0])

   elif (command == "osdbuttonlock"):

       print "OSD Button Lock      = " + ("ON" if response[0]==1 else "OFF")

   elif (command == "versionfirmware"):

       print "Firmware Version     = " + response

   elif (command == "ddcci"):

       print "DDC/CI               = " + ("ON" if response[0]==1 else "OFF")

   elif (command == "lcdconditioning"):

       print "LCD Conditioning     = " + ("ON" if response[0]==1 else "OFF")

   return

# MONITOR MANAGEMENT

CMD_G_ASSET_TAG_L=0x02

CMD_G_ASSET_TAG_C=0x00

CMD_G_ASSET_TAG_RESP_L=0x0D

CMD_G_MONITOR_NAME_L=0x02

CMD_G_MONITOR_NAME_C=0x01

CMD_G_MONITOR_NAME_RESP_L=0x0D

CMD_G_MONITOR_SERIAL_L=0x02

CMD_G_MONITOR_SERIAL_C=0x02

CMD_G_MONITOR_SERIAL_RESP_L=0x0D

CMD_G_BACKLIGHT_HOURS_L=0x02

CMD_G_BACKLIGHT_HOURS_C=0x04

CMD_G_BACKLIGHT_HOURS_RESP_L=0x05

# POWER MANAGEMENT

CMD_G_POWER_STATE_L=0x02

CMD_G_POWER_STATE_C=0x20

CMD_G_POWER_STATE_RESP_L=0x04

CMD_S_POWER_STATE_L=0x03

CMD_S_POWER_STATE_C=0x20

CMD_G_POWER_LED_L=0x02

CMD_G_POWER_LED_C=0x21

CMD_G_POWER_LED_RESP_L=0x04

CMD_S_POWER_LED_L=0x03

CMD_S_POWER_LED_C=0x21

CMD_G_POWER_USB_L=0x02

CMD_G_POWER_USB_C=0x22

CMD_G_POWER_USB_RESP_L=0x04

CMD_S_POWER_USB_L=0x03

CMD_S_POWER_USB_C=0x22

CMD_RESET_POWER_L=0x02

CMD_RESET_POWER_C=0x2F

# IMAGE ADJUSTMENT

CMD_G_BRIGHTNESS_L=0x02

CMD_G_BRIGHTNESS_C=0x30

CMD_G_BRIGHTNESS_RESP_L=0x04

CMD_S_BRIGHTNESS_L=0x03

CMD_S_BRIGHTNESS_C=0x30

CMD_G_CONTRAST_L=0x02

CMD_G_CONTRAST_C=0x31

CMD_G_CONTRAST_RESP_L=0x04

CMD_S_CONTRAST_L=0x03

CMD_S_CONTRAST_C=0x31

CMD_G_ASPECT_RATIO_L=0x02

CMD_G_ASPECT_RATIO_C=0x33

CMD_G_ASPECT_RATIO_RESP_L=0x04

CMD_S_ASPECT_RATIO_L=0x03

CMD_S_ASPECT_RATIO_C=0x33

CMD_G_SHARPNESS_L=0x02

CMD_G_SHARPNESS_C=0x34

CMD_G_SHARPNESS_RESP_L=0x04

CMD_S_SHARPNESS_L=0x03

CMD_S_SHARPNESS_C=0x34

aspect_ratios = { "16x9": 0,

                 "4x3":  2,

                 "5x4":  4 }

# COLOR MANAGEMENT

CMD_G_INPUT_COLOR_FORMAT_L=0x02

CMD_G_INPUT_COLOR_FORMAT_C=0x46

CMD_G_INPUT_COLOR_FORMAT_RESP_L=0x04

CMD_S_INPUT_COLOR_FORMAT_L=0x03

CMD_S_INPUT_COLOR_FORMAT_C=0x46

CMD_G_COLOR_PRESET_CAPS_L=0x02

CMD_G_COLOR_PRESET_CAPS_C=0x47

CMD_G_COLOR_PRESET_CAPS_RESP_L=0x07

CMD_G_COLOR_PRESET_L=0x02

CMD_G_COLOR_PRESET_C=0x48

CMD_G_COLOR_PRESET_RESP_L=0x07

CMD_S_COLOR_PRESET_L=0x06

CMD_S_COLOR_PRESET_C=0x48

CMD_G_CUSTOM_COLOR_L=0x03

CMD_G_CUSTOM_RESP_L=0x09

CMD_G_CUSTOM_COLOR_C=0x49

CMD_G_CUSTOM_COLOR_RESP_L=0x09

CMD_S_CUSTOM_COLOR_L=0x09

CMD_S_CUSTOM_COLOR_C=0x49

CMD_RESET_COLOR_L=0x02

CMD_RESET_COLOR_C=0x4F

input_color_formats = { "RGB": 0,

                       "YPbPr": 1 }

color_presets = { "standard": bytearray([0x01, 0x00, 0x00, 0x00]),

                 "paper":    bytearray([0x10, 0x00, 0x00, 0x00]),

                 "warm":     bytearray([0x00, 0x01, 0x00, 0x00]),

                 "cool":     bytearray([0x00, 0x02, 0x00, 0x00]),

                 "custom":   bytearray([0x80, 0x00, 0x00, 0x00]) }

color_preset_inv = { struct.unpack("

                    struct.unpack("

                    struct.unpack("

                    struct.unpack("

                    struct.unpack("

# VIDEO INPUT MANAGEMENT

CMD_G_AUTO_SELECT_L=0x02

CMD_G_AUTO_SELECT_C=0x60

CMD_G_AUTO_SELECT_RESP_L=0x04

CMD_S_AUTO_SELECT_L=0x03

CMD_S_AUTO_SELECT_C=0x60

CMD_G_VIDEO_INPUT_CAPS_L=0x02

CMD_G_VIDEO_INPUT_CAPS_C=0x61

CMD_G_VIDEO_INPUT_CAPS_RESP_L=0x07

CMD_G_VIDEO_INPUT_L=0x02

CMD_G_VIDEO_INPUT_C=0x62

CMD_G_VIDEO_INPUT_RESP_L=0x07

CMD_S_VIDEO_INPUT_L=0x06

CMD_S_VIDEO_INPUT_C=0x62

# PIP/PBP MANAGEMENT

CMD_G_PXP_MODE_L=0x02

CMD_G_PXP_MODE_C=0x70

CMD_G_PXP_MODE_RESP_L=0x04

CMD_S_PXP_MODE_L=0x03

CMD_S_PXP_MODE_C=0x70

CMD_G_PXP_SUBINPUT_L=0x03

CMD_G_PXP_SUBINPUT_C=0x71

CMD_G_PXP_SUBINPUT_RESP_L=0x07

CMD_S_PXP_SUBINPUT_L=0x06

CMD_S_PXP_SUBINPUT_C=0x71

CMD_G_PXP_LOCATION_L=0x02

CMD_G_PXP_LOCATION_C=0x72

CMD_G_PXP_LOCATION_RESP_L=0x04

CMD_S_PXP_LOCATION_L=0x03

CMD_S_PXP_LOCATION_C=0x72

pxp_mode = { "4k": 0,

            "smallPip": 1,

            "bigPip": 2,

            "SxS": 3,

            "stretchSxS": 4,

            "2x1": 6,

            "1x2": 7,

            "4x4": 8 }

pxp_input = { "vga":   bytearray([0x40, 0x00, 0x00, 0x00]),

             "dp":    bytearray([0x08, 0x00, 0x00, 0x00]),

             "mdp":   bytearray([0x10, 0x00, 0x00, 0x00]),

             "hdmi1": bytearray([0x01, 0x00, 0x00, 0x00]),

             "hdmi2": bytearray([0x02, 0x00, 0x00, 0x00]) }

pxp_locations = { "topRight": 0,

                 "topLeft": 1,

                 "bottomRight": 2,

                 "bottomLeft": 3 }

# PxP Locations (PiP Location)

# 0 - Top Right

# 1 - Top Left

# 2 - Bottom Right

# 3 - Bottom Left

# OSD MANAGEMENT

CMD_S_OSD_TRANSPARENCY_L=0x03

CMD_S_OSD_TRANSPARENCY_C=0x80

CMD_G_OSD_TRANSPARENCY_L=0x02

CMD_G_OSD_TRANSPARENCY_C=0x80

CMD_G_OSD_TRANSPARENCY_RESP_L=0x04

CMD_S_OSD_LANGUAGE_L=0x03

CMD_S_OSD_LANGUAGE_C=0x81

CMD_G_OSD_LANGUAGE_L=0x02

CMD_G_OSD_LANGUAGE_C=0x81

CMD_G_OSD_LANGUAGE_RESP_L=0x04

CMD_S_OSD_TIMER_L=0x03

CMD_S_OSD_TIMER_C=0x83

CMD_G_OSD_TIMER_L=0x02

CMD_G_OSD_TIMER_C=0x83

CMD_G_OSD_TIMER_RESP_L=0x04

CMD_S_OSD_BUTTON_LOCK_L=0x03

CMD_S_OSD_BUTTON_LOCK_C=0x84

CMD_G_OSD_BUTTON_LOCK_L=0x02

CMD_G_OSD_BUTTON_LOCK_C=0x84

CMD_G_OSD_BUTTON_LOCK_RESP_L=0x04

CMD_RESET_OSD_L=0x02

CMD_RESET_OSD_C=0x8F

osd_language = { "english": 0,

                "spanish": 1,

                "french": 2,

                "german": 3,

                "portugese": 4,

                "russian": 5,

                "chinese": 6,

                "japanese": 7 }

# OSD Languages

# 0 - English

# 1 - Spanish

# 2 - French

# 3 - German

# 4 - Portugese

# 5 - Russian

# 6 - Chinese ?

# 7 - Japanese ?

# SYSTEM MANAGEMENT

CMD_G_VERSION_FIRMWARE_L=0x02

CMD_G_VERSION_FIRMWARE_C=0xA0

CMD_G_VERSION_FIRMWARE_RESP_L=0x05

CMD_G_DDCCI_L=0x02

CMD_G_DDCCI_C=0xA2

CMD_G_DDCCI_RESP_L=0x04

CMD_S_DDCCI_L=0x03

CMD_S_DDCCI_C=0xA2

CMD_G_LCD_CONDITIONING_L=0x02

CMD_G_LCD_CONDITIONING_C=0xA3

CMD_G_LCD_CONDITIONING_RESP_L=0x04

CMD_S_LCD_CONDITIONING_L=0x03

CMD_S_LCD_CONDITIONING_C=0xA3

CMD_FACTORY_RESET_L=0x02

CMD_FACTORY_RESET_C=0xAF

GET_ACTIONS = {

   "assettag": CMD_G_ASSET_TAG_C                  , "assettag_len": CMD_G_ASSET_TAG_L,

   "assettag_resplen": CMD_G_ASSET_TAG_RESP_L,

   "monitorname": CMD_G_MONITOR_NAME_C            , "monitorname_len": CMD_G_MONITOR_NAME_L,

   "monitorname_resplen": CMD_G_MONITOR_NAME_RESP_L,

   "monitorserial": CMD_G_MONITOR_SERIAL_C        , "monitorserial_len": CMD_G_MONITOR_SERIAL_L,

   "monitorserial_resplen": CMD_G_MONITOR_SERIAL_RESP_L,

   "backlighthours": CMD_G_BACKLIGHT_HOURS_C      , "backlighthours_len": CMD_G_BACKLIGHT_HOURS_L,

   "backlighthours_resplen": CMD_G_BACKLIGHT_HOURS_RESP_L,

   "powerstate": CMD_G_POWER_STATE_C              , "powerstate_len": CMD_G_POWER_STATE_L,

   "powerstate_resplen": CMD_G_POWER_STATE_RESP_L,

   "powerled": CMD_G_POWER_LED_C                  , "powerled_len": CMD_G_POWER_LED_L,

   "powerled_resplen": CMD_G_POWER_LED_RESP_L,

   "powerusb": CMD_G_POWER_USB_C                  , "powerusb_len": CMD_G_POWER_USB_L,

   "powerusb_resplen": CMD_G_POWER_USB_RESP_L,

   "brightness": CMD_G_BRIGHTNESS_C               , "brightness_len": CMD_G_BRIGHTNESS_L,

   "brightness_resplen": CMD_G_BRIGHTNESS_RESP_L,

   "contrast": CMD_G_CONTRAST_C                   , "contrast_len": CMD_G_CONTRAST_L,

   "contrast_resplen": CMD_G_CONTRAST_RESP_L,

   "aspectratio": CMD_G_ASPECT_RATIO_C            , "aspectratio_len": CMD_G_ASPECT_RATIO_L,

   "aspectratio_resplen": CMD_G_ASPECT_RATIO_RESP_L,

   "sharpness": CMD_G_SHARPNESS_C                 , "sharpness_len": CMD_G_SHARPNESS_L,

   "sharpness_resplen": CMD_G_SHARPNESS_RESP_L,

   "inputcolorformat": CMD_G_INPUT_COLOR_FORMAT_C , "inputcolorformat_len": CMD_G_INPUT_COLOR_FORMAT_L,

   "inputcolorformat_resplen": CMD_G_INPUT_COLOR_FORMAT_RESP_L,

   "colorpresetcaps": CMD_G_COLOR_PRESET_CAPS_C   , "colorpresetcaps_len": CMD_G_COLOR_PRESET_CAPS_L,

   "colorpresetcaps_resplen": CMD_G_COLOR_PRESET_CAPS_RESP_L,

   "colorpreset": CMD_G_COLOR_PRESET_C            , "colorpreset_len": CMD_G_COLOR_PRESET_L,

   "colorpreset_resplen": CMD_G_COLOR_PRESET_RESP_L,

   "customcolor": CMD_G_CUSTOM_COLOR_C            , "customcolor_len": CMD_G_CUSTOM_COLOR_L,

   "customcolor_resplen": CMD_G_CUSTOM_COLOR_RESP_L,

   "autoselect": CMD_G_AUTO_SELECT_C              , "autoselect_len": CMD_G_AUTO_SELECT_L,

   "autoselect_resplen": CMD_G_AUTO_SELECT_RESP_L,

   "videoinputcaps": CMD_G_VIDEO_INPUT_CAPS_C     , "videoinputcaps_len": CMD_G_VIDEO_INPUT_CAPS_L,

   "videoinputcaps_resplen": CMD_G_VIDEO_INPUT_CAPS_RESP_L,

   "videoinput": CMD_G_VIDEO_INPUT_C              , "videoinput_len": CMD_G_VIDEO_INPUT_L,

   "videoinput_resplen": CMD_G_VIDEO_INPUT_RESP_L,

   "pxpmode": CMD_G_PXP_MODE_C                    , "pxpmode_len": CMD_G_PXP_MODE_L,

   "pxpmode_resplen": CMD_G_PXP_MODE_RESP_L,

   "pxpsubinput": CMD_G_PXP_SUBINPUT_C            , "pxpsubinput_len": CMD_G_PXP_SUBINPUT_L,

   "pxpsubinput_resplen": CMD_G_PXP_SUBINPUT_RESP_L,

   "pxplocation": CMD_G_PXP_LOCATION_C            , "pxplocation_len": CMD_G_PXP_LOCATION_L,

   "pxplocation_resplen": CMD_G_PXP_LOCATION_RESP_L,

   "osdtransparency": CMD_G_OSD_TRANSPARENCY_C    , "osdtransparency_len": CMD_G_OSD_TRANSPARENCY_L,

   "osdtransparency_resplen": CMD_G_OSD_TRANSPARENCY_RESP_L,

   "osdlanguage": CMD_G_OSD_LANGUAGE_C            , "osdlanguage_len": CMD_G_OSD_LANGUAGE_L,

   "osdlanguage_resplen": CMD_G_OSD_LANGUAGE_RESP_L,

   "osdtimer": CMD_G_OSD_TIMER_C                  , "osdtimer_len": CMD_G_OSD_TIMER_L,

   "osdtimer_resplen": CMD_G_OSD_TIMER_RESP_L,

   "osdbuttonlock": CMD_G_OSD_BUTTON_LOCK_C       , "osdbuttonlock_len": CMD_G_OSD_BUTTON_LOCK_L,

   "osdbuttonlock_resplen": CMD_G_OSD_BUTTON_LOCK_RESP_L,

   "versionfirmware": CMD_G_VERSION_FIRMWARE_C    , "versionfirmware_len": CMD_G_VERSION_FIRMWARE_L,

   "versionfirmware_resplen": CMD_G_VERSION_FIRMWARE_RESP_L,

   "ddcci": CMD_G_DDCCI_C                         , "ddcci_len": CMD_G_DDCCI_L,

   "ddcci_resplen": CMD_G_DDCCI_RESP_L,

   "lcdconditioning": CMD_G_LCD_CONDITIONING_C    , "lcdconditioning_len": CMD_G_LCD_CONDITIONING_L,

   "lcdconditioning_resplen": CMD_G_LCD_CONDITIONING_RESP_L

}

SET_ACTIONS = {

   "powerstate": CMD_S_POWER_STATE_C              , "powerstate_len": CMD_S_POWER_STATE_L,

   "powerled": CMD_S_POWER_LED_C                  , "powerled_len": CMD_S_POWER_LED_L,

   "powerusb": CMD_S_POWER_USB_C                  , "powerusb_len": CMD_S_POWER_USB_L,

   "brightness": CMD_S_BRIGHTNESS_C               , "brightness_len": CMD_S_BRIGHTNESS_L,

   "contrast": CMD_S_CONTRAST_C                   , "contrast_len": CMD_S_CONTRAST_L,

   "aspectratio": CMD_S_ASPECT_RATIO_C            , "aspectratio_len": CMD_S_ASPECT_RATIO_L,

   "sharpness": CMD_S_SHARPNESS_C                 , "sharpness_len": CMD_S_SHARPNESS_L,

   "inputcolorformat": CMD_S_INPUT_COLOR_FORMAT_C , "inputcolorformat_len": CMD_S_INPUT_COLOR_FORMAT_L,

   "colorpreset": CMD_S_COLOR_PRESET_C            , "colorpreset_len": CMD_S_COLOR_PRESET_L,

   "customcolor": CMD_S_CUSTOM_COLOR_C            , "customcolor_len": CMD_S_CUSTOM_COLOR_L,

   "autoselect": CMD_S_AUTO_SELECT_C              , "autoselect_len": CMD_S_AUTO_SELECT_L,

   "videoinput": CMD_S_VIDEO_INPUT_C              , "videoinput_len": CMD_S_VIDEO_INPUT_L,

   "pxpmode": CMD_S_PXP_MODE_C                    , "pxpmode_len": CMD_S_PXP_MODE_L,

   "pxpsubinput": CMD_S_PXP_SUBINPUT_C            , "pxpsubinput_len": CMD_S_PXP_SUBINPUT_L,

   "pxplocation": CMD_S_PXP_LOCATION_C            , "pxplocation_len": CMD_S_PXP_LOCATION_L,

   "osdtransparency": CMD_S_OSD_TRANSPARENCY_C    , "osdtransparency_len": CMD_S_OSD_TRANSPARENCY_L,

   "osdlanguage": CMD_S_OSD_LANGUAGE_C            , "osdlanguage_len": CMD_S_OSD_LANGUAGE_L,

   "osdtimer": CMD_S_OSD_TIMER_C                  , "osdtimer_len": CMD_S_OSD_TIMER_L,

   "osdbuttonlock": CMD_S_OSD_BUTTON_LOCK_C       , "osdbuttonlock_len": CMD_S_OSD_BUTTON_LOCK_L,

   "ddcci": CMD_S_DDCCI_C                         , "ddcci_len": CMD_S_DDCCI_L,

   "lcdconditioning": CMD_S_LCD_CONDITIONING_C    , "lcdconditioning_len": CMD_S_LCD_CONDITIONING_L

}

RESET_ACTIONS = {

   "power": CMD_RESET_POWER_C                     , "power_len": CMD_RESET_POWER_L,

   "color": CMD_RESET_COLOR_C                     , "color_len": CMD_RESET_COLOR_L,

   "osd": CMD_RESET_OSD_C                         , "osd_len": CMD_RESET_OSD_L,

   "factory": CMD_FACTORY_RESET_C                 , "factory_len": CMD_FACTORY_RESET_L

}

ACTIONS_MAP = { "get": GET_ACTIONS, "set": SET_ACTIONS, "reset": RESET_ACTIONS }

print_debug("len(sys.argv) = " + str(len(sys.argv)))

print_debug("args = " + str(sys.argv))

if (len(sys.argv) < 2 or len(sys.argv) > 5):

   print_usage()

   exit()

if (sys.argv[1] == "dump"):

   dump_info()

   exit()

if (sys.argv[1] in ("get", "set", "reset")):

   keys = ACTIONS_MAP[sys.argv[1]].keys()

   if (sys.argv[2] not in keys):

       print "ERROR:  Invalid command specified"

       exit()

else:

   print "ERROR:  Invalid action specified"

   exit()

param = None

if (len(sys.argv) >= 4):

   if (sys.argv[1] == "set"):

       if   (sys.argv[2] == "osdlanguage"):

           param = osd_language[sys.argv[3]]

       elif (sys.argv[2] == "pxplocation"):

           param = pxp_locations[sys.argv[3]]

       elif (sys.argv[2] == "pxpmode"):

           param = pxp_mode[sys.argv[3]]

       elif (sys.argv[2] == "videoinput"):

           param = pxp_input[sys.argv[3]]

       elif (sys.argv[2] == "pxpsubinput"):

           print "pxpsubinput"

           param = bytearray([int(sys.argv[3])-1])

           param += pxp_input[sys.argv[4]]

           print "param:  " + p4317q_hex_format(param)

       else:

           param = int(sys.argv[3])

   else:

       param = int(sys.argv[3])

output = p4317q_handle_command(sys.argv[1], sys.argv[2], param)

5 Posts

April 12th, 2017 10:00

Thanks sredniv but please post long code fragments on gist or pastebin. Specially with Python's strict indentation rules. I look forward to trying your script.

Really, we need to push Dell for updated Reference guide based off 104 firmware. Evidently the current guide is already years old.

4 Posts

April 12th, 2017 14:00

I wasn't sure if pasting in the python code would survive here.  I guess not.

Pastebin created:  https://pastebin.com/4gumZyHb

Adjusting for the difference in checksum calculation would be done by adjusting the calls to the p4317q_checksum function.

5 Posts

April 12th, 2017 14:00

Good news, with the 104 firmware, I got it to work.. Unlike what was mentioned above with calculating the checksum excluding the header (at least for responses).... I had to include the header in the checksum.

375103ea2100ae turned off the LED

375103ea2101af turned on the LED

xor(0x37;0x51;0x03;0xea;0x21;01)  (SpeedCrunch calculator notation)

= 0xAF

Cool beans.

EDIT: Except, the PxBSubInput cmds do not work anymore (syntax changed), which is the primary reason for this.

3 Posts

April 19th, 2017 10:00

sredniv, thanks for the python script.

With 104, a quick scan through all 256 values of checksum for "get powerstate" results in error code 0x2 for everything.  Wonder if they changed something else in the command, or if someone just slipped up and flipped the verify from accept any to reject all checksum.

Makes one wonder if the api was even tested before releasing the update.

5 Posts

April 25th, 2017 10:00

After bouncing around online chat, dozen phone calls, and emails... I finally reached the top tier of Dell support! :) Suffice to say, www.dell.com/.../manuals is being updated very shortly (currently 404s) with (2) new documents. One is a list of examples. The other is an updated April 2017 version of the reference API !

http://downloads.dell.com/manuals/all-products/esuprt_display_projector/esuprt_display/dell-p4317q-monitor_Reference%20Guide3_en-us.pdf

http://downloads.dell.com/manuals/all-products/esuprt_display_projector/esuprt_display/dell-p4317q-monitor_Reference%20Guide2_en-us.pdf

Suffice to say, the documentation is amazing now... and I got my PxBSubInput cmd to work.. it takes len (7). Everything is LSB first. monitor inputs are (4) bytes wide which makes a lot of sense now.

I updated my scripts and uploaded to github here:

dellquad: gist.github.com/.../4e3855e592a3404bd60f2254fc3483a8

dell4k: gist.github.com/.../f68d384e21988a17d8360bb04216bf57

6 Posts

April 16th, 2019 14:00

Hello, I found your code, and I tried to use it, but my monitor isn't responding. I purchased a USB to serial cable and, I set the output to the serial port listed in /dev; however, I'm not getting a response from the monitor. Is there something I'm missing? Do I need to set a baud rate somewhere? Is there a specific cable I need to purchase?

Thank you!

Lucas

No Events found!

Top