diff --git a/MonitorControl/Support/IntelDDC.swift b/MonitorControl/Support/IntelDDC.swift index 27e78d5f..9f6013b5 100644 --- a/MonitorControl/Support/IntelDDC.swift +++ b/MonitorControl/Support/IntelDDC.swift @@ -4,7 +4,7 @@ // // Original code: https://github.com/reitermarkus/DDC.swift // Adapted for MonitorControl -// Credits to @reitermarkus +// Credits to @reitermarkus, @waydabber // import Foundation @@ -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 }