Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 68 additions & 61 deletions MonitorControl/Support/IntelDDC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Original code: https://github.com/reitermarkus/DDC.swift
// Adapted for MonitorControl
// Credits to @reitermarkus
// Credits to @reitermarkus, @waydabber
//

import Foundation
Expand Down Expand Up @@ -38,84 +38,91 @@ public class IntelDDC {
}

public func write(command: UInt8, value: UInt16, errorRecoveryWaitTime: UInt32? = nil, writeSleepTime: UInt32 = 10000, numofWriteCycles: UInt8 = 2) -> Bool {
let message: [UInt8] = [0x03, command, UInt8(value >> 8), UInt8(value & 0xFF)]
var replyData: [UInt8] = []
var success: Bool = false
var data: [UInt8] = Array(repeating: 0, count: 7)

data[0] = 0x51
data[1] = 0x84
data[2] = 0x03
data[3] = command
data[4] = UInt8(value >> 8)
data[5] = UInt8(value & 255)
data[6] = 0x6E ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[5]

for _ in 1 ... numofWriteCycles {
usleep(writeSleepTime)
if self.sendMessage(message, replyData: &replyData, errorRecoveryWaitTime: errorRecoveryWaitTime ?? 20000) != nil {
var request = IOI2CRequest()
request.commFlags = 0
request.sendAddress = 0x6E
request.sendTransactionType = IOOptionBits(kIOI2CSimpleTransactionType)
request.sendBuffer = withUnsafePointer(to: &data[0]) { vm_address_t(bitPattern: $0) }
request.sendBytes = UInt32(data.count)
request.replyTransactionType = IOOptionBits(kIOI2CNoTransactionType)
request.replyBytes = 0
if IntelDDC.send(request: &request, to: self.framebuffer, errorRecoveryWaitTime: errorRecoveryWaitTime) {
success = true
}
}
return success
}

public func sendMessage(_ message: [UInt8], replyData: inout [UInt8], minReplyDelay: UInt64? = nil, errorRecoveryWaitTime: UInt32? = nil) -> IOI2CRequest? {
var data: [UInt8] = [UInt8(0x51), UInt8(0x80 + message.count)] + message + [UInt8(0x6E)]
for i in 0 ..< (data.count - 1) {
data[data.count - 1] ^= data[i]
}
var request = IOI2CRequest()
request.commFlags = 0
request.sendAddress = 0x6E
request.sendTransactionType = IOOptionBits(kIOI2CSimpleTransactionType)
request.sendBytes = UInt32(data.count)
request.sendBuffer = withUnsafePointer(to: &data[0]) { vm_address_t(bitPattern: $0) }
if replyData.count == 0 {
request.replyTransactionType = IOOptionBits(kIOI2CNoTransactionType)
request.replyBytes = 0
} else {
public func read(command: UInt8, tries: UInt = 1, replyTransactionType _: IOOptionBits? = nil, minReplyDelay: UInt64? = nil, errorRecoveryWaitTime: UInt32? = nil, writeSleepTime: UInt32 = 10000) -> (UInt16, UInt16)? {
var data: [UInt8] = Array(repeating: 0, count: 5)
var replyData: [UInt8] = Array(repeating: 0, count: 11)

data[0] = 0x51
data[1] = 0x82
data[2] = 0x01
data[3] = command
data[4] = 0x6E ^ data[0] ^ data[1] ^ data[2] ^ data[3]

for i in 1 ... tries {
usleep(writeSleepTime)
usleep(errorRecoveryWaitTime ?? 0)
var request = IOI2CRequest()
request.commFlags = 0
request.sendAddress = 0x6E
request.sendTransactionType = IOOptionBits(kIOI2CSimpleTransactionType)
request.sendBuffer = withUnsafePointer(to: &data[0]) { vm_address_t(bitPattern: $0) }
request.sendBytes = UInt32(data.count)
request.minReplyDelay = minReplyDelay ?? 10
request.replyAddress = 0x6F
request.replySubAddress = 0x51
request.replyTransactionType = self.replyTransactionType
request.replyBytes = UInt32(replyData.count)
request.replyBuffer = withUnsafePointer(to: &replyData[0]) { vm_address_t(bitPattern: $0) }
}
guard IntelDDC.send(request: &request, to: self.framebuffer, errorRecoveryWaitTime: errorRecoveryWaitTime) else {
return nil
}
if replyData.count > 0 {
let checksum = replyData.last!
var calculated = UInt8(0x50)
for i in 0 ..< (replyData.count - 1) {
calculated ^= replyData[i]
}
guard checksum == calculated else {
os_log("Checksum of reply does not match. Expected %u, got %u.", type: .error, checksum, calculated)
os_log("Response was: %{public}@", type: .debug, replyData.map { String(format: "%02X", $0) }.joined(separator: " "))
return nil
}
}
return request
}

public func read(command: UInt8, tries: UInt = 1, replyTransactionType _: IOOptionBits? = nil, minReplyDelay: UInt64? = nil, errorRecoveryWaitTime: UInt32? = nil) -> (UInt16, UInt16)? {
assert(tries > 0)
let message: [UInt8] = [0x01, command]
var replyData: [UInt8] = Array(repeating: 0, count: 11)
for i in 1 ... tries {
guard self.sendMessage(message, replyData: &replyData, minReplyDelay: minReplyDelay, errorRecoveryWaitTime: errorRecoveryWaitTime ?? 40000) != nil else {
continue
}
guard replyData[2] == 0x02 else {
os_log("Got wrong response type for %{public}@. Expected %u, got %u.", type: .debug, String(reflecting: command), 0x02, replyData[2])
os_log("Response was: %{public}@", type: .debug, replyData.map { String(format: "%02X", $0) }.joined(separator: " "))
continue
}
guard replyData[3] == 0x00 else {
os_log("Reading %{public}@ is not supported.", type: .debug, String(reflecting: command))
return nil
}
if i > 1 {
os_log("Reading %{public}@ took %u tries.", type: .debug, String(reflecting: command), i)
if IntelDDC.send(request: &request, to: self.framebuffer, errorRecoveryWaitTime: errorRecoveryWaitTime) {
if replyData.count > 0 {
let checksum = replyData.last!
var calculated = UInt8(0x50)
for i in 0 ..< (replyData.count - 1) {
calculated ^= replyData[i]
}
guard checksum == calculated else {
os_log("Checksum of reply does not match. Expected %u, got %u.", type: .debug, checksum, calculated)
os_log("Response was: %{public}@", type: .debug, replyData.map { String(format: "%02X", $0) }.joined(separator: " "))
continue
}
}
guard replyData[2] == 0x02 else {
os_log("Got wrong response type for %{public}@. Expected %u, got %u.", type: .debug, String(reflecting: command), 0x02, replyData[2])
os_log("Response was: %{public}@", type: .debug, replyData.map { String(format: "%02X", $0) }.joined(separator: " "))
continue
}
guard replyData[3] == 0x00 else {
os_log("Reading %{public}@ is not supported.", type: .debug, String(reflecting: command))
return nil
}
if i > 1 {
os_log("Reading %{public}@ took %u tries.", type: .debug, String(reflecting: command), i)
}
let (mh, ml, sh, sl) = (replyData[6], replyData[7], replyData[8], replyData[9])
let maxValue = UInt16(mh << 8) + UInt16(ml)
let currentValue = UInt16(sh << 8) + UInt16(sl)
return (currentValue, maxValue)
}
let (mh, ml, sh, sl) = (replyData[6], replyData[7], replyData[8], replyData[9])
let maxValue = UInt16(mh << 8) + UInt16(ml)
let currentValue = UInt16(sh << 8) + UInt16(sl)
return (currentValue, maxValue)
}
os_log("Reading %{public}@ failed.", type: .error, String(reflecting: command))
return nil
}

Expand Down