Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Picture-by-Picture #163

Open
pjaitken opened this issue Dec 28, 2020 · 16 comments
Open

Picture-by-Picture #163

pjaitken opened this issue Dec 28, 2020 · 16 comments

Comments

@pjaitken
Copy link

I'm looking for a way to change the Picture-by-Picture (PBP) input on a Philips 499P9. The PBP mode allows it to display two inputs side-by-side.

ddcutil reports the monitor as two displays on different I2C buses. When reading, the same values seem to be returned from both. Writing to either display or bus affects the monitor as a whole.

Writing to vcp 60 only changes the primary input. However when the inputs are changed manually, reading vcp 60 returns the value for the most-recently changed input - whether the primary or PBP.

When running from a single input, vcp e6 reports sl=0x01; for PBP it reports 0x00. Writing has no effect. There are a handful of other manufacturer vcp's, but they don't change when the inputs are changed and writing to them doesn't have any obvious effect.

"ddcutil watch" doesn't help: although vcp 2 reports "One or more new control values have been saved", vcp 52 always reports value 0x02 - even after writing 1 to vcp 2, which then reports "No new control values".

Thanks.

@bugrasan
Copy link

Looking for the same solution for the same monitor. I was hoping that one of the E? codes work but i can't read their values even some of them shown in the capabilities:

   Feature: E9 (manufacturer specific feature)
      Values: 00 02 (interpretation unavailable)
   Feature: EB (manufacturer specific feature)
      Values: 00 01 02 03 (interpretation unavailable)
   Feature: F0 (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: FD (manufacturer specific feature)
   Feature: FF (manufacturer specific feature)

and E6 doesn't show any the difference in PBP mode (on or off):

$ ddcutil --bus=x getvcp e6
VCP code 0xe6 (Manufacturer Specific         ): mh=0x00, ml=0x00, sh=0x00, sl=0x00

in addition to PBP i would be also interested to switch the USB KVM (Auto, USB-C, USB-Up).

interestingly when using ddcutil --bus=x watch i can't use the on-screen-display, the timeout seems to get borked, and it disappears immediately. also the VCP code 0x02 repeats until ddcutil "loop guard" kicks in.

@pjaitken
Copy link
Author

For me, the low bit of VCP e6 does indicate the PBP mode:

With PBP mode enabled (ie, two inputs / split screen):

$ ddcutil -b 1 getvcp e6
VCP code 0xe6 (Manufacturer Specific         ): mh=0x00, ml=0x00, sh=0x00, sl=0x00

Without PBP mode (ie, one input):

$ ddcutil -b 1 getvcp e6
VCP code 0xe6 (Manufacturer Specific         ): mh=0x00, ml=0x00, sh=0x00, sl=0x01

"scan" and "capabilities" and report different sets of manufacturer specific codes:

$ ddcutil -b 1 getvcp scan | grep -i manufacturer
VCP code 0xe0 (Manufacturer Specific         ): mh=0x00, ml=0x14, sh=0x00, sl=0x03
VCP code 0xe6 (Manufacturer Specific         ): mh=0x00, ml=0x00, sh=0x00, sl=0x00
VCP code 0xeb (Manufacturer Specific         ): mh=0x00, ml=0x01, sh=0x00, sl=0x01
VCP code 0xf0 (Manufacturer Specific         ): mh=0x00, ml=0x01, sh=0x00, sl=0x01
VCP code 0xfe (Manufacturer Specific         ): Maximum retries exceeded

$ ddcutil -b 1 capabilities | grep -i manufacturer
   Feature: E9 (manufacturer specific feature)
   Feature: EB (manufacturer specific feature)
   Feature: F0 (manufacturer specific feature)
   Feature: FD (manufacturer specific feature)
   Feature: FF (manufacturer specific feature)

Reading manufacturer specific codes:

$ ddcutil -b 1 getvcp e0
VCP code 0xe0 (Manufacturer Specific         ): mh=0x00, ml=0x14, sh=0x00, sl=0x03
$ ddcutil -b 1 getvcp e6
VCP code 0xe6 (Manufacturer Specific         ): mh=0x00, ml=0x00, sh=0x00, sl=0x00
$ ddcutil -b 1 getvcp eb
VCP code 0xeb (Manufacturer Specific         ): mh=0x00, ml=0x01, sh=0x00, sl=0x01
$ ddcutil -b 1 getvcp f0
VCP code 0xf0 (Manufacturer Specific         ): mh=0x00, ml=0x01, sh=0x00, sl=0x01
$ ddcutil -b 1 getvcp fe
VCP code 0xfe (Manufacturer Specific         ): Maximum retries exceeded

$ ddcutil -b 1 getvcp e9
VCP code 0xe9 (Manufacturer Specific         ): Unsupported feature code
$ ddcutil -b 1 getvcp eb 
VCP code 0xeb (Manufacturer Specific         ): mh=0x00, ml=0x01, sh=0x00, sl=0x01
$ ddcutil -b 1 getvcp f0
VCP code 0xf0 (Manufacturer Specific         ): mh=0x00, ml=0x01, sh=0x00, sl=0x01
$ ddcutil -b 1 getvcp fd
VCP code 0xfd (Manufacturer Specific         ): Unsupported feature code
$ ddcutil -b 1 getvcp ff
VCP code 0xff (Manufacturer Specific         ): Unsupported feature code

Writing manufacturer specific codes:

vcp e0 can be set to 0 or 3 with no obvious effect.
vcp e6 can be written, but never changes from 0.
vcp eb can be set 0 - 3 with no obvious effect.
vcp f0 can be set 0 - ff; the upper bits are lost, only the bottom bit is kept (0 - 1).

@rockowitz
Copy link
Owner

@pjaitken I have, as they say, been admiring your problem, and trying to think of useful things to suggest. PBP is so beyond what was considered when MCCS was defined. You've looked in all the obvious places, and then some. Here are some observations and questions (many of which are undoubtedly obvious).

  • What is the hardware configuration?
  • I assume the second OS is Windows - is that correct?
  • The capabilities string is unreliable. On the other hand, attempting to read a feature code that is write-only will not detect the feature
  • If a feature listed in the capabilities string has a value list, it's a Non-Continuous feature of some sort. Otherwise it's likely a Continuos feature. However, another indication of a NC feature is a low maximum value (mh/ml) returned when reading the feature, as you've found with xf0.
  • Implementations of feature x60 vary. Some monitors will respond to DDC requests only on the currently selected input, others are responsive on any input. PBP makes the behaviour of the feature even more variable.
  • Comparing the output of getvcp scan or getvcp mfg in various monitor states, as you seem to be doing, is how I would proceed.
  • Please run ddcutil interrogate in each of the various monitor states you can: from the Linux system with PBP off and on, and if the second input is also Linux, from that one as well. I'll study the output. On the one hand it will produce an overkill of information, but it will avoid lots of back and forth with specific questions.
  • For probing from Windows, enTech's softMCCS is the program to use.
  • Re the monitor appearing with 2 different /dev/i2c buses, my best guess is that it's a driver problem that surfaces in the context of DisplayPort MST, either with a docking station or use of a USB type-C connector on a laptop. The latest version of environment and interrogate extensively explores /sys in this regard, so that ddcutil can handle the situation and/or I can create a useful bug report for the driver folks.
  • The best way to understand what is going on would be to put a logic analyser on the physical I2C bus and watch how Phillips's Windows program communicates with the monitor. Alternatively, it conceivably could be possible to trace the low level I2C communication within Windows, but that is well beyond my Windows knowledge.

Regards,
Sanford

@rockowitz
Copy link
Owner

@bugrasan Most of my reply to @pjaitken is for you as well.

The one thing I would add is that the watch command is problematic. The version in branch 1.0.0-dev better handles error conditions. In MCCS, feature x52 became a FIFO, meant to be read repeatedly until a value of x00 is returned. Branch 1.0.0-dev adds command line option **--x52-no-fifo, which forces watch to always use MCCS 2.0/2.1 behaviour, reading a single feature id from feature x52 and then checking feature x02 to see if there are more changed features.

I'd appreciate it if you run ddcutil interrogate in the various monitor states and send the output, of course as attachments of some sort.

Regards,
Sanford

@pjaitken
Copy link
Author

pjaitken commented Dec 31, 2020

Thanks @rockowitz. I've emailed you some "ddcutil interrogate" outputs.

The hardware configuration is debian connected to the displayPort + HDMI-1 inputs, and macOS connected to HDMI-2.
No windows machines.
I couldn't build ddcutil for macOS (no libudev), so no outputs from there.

@pjaitken
Copy link
Author

pjaitken commented Jan 3, 2021

FWIW, ddcutil getvcp SCAN gives different output for some VCPs compared with discrete queries:

SCAN:

VCP code 0x20 (Horizontal Position (Phase)   ): current value =     0, max value =     1
VCP code 0x30 (Vertical Position (Phase)     ): current value =     0, max value =     1
VCP code 0x52 (Active control                ): Value: 0x00

Discrete getvcp queries:

VCP code 0x20 (Horizontal Position (Phase)   ): current value =   514, max value = 65535
VCP code 0x30 (Vertical Position (Phase)     ): current value =   514, max value = 65535
VCP code 0x52 (Active control                ): Value: 0x02

Also, --x52-no-fifo doesn't make any difference.

@rockowitz
Copy link
Owner

I'm not sure what to make of the feature x20 and x30 discrepancies. These features are in the Geometry section of the MCCS spec, which contains features like pincushion that apply only to CRTs. What these features mean for flat panels is unclear. A pixel offset?

And yet, 2 of the 3 monitors in front of me list these features in their capabilities string. All 3 reply to getvcp requests for the features. And all 3 show show a similar deviation in the output of getvcp 20/getvcp 30 versus getvcp scan.

The obvious suspect is some buffer corruption in ddcutil. But tracing at the lowest I2C level shows that the request packets are identical, while the response packets diverge.

I've improved the tracing in branch 1.0.0-dev to make this easier to see. Use the command

$ ddcutil getvcp 20 --verbose --trcfunc get_raw_value_for_feature_metadata, --trcfunc i2c_fileio_reader, --trcfunc_i2c_fileio_writer

and similar commands for feature x30 and scan

What's of interest are the i2c_fileio_writer() and i2c_fileio_reader() calls within get_raw_value_for_feature_metadata().
i2c_fileio_writer() writes the same request packets for feature x20/x30 for scan versus for discrete getvcp requests.. But the response packets are different. The ending trace for get_raw_value_for_feature_metadata() is properly interpreting the returned bytes. (Note: Only the first 11 bytes in the buffer reported by i2c_fileio_reader() are the actual response. The 11th byte is a checksum.)

@rockowitz
Copy link
Owner

Re the x52 deviations, I would expect the value of feature x52 to vary based on the monitor's state. That the value of x52 is x00 for scan suggests that the read of feature x02 earlier in the scan returned either x01 (No new control values) or xff (No user controls are present).

@pjaitken
Copy link
Author

pjaitken commented Jan 4, 2021

I see the same: different data returned by "scan" versus "getvcp".

Here's the output of ddcutil getvcp SCAN --verbose --trcfunc=get_raw_value_for_feature_metadata --trcfunc=i2c_fileio_reader --trcfunc=i2c_fileio_writer:

Getting data for non-table VCP code 0x20 - Horizontal Position (Phase):
(get_raw_value_for_feature_metadata) Starting. frec=0x55cf03763840, feature_code=0x20
(i2c_fileio_writer             ) Starting. fh=3, filename=/dev/i2c-1, slave_address=0x37, bytect=5, pbytes=0x55cf0375e721 -> 51 82 01 20 9c
(i2c_fileio_writer             ) Done. Returning: OK(0): success
(i2c_fileio_reader             ) Starting. fd=3, fn=/dev/i2c-1, bytect=20, slave_address=0x37, single_byte_reads=false
(i2c_fileio_reader             ) Returning: OK(0): success, readbuf: 6e 88 02 00 20 01 00 01 00 00 94 00 00 00 00 00 00 00 00 00
(get_raw_value_for_feature_metadata) Done.     Returning NULL, *pvalrec ->  
         Single_Vcp_Value at 0x55cf0375e920:
            Opcode:          0x20
            Value type:      DDCA_NON_TABLE_VCP_VALUE (0x01)
            max_val:     1 - 0x0001
            cur_val:     0 - 0x0000
            mh:          0x00
            ml:          0x01
            sh:          0x00
            sl:          0x00
Raw value: opcode=0x20, mh=0x00, ml=0x01, sh=0x00, sl=0x00, max_val=1 (0x0001), cur_val=0 (0x0000)
VCP code 0x20 (Horizontal Position (Phase)   ): current value =     0, max value =     1

Getting data for non-table VCP code 0x30 - Vertical Position (Phase):
(get_raw_value_for_feature_metadata) Starting. frec=0x55cf037643a0, feature_code=0x30
(i2c_fileio_writer             ) Starting. fh=3, filename=/dev/i2c-1, slave_address=0x37, bytect=5, pbytes=0x55cf0375e011 -> 51 82 01 30 8c
(i2c_fileio_writer             ) Done. Returning: OK(0): success
(i2c_fileio_reader             ) Starting. fd=3, fn=/dev/i2c-1, bytect=20, slave_address=0x37, single_byte_reads=false
(i2c_fileio_reader             ) Returning: OK(0): success, readbuf: 6e 88 02 00 30 01 00 01 00 00 84 00 00 00 00 00 00 00 00 00
(get_raw_value_for_feature_metadata) Done.     Returning NULL, *pvalrec ->  
         Single_Vcp_Value at 0x55cf0375e920:
            Opcode:          0x30
            Value type:      DDCA_NON_TABLE_VCP_VALUE (0x01)
            max_val:     1 - 0x0001
            cur_val:     0 - 0x0000
            mh:          0x00
            ml:          0x01
            sh:          0x00
            sl:          0x00
Raw value: opcode=0x30, mh=0x00, ml=0x01, sh=0x00, sl=0x00, max_val=1 (0x0001), cur_val=0 (0x0000)
VCP code 0x30 (Vertical Position (Phase)     ): current value =     0, max value =     1

Here are the outputs of ddcutil getvcp 20 --verbose --trcfunc=get_raw_value_for_feature_metadata --trcfunc=i2c_fileio_reader --trcfunc=i2c_fileio_writer and ddcutil getvcp 20 --verbose --trcfunc=get_raw_value_for_feature_metadata --trcfunc=i2c_fileio_reader --trcfunc=i2c_fileio_writer:

Getting data for non-table VCP code 0x20 - Horizontal Position (Phase):
(get_raw_value_for_feature_metadata) Starting. frec=0x558151a73110, feature_code=0x20
(i2c_fileio_writer             ) Starting. fh=3, filename=/dev/i2c-1, slave_address=0x37, bytect=5, pbytes=0x558151a72a71 -> 51 82 01 20 9c
(i2c_fileio_writer             ) Done. Returning: OK(0): success
(i2c_fileio_reader             ) Starting. fd=3, fn=/dev/i2c-1, bytect=20, slave_address=0x37, single_byte_reads=false
(i2c_fileio_reader             ) Returning: OK(0): success, readbuf: 6e 88 02 00 20 00 ff ff 02 02 94 00 00 00 00 00 00 00 00 00
(get_raw_value_for_feature_metadata) Done.     Returning NULL, *pvalrec -> 
         Single_Vcp_Value at 0x558151a72ae0:
            Opcode:          0x20
            Value type:      DDCA_NON_TABLE_VCP_VALUE (0x01)
            max_val:     65535 - 0xffff
            cur_val:     514 - 0x0202
            mh:          0xff
            ml:          0xff
            sh:          0x02
            sl:          0x02
Raw value: opcode=0x20, mh=0xff, ml=0xff, sh=0x02, sl=0x02, max_val=65535 (0xffff), cur_val=514 (0x0202)
VCP code 0x20 (Horizontal Position (Phase)   ): current value =   514, max value = 65535

Getting data for non-table VCP code 0x30 - Vertical Position (Phase):
(get_raw_value_for_feature_metadata) Starting. frec=0x556b2c0e9110, feature_code=0x30
(i2c_fileio_writer             ) Starting. fh=3, filename=/dev/i2c-1, slave_address=0x37, bytect=5, pbytes=0x556b2c0e8a71 -> 51 82 01 30 8c
(i2c_fileio_writer             ) Done. Returning: OK(0): success
(i2c_fileio_reader             ) Starting. fd=3, fn=/dev/i2c-1, bytect=20, slave_address=0x37, single_byte_reads=false
(i2c_fileio_reader             ) Returning: OK(0): success, readbuf: 6e 88 02 00 30 00 ff ff 02 02 84 00 00 00 00 00 00 00 00 00
(get_raw_value_for_feature_metadata) Done.     Returning NULL, *pvalrec -> 
         Single_Vcp_Value at 0x556b2c0e8ae0:
            Opcode:          0x30
            Value type:      DDCA_NON_TABLE_VCP_VALUE (0x01)
            max_val:     65535 - 0xffff
            cur_val:     514 - 0x0202
            mh:          0xff
            ml:          0xff
            sh:          0x02
            sl:          0x02
Raw value: opcode=0x30, mh=0xff, ml=0xff, sh=0x02, sl=0x02, max_val=65535 (0xffff), cur_val=514 (0x0202)
VCP code 0x30 (Vertical Position (Phase)     ): current value =   514, max value = 65535

@pjaitken
Copy link
Author

pjaitken commented Jan 4, 2021

The earlier read of 0x02 returned 2.
Writing 1 to 0x02 resets 0x02 - but 0x52 continues to report 0x02:

$DDC getvcp -b 1 x02
VCP code 0x02 (New control value             ): One or more new control values have been saved (0x02)

$DDC getvcp -b 1 x52
VCP code 0x52 (Active control                ): Value: 0x02

$DDC setvcp -b 1 x02 1

$DDC getvcp -b 1 x02
VCP code 0x02 (New control value             ): No new control values (0x01)

$DDC getvcp -b 1 x52
VCP code 0x52 (Active control                ): Value: 0x02

@rockowitz
Copy link
Owner

rockowitz commented Feb 25, 2021

Hi Paul,

@pjaitken, If you're still trying to figure out the DDC command sequences and the Phillips control software runs on your Mac, I may have a solution. Recently I came across an inexpensive device called I2CDriver that can sniff I2C traffic. I also got lucky and found a DVI DDC breakout cable online on closeout for $22.50 plus shipping, which saved me from having to make the cable myself. I had to fiddle a bit to get from the connector on the cable, which is the header for a 10 pin ribbon cable, but I fished an old COM port ribbon cable out of the parts bin.

I had to fiddle a bit to get things working - this is a tool for people who can figure things out on their own. I can now capture the I2C traffic, including ACKs and NACKs, in a CSV file. The next step will be to write a Python program that interprets the sequences of "READ, 8, ACK, WRITE 2" etc. as DDC commands.

A couple things are worth pointing out. There are 4 leads from the I2CDriver device: SDA, SCL, GROUND, and 5v VCC. The last is irrelevant for sniffing the line and should be left disconnected. It exists to power a small device being driven from I2CDriver.

Second, I2CDriver has 3 modes: command for controlling the attached device, monitor for watching bits go by on the line, and capture for collecting the traffic and writing it to a file. When in capture mode it doesn't look like anything is happening. Only when capture mode is terminated is output written to the log file.

Regards,
Sanford

@pjaitken
Copy link
Author

pjaitken commented Aug 1, 2021

@bugrasan I found how to set/swap the PBP inputs:

setvcp 0x60 controls the input source:

           0f: DisplayPort-1
           10: DisplayPort-2
           11: HDMI-1
           12: HDMI-2

PBP mode has to be set manually through the menus. However, once in PBP mode, setvcp --noverify 0xF6 1 swaps the 0x60 and PBP displays.

So to show $RIGHT and $LEFT outputs in PBP mode:

    set 0x60 $RIGHT          # appears on the left
    set --noverify 0xF6 1    # swaps left and right
    set 0x60 $LEFT           # appears on the left

Other VCPs I discovered:

E0: R/W Audio source: 1=HDMI-1, 3=DisplayPort-1 Presumably 2=HDMI-2 and 4=Display-2.
E6: Read: 0x00 indicates PBP mode; 0x01 indicates single input mode. Not writeable.
EB: R/W smartresponse: 0=off, 1=fast, 2=faster, 3=fastest.
F0: R/W smartcontrast: 0=off, 1=on.
F6: Write --noverify: 1=swap 0x60 and PBP (no effect in non-PBP mode).

I did not find any VCPs relating to USB settings.

@hadess
Copy link

hadess commented Jan 21, 2023

I'm looking for a way to change the Picture-by-Picture (PBP) input on a Philips 499P9. The PBP mode allows it to display two inputs side-by-side.

I have a Philips 346P1CRH and tested the SmartControl tool that Philips offers (version 6.9.00 after it auto-updated) and PBP wasn't available for selection even though I had a laptop and my desktop machine attached to it.

Capture2

Does the Philips tool work for you to configure PBP? I had the monitor connected through USB as well as HDMI, to no avail. This seems to confirm that the lack of support is a problem with the monitor not offering the functionality through DDC/CI, rather than us not finding out how to enable it. I was personally interested in changing the aspect ratio to 16:9, but that's not available either.

Device and software info screenshot

@pjaitken
Copy link
Author

pjaitken commented Feb 5, 2023

I was able to set PBP like this:

    set 0x60 $RIGHT          # appears on the left
    set --noverify 0xF6 1    # swaps left and right
    set 0x60 $LEFT           # appears on the left

The values for 0x60 are:

setvcp 0x60 controls the input source:

           0f: DisplayPort-1
           10: DisplayPort-2
           11: HDMI-1
           12: HDMI-2

@hadess
Copy link

hadess commented Feb 5, 2023

I was able to set PBP like this:

So, not through the Philips tool, and you still need to enable PBP manually, right?

@pjaitken
Copy link
Author

pjaitken commented Feb 5, 2023

I found that PBP mode had to be set manually through the menus.

I'm not able to test with the Philips tool since I nolonger have the monitor.

Be careful when writing to unknown VCPs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants