Skip to content

Commit

Permalink
Bugfix for checksum calculations.
Browse files Browse the repository at this point in the history
  • Loading branch information
newAM committed Nov 21, 2020
1 parent 4bda72b commit 27235db
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 12 deletions.
30 changes: 18 additions & 12 deletions monitorcontrol/vcp/vcp_linux.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class LinuxVCP(VCP):

# addresses
DDCCI_ADDR = 0x37 # DDC-CI command address on the I2C bus
HOST_ADDRESS = 0x50 # virtual I2C slave address of the host
HOST_ADDRESS = 0x51 # virtual I2C slave address of the host
I2C_SLAVE = 0x0703 # I2C bus slave address

GET_VCP_RESULT_CODES = {
Expand Down Expand Up @@ -108,9 +108,12 @@ def set_vcp_feature(self, code: int, value: int):
# add headers and footers
data.insert(0, (len(data) | self.PROTOCOL_FLAG))
data.insert(0, self.HOST_ADDRESS)
data.append(self.get_checksum(data))
data.append(
self.get_checksum(bytearray([self.DDCCI_ADDR << 1]) + data)
)

# write data
self.logger.debug("data=" + " ".join([f"{x:02X}" for x in data]))
self.write_bytes(data)

# store time of last set VCP
Expand Down Expand Up @@ -139,23 +142,26 @@ def get_vcp_feature(self, code: int) -> Tuple[int, int]:
# add headers and footers
data.insert(0, (len(data) | self.PROTOCOL_FLAG))
data.insert(0, self.HOST_ADDRESS)
data.append(self.get_checksum(data))
data.append(
self.get_checksum(bytearray([self.DDCCI_ADDR << 1]) + data)
)

# write data
self.logger.debug("data=" + " ".join([f"{x:02X}" for x in data]))
self.write_bytes(data)

time.sleep(self.GET_VCP_TIMEOUT)

# read the data
header = self.read_bytes(self.GET_VCP_HEADER_LENGTH)
self.logger.debug(f"header={header}")
source, length = struct.unpack("BB", header)
self.logger.debug("header=" + " ".join([f"{x:02X}" for x in header]))
source, length = struct.unpack("=BB", header)
length &= ~self.PROTOCOL_FLAG # clear protocol flag
payload = self.read_bytes(length + 1)
self.logger.debug(f"payload={payload}")
self.logger.debug("payload=" + " ".join([f"{x:02X}" for x in payload]))

# check checksum
payload, checksum = struct.unpack(f"{length}sB", payload)
payload, checksum = struct.unpack(f"={length}sB", payload)
calculated_checksum = self.get_checksum(header + payload)
checksum_xor = checksum ^ calculated_checksum
if checksum_xor:
Expand Down Expand Up @@ -193,19 +199,19 @@ def get_vcp_feature(self, code: int) -> Tuple[int, int]:

return feature_current, feature_max

def get_checksum(self, data: List, prime: bool = False) -> int:
@staticmethod
def get_checksum(data: bytearray) -> int:
"""
Computes the checksum for a set of data, with the option to
use the virtual host address (per the DDC-CI specification).
Args:
data: data array to transmit
prime: compute checksum using the 0x50 virtual host address
data: Data array to transmit.
Returns:
checksum for the data
Checksum for the data.
"""
checksum = self.HOST_ADDRESS
checksum = 0x00
for data_byte in data:
checksum ^= data_byte
return checksum
Expand Down
20 changes: 20 additions & 0 deletions tests/test_linux_vcp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import pytest
from monitorcontrol.vcp.vcp_linux import LinuxVCP


@pytest.mark.parametrize(
"data, checksum",
[
(bytearray([0x6E, 0x51, 0x82, 0x01, 0x10]), 0xAC),
(bytearray([0xF0, 0xF1, 0x81, 0xB1]), 0x31),
(bytearray([0x6E, 0xF1, 0x81, 0xB1]), 0xAF),
],
)
def test_get_checksum(data: bytearray, checksum: int):
computed = LinuxVCP.get_checksum(data)
xor = checksum ^ computed
assert computed == checksum, (
f"computed=0x{computed:02X} 0b{computed:08b} "
f"checksum=0x{checksum:02X} 0b{checksum:08b} "
f"xor=0x{xor:02X} 0b{xor:08b}"
)

0 comments on commit 27235db

Please sign in to comment.